diff --git a/Docs/ChangeLog.txt b/Docs/ChangeLog.txt new file mode 100644 index 0000000..7407814 --- /dev/null +++ b/Docs/ChangeLog.txt @@ -0,0 +1,388 @@ +ChageLog: + v1.5: + * Improved NetPlay code, now the NETopen can return -2 if something + changed in the netInfo, note that first the netInfo is set by + NETsetInfo and then NETopen is called, so if it returns -2 pcsx + will reload the plugins and the memcards, thanks to JNS (linuzappz) + + * Fixed SW Ints over the Recompiler, thanks to Xeven (linuzappz) + + * Small change in CdromCheck, now if CdromLabel[0] == ' ' + the CdromId is copid to CdromLabel (linuzappz) + + * Added Translations support (linuzappz) + + * Fixed a RootCounter bug, single interrupt didn't + interrupted :P, psxCounters.c (linuzappz) + + * Fixed a Flushing problem in PsxDma.c (linuzappz) + + * Fixed a bug within Sio.c, TX_EMPTY flag + was being used incorrectly (linuzappz) + + * Decode_XA.c now uses fixed point, + added NEGCON type to plugins.c/PsxBios.c, + and improved the mingw32 port (yokota) + + * Added MacOSX code (Stefhane Conversy) + + * Fixed bug in CreateMcd (kitaro) + + * Added gettext code for translations (linuzappz) + + * Fixed some pcsx behaviors while opening/closing plugins (linuzappz) + + * Added a 'NO PIC' image (linuzappz) + + * Fixed a buf within the recompiler, it now counts better + the ops by block (linuzappz) + + * Pcsx now compiles without a recompiler ;) (linuzappz) + + * Added code for NULL pointers with PSXM (linuzappz) + + * Fixed intJALR, Rs is loaded before storing Rd (linuzappz) + + * Implemented SWL/SWR in iR3000A.c (linuzappz) + + * Pcsx is now compilable on mingw, thanks to yokota (linuzappz) + + * Fixed small bug on SLTIU, PsxInterpreter.c (linuzappz) + + * Fixed a bug within rcnt exceptions on PsxBios.c (linuzappz) + + * Small speedup over PsxMem.c (linuzappz) + + * Fixed RTPS/RTPT SXYP fifo issue, thanks to Xeven (linuzappz) + + * Improved HLE loading cdrom (for files within dirs), + and added LoadExec/Load syscalls (linuzappz) + + * The HLE bios now support NetPlay (linuzappz) + + * Fixed the seek flag stuff, CdRom.c/h (linuzappz) + + v1.4: + * Added NetPlay support, the api is not the same for cyberpad (linuzappz) + + * Errors on open/close/init are now only for negative values, + plugin.c, plugins.c (linuzappz) + + * Added GPUclearDynarec, for pec, plugins.c/h, plugin.c (linuzappz) + + * Implemented Load Branch Delay stuff :), PsxInterpreter, iR300A.c, + R3000A.h, thanks to Farfetch (linuzappz) + + * Added States Menu WndMain.c, Misc.c/h (linuzappz) + + * Fix on READ_ACK, StatP is ORed with 0x20 after now, CdRom.c (linuzappz) + + * Fixed bug on iBrach for branchs on branch delay slots, iR3000A.c (linuzappz) + + * Fixed Mcd Dialog in Windows, WndMain.c (jang2k) + + * Added workaround in PsxCounters.c for "lost" vsync interrupts (linuzappz) + + * Fixed small bug in PsxBios.c, rootcnt clear must be only when used an event, + also added SaveMcd on FCREAT (linuzappz) + + * Fixes to PsxCounters.c, gives a bit more speed also (linuzappz) + + * Added software interruption over PsxInterpreter.c, untested (linuzappz) + + * Added sTitle in McdBlock Struct, Sio.c/h (linuzappz) + + * Refixed a few lines on Gte.c, and some updates over pcsxdc (Mark Grilenkov) + + * Finished RTPS/RTPT optimization, Gte.c (linuzappz) + + * Added option for Parasite Eve 2, PsxCounters.c, ConfigurePlugins.c, WndMain.c (linuzappz) + + * Removed SPUupdate support since it won't be needed anymore, plugins.c/h, + PsxCounters.c/h (linuzappz) + + * Changed BIAS to 2, and the cdReadTime is now 75 as it should be, PsxCommon.h, + CdRom.c (linuzappz) + + * Several optimizations on iR3000A.c,, ix86.c/h, added iGte.h (linuzappz) + + * Largely optimized Gte.c, also optimized PsxMem.c for direct recClear (linuzappz) + + * Rewritten LWL/LWR/SWL/SWR, PsxInterpreter.c (linuzappz) + + * Added workaround for firstfile, PsxBios.c (linuzappz) + + * Several optimizations over iR3000A.c, ix86.c/h, 10% faster (linuzappz) + + * Removed CdTiming fix since it's not needed anymore, PsxCommon.h, CdRom.c (linuzappz) + + * Fixed bios_write for stdout, PsxBios.c (linuzappz) + + * Added DreamCast port, Dreamcast/sh4 dir, Sio.c, plugins.h, R3000A.c/h, PsxCommon.h, + CdRom.h, Misc.c (Mark Grilenkov) + + * Small speedups over Decode_XA.c (linuzappz) + + * Fixed bug in iR3000A.c, thanks to Mark Grilenkov (linuzappz) + + * Small optimizations to iR3000A.c, ix86.c/h (linuzappz) + + * Fixes for danger girl, legend of mana and tekken2, CdRom.c, and fix + for old pad plugins, ConfigurePlugins.c, thanks to jang2k (linuzappz) + + * Fix for Parasite Eve 2, PsxCounters.c, thanks to psychojak (linuzappz) + + v1.3: + * Fixed icon colors for 15/16bits, thanks to jang2k (linuzappz) + + * Fix silly bug on PsxCounters.c for SPUasync (linuzappz) + + * Refixed the mdecs, more correct. PsxHw.c, Mdec.c, and small fixes on + WndMain.c/Plugin.c, thanks to jang2k (linuzappz) + + * Fix for some mdecs on MdecWrite1, Mdec.c, thanks to psychojak (linuzappz) + + * CVGS Mcds now are detected by file size, also fixes to SaveMcd, + and added support for .gme mcds, Sio.c, thanks to jang2k (linuzappz) + + * Fixed Pcsx title for some win32, small fix in Gte.c, and added + icons for win32 mcd dlg (still unanimated), WndMain.c, + thanks to jang2k (linuzappz) + + * Added rename syscall, PsxBios.c (linuzappz) + + * Fixed bug in MTC2 in linux define, Gte.c (linuzappz) + + * Minor fixes to GtkGui.c (linuzappz) + + * More to PsxBios.c (linuzappz) + + * Fixed bug when S_addr == 0 in Misc.c (linuzappz) + + * Now won't close the plugins if the user press escape more than once, + WinMain.c, plugin.c (linuzappz) + + * Added SPUasync support, thanks to Andy and Iori (linuzappz) + + * Removed the BREAK code, since the bios rom doens't handles it, + thanks to psychojak (linuzappz) + + * Some bugfixes to Gte.c, thanks to jang2k (linuzappz) + + * "hokuto no ken" / "Crash Bandicot 2" ... fix, thanks to Taka (linuzappz) + + * Renamed/rewrote some stuff for pcsx2 compat ;) (linuzappz) + + * Small speedups for Mdec.c (linuzappz) + + * Rewrote DisR3000A.c (linuzappz) + + * Improved and rewrote partially HLE stuff (linuzappz) + + * Rewrote the way we call syscalls (linuzappz) + + * Added in Gte.c SUM_FLAG to opcodes that didn't have it, thanks to Taka (linuzappz) + + * CdlPause Acknowledge irq timing changed to 0x40000, thanks to Taka (linuzappz) + + * Fixed bug in recBLTZAL and recBGEZAL, thanks to Taka (linuzappz) + + * Fixed bug in Sio.c, thanks to gunshinn (linuzappz) + + * Fixed bug in Hw.c, thanks to bilgerat (linuzappz) + + * Fixes to Gte.c, thanks to roor (shadow) + + v1.2: + * Added Reg2 to cdrStruct, for Reg2 == 0x18 (non-interrupted cmds) (linuzappz) + + * Fixed one bug in Counters, count < 0 (linuzappz) + + * Now the cursor will be hidden in Win32 after OpenPlugins. (linuzappz) + + * Refixed Getlocl (linuzappz) + + * Fixed recJALR, 31 for _Rd_ (linuzappz) + + * Fixes to Gte.c (linuzappz) + + * Optimized iR3000A.c for speed (linuzappz) + + * Rewritten branch opcodes on iR3000A.c and removed cache stuff (linuzappz) + + * PRevID changed to 0x2, thanks to shadow (linuzappz) + + * Added PADstartPoll and PADpoll support, thanks to gunshinn (linuzappz) + + * Speed improvements to iR3000A.c (linuzappz) + + * Rewrote the cycles tests stuff, removed the workaround that reseted to 0x80000000 + (linuzappz) + + * CDRgetBufferSub and fixes to CDREAD stuff, CdRom.c, plugins.c/h (linuzappz + + * Correct Mouse, AnalogJoystick and AnalogPad emulation, contributed by + gunshinn (linuzappz) + + * MOVZX and MOVSX to ix86.h and iR3000A.h (linuzappz) + + * Improved Memcard Dialog on Linux (linuzappz) + + * Counters again use BIAS (linuzappz) + + * Autodetect psx type should be fine now, Misc.c (linuzappz) + + * Removed nasm stuff (linuzappz) + + * Fixed VK_F10 in Plugin.c, WndMain.c (linuzappz) + + * LWC2/SWC2 now in Gte.c/h, Interpreter.c, iR3000A.c (linuzappz) + + * Fixed gte_Cxx in MVMVA, Gte.c (linuzappz) + + * Fixed a bug within PIC stuff, Plugin.c (win32 and linux) (linuzappz) + + * Rewrote bios_printf, Bios.c (linuzappz) + + * gtk_widget_hide changed for gtk_widget_destroy, thanks to lu_zero (linuzappz) + + * Fix for cpuIrq.cycle, now it won't freeze when reaching 0xffffffff, since + we now reset when reaches 0x80000000, Counters.c (linuzappz) + + * Counters 1 and 2 (in mode 0x100) should be a little more accurate now (linuzappz) + + * Made workaround for Gran Turismo, WndMain.c, ConfigurePlugins.c, LnxMain.c, + Config.c, GtkGui.c (linuzappz) + + * cp2NCLIP added in iGte.asm (linuzappz) + + * Fixed some bugs on Memory.c (memset to memLUT) and ConfigurePlugins.c + (strlen("HLE") + 1), thanks to Taka (linuzappz) + + * Refixed XA quality, now should be perfect always, Decode_XA.c, and a bug on + the spu dma is now fixed, Dma.c, thanks to Iori for this (linuzappz) + + * Fixed a bug in cp2MTC2 in iGte.asm, movsx now used (linuzappz) + + * cdReadTime is now divided by 75, thanks to calb, and the CDREAD_INT is set + on a irq reset, CdRom.c/h (linuzappz) + + v1.1: + * Fixed a bug in R3000A.c, hwReset() after the cpuIrq reset (linuzappz) + + * Refixed RootCounters, still need to clean, Counters.c (linuzappz) + + * Fixed XA quality, still in some games quality is not perfect (maybe cdrom bug) + Decode_XA.c (linuzappz) + + * Reset var is now unused in CdRom.c, instead cdr.Ctrl is now used (linuzappz) + + * Small speedup for Hw.c, Sio.c/h (linuzappz) + + * Added cdrRead2 handling and fixed cddma, thanks to shunt, CdRom.c (linuzappz) + + * Cleaned a bit Memory.c, R3000A.c and Hw.c (linuzappz) + + * Support for VGS Memory Card Format (*.mem), Sio.c (linuzappz) + + * Rewrote cdirq handling, CdRom.c/h, R3000A.c (linuzappz) + + * Speed up on iR3000A.c code for cop2 (linuzappz) + + * Improved cdrom decoder and cdirq handling, CdRom.c/h (linuzappz) + + * Cleaned error checking on plugins.c/h (linuzappz) + + * Improved SysPrintf as SysMessage, System.h, LnxMain.c, WndMain.c (linuzappz) + + * Added sioInterrupt call, for cleaner code, Sio.c/h, R3000A.c (linuzappz) + + * Cleaned a little initial regs, R3000A.c (linuzappz) + + * Fixes to Dma stuff (HW_DMA_PCR is now used), hwDma3 set now only to + (chcr) 0x11000000 and 0x11400100, Hw.c, CdRom.c (linuzappz) + + * Added status seek flag to SeekL and SeekP, CdRom.c (linuzappz) + + * Icon animated support for McdDlg, GtkGui.c, Sio.c/h (linuzappz) + + * Gettd now returns frame too, CdRom.c (linuzappz) + + * Fixed bug in CdlPlay, CdRom.c (linuzappz) + + * SPUupdate interface support Counters.c/h, plugins.c/h (linuzappz) + + * Added CDRCMD_DEBUG flag in Debug.h, for CdRom.c cmd debug only (linuzappz) + + * AUTOPAUSE stuff improved on Cdrom.c (linuzappz) + + * Icon stuff and more on McdDlg, WndMain.c/GtkGui.c, Sio.c/h (linuzappz) + + * Fixed PsxAuto buf in Misc.c (linuzappz) + + * Memory Card Manager improved to handle blocks, still need + lotta work, WndMain.c/GtkGui.c, Sio.c/h (linuzappz) + + * Fixed in LoadCdrom the System.cnf a bit more (linuzappz) + + * Added Unused data to freeze functions and fixed LoadState to fail only for + STvX (linuzappz) + + * More fixes to Gte.c, added another gte debug in Debug.h/WndMain.c + + * Fixed a bug in RemoveCmdQueue, CdRom.c (linuzappz) + + * Fixed Registry compatibility between versions in Win32, ConfigurePlugins.c + (linuzappz) + + * Gte.c: total rewrite. Rage racer,Ridge racer,Bloady roar,Ridge racer 4 + now WORKS!!! (some small problems still althought ;p) + Bios.c: some more comment opcodes to biosInit.(i think that all exists now) + (shadow) + + * Bios.c: fixed ResetEntryInt & HookEntryInt (hex was opposite) + add some names to BiosInit (commented) + A0:3b, A0:3c, A0:4a, A0:4c, added (shadow) + + * Added LoadCdrom(), for HLE cdrom support, Misc.c, LnxMain.c, GtkGui.c, + WndMain.c (linuzappz) + + * More to Bios.c: longjmp, mem2vram (thought that might fix some demos + but not. Maybe need a recheck..), InitPAD + biosInterrupt (some changes.. + Not seems to work okay.. but dunno..), bios_GPU_dw (probably buggy need a + recheck), bios_atoi, bios_atol, bios_index, bios_rindex, bios_strchr, + bios_strrchr, bios_strpbrk, bios_strspn, bios_strcspn, bios_strtok, + bios_strstr. + And add some names of bios opcodes to the table.(commentted) (shadow) + + * Bios.c, added: SendGPU, StartPAD, GPU_SendPackets, GPU_GetGPUStatus, + toupper, tolower, bcopy, bzero, bcmp (shadow) + + * Now you can change Bios and Plugins Path, in both Win32/Linux, + ConfigurePlugins.c, Config.c, plugins.c, Wnd/LnxMain.c, Memory.c, (linuzappz) + + * StatesC in Linux same as Win32, Plugin.c (linuzappz) + + * Fixed rcntRcount, removed one BIAS, Counters.c (linuzappz) + + * Added CheckCdrom() after you change a cdrom, Cdrom.c (linuzappz) + + * Fixed iMdec.asm, still need to fix colours, they aren't 100% right (linuzappz) + + * F8 now set to make a snapshot (linuzappz) + + * Added bios syscalls names in Bios.c/R3000A.c (linuzappz) + + * GetTD and GetTN cmds are now non-blocking and added error code, + CdRom.c (linuzappz) + + * Simplified queuing code and now reads are done like cmds (instead of + using the synk stuff), CdRom.c/R3000A.c (linuzappz) + + * Made a workaround for iso cdrom plugins, when they changed the dir, + Plugin.c/WndMain.c (linuzappz) + + * Fixed bug in CdRom.c (gcc3 support) (linuzappz) + + v1.0: + * First source code public release. \ No newline at end of file diff --git a/Docs/CodingStyle.txt b/Docs/CodingStyle.txt new file mode 100644 index 0000000..1b62de9 --- /dev/null +++ b/Docs/CodingStyle.txt @@ -0,0 +1,29 @@ +## PCSX CODING STYLE + +typedef struct { // { within struct + int i; +} name; + +void func(int i) { // { within func declaration + if () { // same + switch () { // same + default: + printf(); // 1 tab per level (considering the default and the code in it + // as diferent ones + } + } + + for (;;) { // same for while + } +} + +Also try to align the code: + Something = x; + AnotherThing = x; +but not always: + i = x; + Something = x; + +tab = 4 +indent = 4 + diff --git a/Docs/License.txt b/Docs/License.txt new file mode 100644 index 0000000..1f963da --- /dev/null +++ b/Docs/License.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. + diff --git a/Docs/Readme.txt b/Docs/Readme.txt new file mode 100644 index 0000000..89cf42e --- /dev/null +++ b/Docs/Readme.txt @@ -0,0 +1,196 @@ + Pcsx - Pc Psx Emulator + ---------------------- + +Contents +-------- + +1) General +2) How it works +3) Supported games +4) TroubleShoot +5) Credits + +-------------------------------------------------------------------------------- + +1) General + ------- + +Pcsx is a PSX emulator. What that really means? It means that it emulates the +way that a PSX works and tries to translate PSX machine language to PC language. +That is very hard to be done and we can't speak for 100% success in any time. +The hardware would always be better than the software so if you wanna play games +then better get a real PSX. Pcsx is capable to run most of the games, but a few +others still don't. We are working on it ;). The members of the team are very +advanced coders and they will continue the work on the Pcsx as far as they have +enough time to work on it. Real life comes first and sometimes it is much more +demanding. + + The team of Pcsx + +-------------------------------------------------------------------------------- + +2) How it works + ------------ + +Steps: +------ + 1) Put a bios on bios directory (recommended: scph1001.bin) (optional) + 2) Put plugins in plugin directory + 3) Open the emu + 4) Configure plugins from configuration menu and Memcards from Mcd Manager + 5) Restart + 6) Put a cd in your cdrom drive + 7) Press Run CD and the game might work ;P + +Quick Keys: +---------- + F1: Save State + F2: Increase State Num + F3: Load State + F4: Show State-Pic + F5: Sio Irq Dis/Enable + F6: Black&White Mdecs Dis/Enable + F7: Dis/Enable Xa + F8: Makes a Snapshot + The 2 next keys are only implemented if the cdrom plugin doesn't support + the CDRgetStatus interface. + F9: Press to simulate an open case (to change cdroms in game) + F10: And this to close it + +Cpu Options: +----------- + * Disable Xa Decoding: + Disables xa sound, if you don't want sound this might + speed up a little movies (mostly) and the game itself. + + * Sio Irq Always Enabled: + Enable this only when pads or memcards doesn't works, + but usually brokes compatibility with them. + + * Spu Irq Always Enabled: + May help your game to work, but usually doesn't helps. + + * Black & White Movies: + Speed up for slow machines on movies. + + * Disable CD-DA: + Will disable CD audio. + + * Enable Console Output: + Displays the psx text output. + + * Enable Interpreter Cpu: + Enables interpretive emulation (recomiler by default), + it may be more compatible, but it's slower. + + * Psx System Type: + Autodetect: Try to autodetect the system. + NSTC/PAL: Specify it for yourself. + +Internal HLE Bios: +----------------- + If you select this instead of a regular bios (ie. "scph1001.bin") + Pcsx will emulate the bios (this might not work in all cases but it is + quite advanced), you can try it and see which one works better, notice + that the HLE bios might be faster than a regular one and may make some + games work better. + +NetPlay: +------- + You must select a plugin in the NetPlay Configuration, note that the plugin + must support the v2 of the api. If you don't want to use it simply select + the Disabled one, refer to the plugin's doc for more info. + +-------------------------------------------------------------------------------- + +3) Supported Games + --------------- + +Here is a small list with games that pcsx support. Notice that it might have +some glitches on sound or gfx but it is considered playable. :) + + Crash Bandicoot 1 + Time crisis + Mickey Wild adventure + Coolboarders 3 + Street fighter EX+a + Street fighter EX2 plus + Breath of fire 3 + Breath of fire 4 + Quake II + Alone in the Dark 4 + Tekken 3 + +and probably lots more. +Check www.emufanatics.com or www.ngemu.com for compatibility lists. + +------------------------------------------------------------------------------------------------ + +4) Troubleshoot + ------------ + + -QUE: My favourite game doesn't work + -AN: Wait for the next release, or get another emu ;) + -QUE: Can I have a bios image? + -AN : No + -QUE: CD audio is crappy... + -AN : If it doesn't work then disable it :) + +------------------------------------------------------------------------------------------------ + +5) Credits + ------- + +PCSX is the work of the following people: + +main coder: + Linuzappz , e-mail: linuzappz@pcsx.net +co-coders: + Shadow , e-mail: shadow@pcsx.net +ex-coders: + Pete Bernett, e-mail: psswitch@online.de + NoComp , e-mail: NoComp@mailcity.com + Nik3d , e-mail: +webmaster: + Akumax , e-mail: akumax@pcsx.net + +Team would like to thanks: +-------------------------- +Ancient :Shadow's small bother for beta testing pcsx and bothering me to correct it :P +Roor :for his help on cd-rom decoding routine :) +Duddie, +Tratax, +Kazzuya :for the great work on psemu,and for the XA decoder :) +Calb :for nice chats and coding hits ;) We love you calb ;) +Twin :for the bot to #pcsx on efnet, for coding hints and and :) +Lewpy :Man this plugin is quite fast! +Psychojak :For beta testing Pcsx and donating a great amount of games to Shadow ;) +JNS :For adding PEC support to Pcsx +Antiloop :Great coder :) +Segu :He knows what for :) +Null :He also knows :) +Bobbi +cdburnout :For putting Pcsx news to their site and for hosting.. +D[j] :For hosting us ;) +Now3d :For nice chats,info and blabla :) +Ricardo Diaz:Linux version may never have been released without his help +Nuno felicio:Beta testing, suggestions and a portugues readme +Shunt :Coding hints and nice chats :) +Taka :Many fixes to Pcsx +jang2k :Lots of fixes to Pcsx :) + +and last but not least: +----------------------- +James : for all the friendly support +Dimitris: for being good friend to me.. +Joan: The woman that make me nuts the last couple months... + +------------------------------------------------------------------------------------------------ + +Official website: http:/www.pcsx.net + +If I forgot someone beat me :P +"What you feel is what you are,and what you are is beatiful." +Log off +Shadow/ Linuzappz + diff --git a/Docs/Sources.txt b/Docs/Sources.txt new file mode 100644 index 0000000..035c7aa --- /dev/null +++ b/Docs/Sources.txt @@ -0,0 +1,83 @@ + Pcsx Sources Notes/FAQ + ---- ------- --------- + + +Requeriments +------------ + +* zlib 1.1.3 - www.gzip.org/zlib + + Platform specifycs + ------------------ + + Windows: +* Visual C++ 6.0 + + Linux: +* gtk 1.2.5 - www.gtk.org +* gcc - www.gnu.org/gcc + + DreamCast: + +* gcc - http://www.gnu.org/gcc +* KOS 1.1.8cvs - http://dcdev.allusion.net/ +* GPU plugin - ???? + + Windows-mingw: +* mingw http://mingw.sourceforge.net +* gnu tools http://unxutils.sourceforge.net +* directx 7 (dx70_mgw.zip) http://alleg.sourceforge.net +* Borland C++ Compiler 5.5 (brcc32.exe, rw32core.dll) http://www.borland.com +* mingw/include/afxres.h (2 lines) +#include +#define IDC_STATIC (-1) + +Building +-------- + + Windows: + Open the pcsx.dsw, and use the build command, + also you should set the active configuration to + release. + + Linux: + Open the Linux dir, and type 'make', just that, + but maybe you'll want to edit the Makefile ie. if + you don't have pgcc comment the line CC = pgcc to CC = gcc. + + DreamCast: + Set the correct environment variables according to the KOS documentation. + Change to the Dreamcast directory, and type 'make'. You will get an elf + binary called "pcsx.elf". Convert it to a raw binary format by typing + 'sh-elf-objcopy -O binary pcsx.elf 1st.read'. After scrambling and adding + an IP.BIN, you're ready to burn it on CD. + + Windows-mingw: + Open the Win32 dir, Type as below. +SET PATH=%PATH%;c:\mingw\bin +set INCLUDE=c:\mingw\include +make + +FAQ +--- + +* Q - I think i found a bug in Pcsx, what should i do? + A - Tell me :) (linuzappz@hotmail.com). + +* Q - I would like to port it to some other platform/cpu, where can i start? + A - You should start porting the pcsx itself first (using the interpreter) + and then if needed u will have to code plugins also. + +* Q - I found a problem with some game, how can i debug it? + A - Check Debug.h, enable the logs you think you need and check the output + over emuLog.txt, also you can use the LOG_STDOUT to send the logs over + SysPrintf (to the console). + +* Q - I have problems compiling Pcsx, what's wrong? + A - First check the Building section, if you still have problem you can + contact me (linuzappz@hotmail.com) and i'll try to help you. + +* Q - The code is all unaligned in my editor, why? + A - Set in the editor the tab/indent size to 4. + + diff --git a/Docs/ToDo.txt b/Docs/ToDo.txt new file mode 100644 index 0000000..6e0133e --- /dev/null +++ b/Docs/ToDo.txt @@ -0,0 +1,7 @@ +To do for Pcsx: + * Add reg caching code for the recompiler. + * Continue Bios emulation. (linuzappz) + * Fix CdRom code. (linuzappz) + * Fix Gte and speed it up, convert it to fixed point. + * Check Sio in games that don't work. + * Port to other platforms and CPUs. diff --git a/Docs/Translating.txt b/Docs/Translating.txt new file mode 100644 index 0000000..7ad3bf8 --- /dev/null +++ b/Docs/Translating.txt @@ -0,0 +1,30 @@ + Translating PCSX + ---------------- + +Just some small notes for translators. + +PCSX translations are based on the gettext library: +http://www.gnu.org/software/gettext. + +The main file to translate is pcsx.po located at the +'Intl' dir, note that you must place the translated +strings over the msgstr and leave untouched the msgid. + +To test the translation use the 'msgfmt' utility to +convert the translated pcsx.po file to a pcsx.mo file +(ie. 'msgfmt pcsx.po -o pcsx.mo'), after translating +the file please send it to us and please ask before +translating it, maybe someone has already started it +for your language. + +Note that the subdir over the 'Langs' should be two +letters from the languages codes (see the gettext lib +documentation), ie: Italian: 'it', Spanish: 'es', and +so on. + + +If you have any problems contact us and we'll try to +help you. + + linuzappz + diff --git a/Gamecube/DEBUG.c b/Gamecube/DEBUG.c new file mode 100644 index 0000000..f932ed4 --- /dev/null +++ b/Gamecube/DEBUG.c @@ -0,0 +1,141 @@ +/* DEBUG.c - DEBUG interface + by Mike Slegeir for Mupen64-GC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "DEBUG.h" +#include "TEXT.h" +//#include "usb.h" + +char text[DEBUG_TEXT_HEIGHT][DEBUG_TEXT_WIDTH]; +char printToSD = 1; +extern u32 dyna_used; +extern u32 dyna_total; + +#ifdef SHOW_DEBUG +char txtbuffer[1024]; +long long texttimes[DEBUG_TEXT_HEIGHT]; +extern long long gettime(); +extern unsigned int diff_sec(long long start,long long end); +static void check_heap_space(void){ + sprintf(txtbuffer,"%dKB MEM1 available", SYS_GetArena1Size()/1024); + DEBUG_print(txtbuffer,DBG_MEMFREEINFO); + + sprintf(txtbuffer,"Dynarec (KB) %04d/%04d",dyna_used,dyna_total/1024); + DEBUG_print(txtbuffer,DBG_CORE1); + + sprintf(txtbuffer,"DSP is at %f%%",AESND_GetDSPProcessUsage()); + DEBUG_print(txtbuffer,DBG_CORE2); +} +#endif + +void DEBUG_update() { + #ifdef SHOW_DEBUG + int i; + long long nowTick = gettime(); + for(i=0; i=DEBUG_STRING_LIFE) + { + memset(text[i],0,DEBUG_TEXT_WIDTH); + } + } + check_heap_space(); + #endif +} + +int flushed = 0; +int writtenbefore = 0; +int amountwritten = 0; +//char *dump_filename = "dev0:\\PSXISOS\\debug.txt"; +char *dump_filename = "/PSXISOS/debug.txt"; +FILE* fdebug = NULL; +void DEBUG_print(char* string,int pos){ + + #ifdef SHOW_DEBUG + if(pos == DBG_USBGECKO) { + #ifdef PRINTGECKO + if(!flushed){ + usb_flush(1); + flushed = 1; + } + int size = strlen(string); + usb_sendbuffer_safe(1, &size,4); + usb_sendbuffer_safe(1, string,size); + #endif + } + else if(pos == DBG_SDGECKOOPEN) { +#ifdef SDPRINT + if(!f && printToSD) + fdebug = fopen( dump_filename, "wb" ); +#endif + } + else if(pos == DBG_SDGECKOAPPEND) { +#ifdef SDPRINT + if(!fdebug && printToSD) + fdebug = fopen( dump_filename, "ab" ); +#endif + } + else if(pos == DBG_SDGECKOCLOSE) { +#ifdef SDPRINT + if(fdebug) + { + fclose(fdebug); + fdebug = NULL; + } +#endif + } + else if(pos == DBG_SDGECKOPRINT) { +#ifdef SDPRINT + if(!f || (printToSD == 0)) + return; + fwrite(string, 1, strlen(string), f); +#endif + } + else { + memset(text[pos],0,DEBUG_TEXT_WIDTH); + strncpy(text[pos], string, DEBUG_TEXT_WIDTH); + memset(text[DEBUG_TEXT_WIDTH-1],0,1); + texttimes[pos] = gettime(); + } + #endif + +} + + +#define MAX_STATS 20 +unsigned int stats_buffer[MAX_STATS]; +unsigned int avge_counter[MAX_STATS]; +void DEBUG_stats(int stats_id, char *info, unsigned int stats_type, unsigned int adjustment_value) +{ + #ifdef SHOW_DEBUG + switch(stats_type) + { + case STAT_TYPE_ACCUM: //accumulate + stats_buffer[stats_id] += adjustment_value; + break; + case STAT_TYPE_AVGE: //average + avge_counter[stats_id] += 1; + stats_buffer[stats_id] += adjustment_value; + break; + case STAT_TYPE_CLEAR: + if(stats_type & STAT_TYPE_AVGE) + avge_counter[stats_id] = 0; + stats_buffer[stats_id] = 0; + break; + + } + unsigned int value = stats_buffer[stats_id]; + if(stats_type == STAT_TYPE_AVGE) value /= avge_counter[stats_id]; + + sprintf(txtbuffer,"%s [ %u ]", info, value); + DEBUG_print(txtbuffer,DBG_STATSBASE+stats_id); + #endif +} + diff --git a/Gamecube/DEBUG.h b/Gamecube/DEBUG.h new file mode 100644 index 0000000..b7cb04e --- /dev/null +++ b/Gamecube/DEBUG.h @@ -0,0 +1,104 @@ +/* DEBUG.h - DEBUG interface + by Mike Slegeir for Mupen64-GC + */ + +#ifndef DEBUG_H +#define DEBUG_H + +//#define SDPRINT +//#define PEOPS_SDLOG + +#define DBG_MEMFREEINFO 0 +#define DBG_CORE1 1 +#define DBG_CORE2 2 +#define DBG_CORE3 3 +#define DBG_GPU1 4 +#define DBG_GPU2 5 +#define DBG_GPU3 6 +#define DBG_SPU1 7 +#define DBG_SPU2 8 +#define DBG_SPU3 9 +#define DBG_CDR1 10 +#define DBG_CDR2 11 +#define DBG_CDR3 12 +#define DBG_CDR4 13 +#define DBG_PROFILE_IDLE 14 +#define DBG_PROFILE_GFX 15 +#define DBG_PROFILE_AUDIO 16 +#define DBG_PROFILE_TLB 17 +#define DBG_PROFILE_FP 18 +#define DBG_PROFILE_COMP 19 +#define DBG_PROFILE_INTERP 20 +#define DBG_PROFILE_TRAMP 21 +#define DBG_STATSBASE 12 // ALL stats print from this line onwards +#define DBG_SDGECKOAPPEND 0xFB +#define DBG_SDGECKOOPEN 0xFC +#define DBG_SDGECKOCLOSE 0xFD +#define DBG_SDGECKOPRINT 0xFE +#define DBG_USBGECKO 0xFF + +// profiling + +#define GFX_SECTION 1 +#define AUDIO_SECTION 2 +#define COMPILER_SECTION 3 +#define IDLE_SECTION 4 +#define TLB_SECTION 5 +#define FP_SECTION 6 +#define INTERP_SECTION 7 +#define TRAMP_SECTION 8 +#define FUNCS_SECTION 9 +#define NUM_SECTIONS 9 + +#ifdef PROFILE + +void start_section(int section_type); +void end_section(int section_type); +void refresh_stat(); + +#else + +#define start_section(a) +#define end_section(a) +#define refresh_stat() + +#endif + +//DEBUG_stats defines +#define STAT_TYPE_ACCUM 0 +#define STAT_TYPE_AVGE 1 +#define STAT_TYPE_CLEAR 2 + +#define STATS_RECOMPCACHE 0 +#define STATS_CACHEMISSES 1 +#define STATS_FCOUNTER 2 //FRAME counter +#define STATS_THREE 3 + +extern char txtbuffer[1024]; +// Amount of time each string will be held onto +#define DEBUG_STRING_LIFE 5 +// Dimensions of array returned by get_text +#define DEBUG_TEXT_WIDTH 100 +#define DEBUG_TEXT_HEIGHT 40 + +#ifdef __cplusplus +extern "C" { +#endif + +// Pre-formatted string (use sprintf before sending to print) +void DEBUG_print(char* string,int pos); +void DEBUG_stats(int stats_id, char *info, unsigned int stats_type, unsigned int adjustment_value); + +// Should be called before get_text. Ages the strings, and remove old ones +void DEBUG_update(void); + +// Returns pointer to an array of char* +char** DEBUG_get_text(void); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/Gamecube/GamecubeMain.cpp b/Gamecube/GamecubeMain.cpp new file mode 100644 index 0000000..866a479 --- /dev/null +++ b/Gamecube/GamecubeMain.cpp @@ -0,0 +1,745 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * Copyright (C) 2009-2010 WiiSX Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef DEBUGON +# include +#endif + +#include "../psxcommon.h" +#include "wiiSXconfig.h" +#include "menu/MenuContext.h" + +extern u32 __di_check_ahbprot(void); + +extern "C" { +#include "DEBUG.h" +#include "fileBrowser/fileBrowser.h" +#include "fileBrowser/fileBrowser-libfat.h" +#include "fileBrowser/fileBrowser-DVD.h" +#include "fileBrowser/fileBrowser-CARD.h" +#include "fileBrowser/fileBrowser-SMB.h" +#include "gc_input/controller.h" +} + + +#ifdef WII +unsigned int MALLOC_MEM2 = 0; +extern "C" { +#include +} +#endif //WII + +/* function prototypes */ +extern "C" { +int SysInit(); +void SysReset(); +void SysClose(); +void SysPrintf(const char *fmt, ...); +void *SysLoadLibrary(char *lib); +void *SysLoadSym(void *lib, char *sym); +char *SysLibError(); +void SysCloseLibrary(void *lib); +void SysUpdate(); +void SysRunGui(); +void SysMessage(char *fmt, ...); +} + +u32* xfb[2] = { NULL, NULL }; /*** Framebuffers ***/ +int whichfb = 0; /*** Frame buffer toggle ***/ +GXRModeObj *vmode; /*** Graphics Mode Object ***/ +#define DEFAULT_FIFO_SIZE ( 256 * 1024 ) +BOOL hasLoadedISO = FALSE; +fileBrowser_file isoFile; //the ISO file +fileBrowser_file cddaFile; //the CDDA file +fileBrowser_file subFile; //the SUB file +fileBrowser_file *biosFile = NULL; //BIOS file + +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) +FILE *emuLog; +#endif + +PcsxConfig Config; +char dynacore; +char biosDevice; +char LoadCdBios=0; +char frameLimit; +char frameSkip; +extern char audioEnabled; +char volume; +char showFPSonScreen; +char printToScreen; +char menuActive; +char saveEnabled; +char creditsScrolling; +char padNeedScan=1; +char wpadNeedScan=1; +char shutdown = 0; +char nativeSaveDevice; +char saveStateDevice; +char autoSave; +signed char autoSaveLoaded = 0; +char screenMode = 0; +char videoMode = 0; +char fileSortMode = 1; +char padAutoAssign; +char padType[2]; +char padAssign[2]; +char rumbleEnabled; +char loadButtonSlot; +char controllerType; +char numMultitaps; + +#define CONFIG_STRING_TYPE 0 +#define CONFIG_STRING_SIZE 256 +char smbUserName[CONFIG_STRING_SIZE]; +char smbPassWord[CONFIG_STRING_SIZE]; +char smbShareName[CONFIG_STRING_SIZE]; +char smbIpAddr[CONFIG_STRING_SIZE]; + +int stop = 0; + +static struct { + const char* key; + // For integral options this is a pointer to a char + // for string values, this is a pointer to a 256-byte string + // thus, assigning a string value to an integral type will cause overflow + char* value; + char min, max; +} OPTIONS[] = +{ { "Audio", &audioEnabled, AUDIO_DISABLE, AUDIO_ENABLE }, + { "Volume", &volume, VOLUME_LOUDEST, VOLUME_LOW }, + { "FPS", &showFPSonScreen, FPS_HIDE, FPS_SHOW }, +// { "Debug", &printToScreen, DEBUG_HIDE, DEBUG_SHOW }, + { "ScreenMode", &screenMode, SCREENMODE_4x3, SCREENMODE_16x9_PILLARBOX }, + { "VideoMode", &videoMode, VIDEOMODE_AUTO, VIDEOMODE_PROGRESSIVE }, + { "FileSortMode", &fileSortMode, FILESORT_DIRS_MIXED, FILESORT_DIRS_FIRST }, + { "Core", &dynacore, DYNACORE_DYNAREC, DYNACORE_INTERPRETER }, + { "NativeDevice", &nativeSaveDevice, NATIVESAVEDEVICE_SD, NATIVESAVEDEVICE_CARDB }, + { "StatesDevice", &saveStateDevice, SAVESTATEDEVICE_SD, SAVESTATEDEVICE_USB }, + { "AutoSave", &autoSave, AUTOSAVE_DISABLE, AUTOSAVE_ENABLE }, + { "BiosDevice", &biosDevice, BIOSDEVICE_HLE, BIOSDEVICE_USB }, + { "BootThruBios", &LoadCdBios, BOOTTHRUBIOS_NO, BOOTTHRUBIOS_YES }, + { "LimitFrames", &frameLimit, FRAMELIMIT_NONE, FRAMELIMIT_AUTO }, + { "SkipFrames", &frameSkip, FRAMESKIP_DISABLE, FRAMESKIP_ENABLE }, + { "PadAutoAssign", &padAutoAssign, PADAUTOASSIGN_MANUAL, PADAUTOASSIGN_AUTOMATIC }, + { "PadType1", &padType[0], PADTYPE_NONE, PADTYPE_WII }, + { "PadType2", &padType[1], PADTYPE_NONE, PADTYPE_WII }, + { "PadAssign1", &padAssign[0], PADASSIGN_INPUT0, PADASSIGN_INPUT3 }, + { "PadAssign2", &padAssign[1], PADASSIGN_INPUT0, PADASSIGN_INPUT3 }, + { "RumbleEnabled", &rumbleEnabled, RUMBLE_DISABLE, RUMBLE_ENABLE }, + { "LoadButtonSlot", &loadButtonSlot, LOADBUTTON_SLOT0, LOADBUTTON_DEFAULT }, + { "ControllerType", &controllerType, CONTROLLERTYPE_STANDARD, CONTROLLERTYPE_ANALOG }, +// { "NumberMultitaps", &numMultitaps, MULTITAPS_NONE, MULTITAPS_TWO }, + { "smbusername", smbUserName, CONFIG_STRING_TYPE, CONFIG_STRING_TYPE }, + { "smbpassword", smbPassWord, CONFIG_STRING_TYPE, CONFIG_STRING_TYPE }, + { "smbsharename", smbShareName, CONFIG_STRING_TYPE, CONFIG_STRING_TYPE }, + { "smbipaddr", smbIpAddr, CONFIG_STRING_TYPE, CONFIG_STRING_TYPE } +}; +void handleConfigPair(char* kv); +void readConfig(FILE* f); +void writeConfig(FILE* f); +int checkBiosExists(int testDevice); + +void loadSettings(int argc, char *argv[]) +{ + // Default Settings + audioEnabled = 1; // Audio + volume = VOLUME_MEDIUM; +#ifdef RELEASE + showFPSonScreen = 0; // Don't show FPS on Screen +#else + showFPSonScreen = 1; // Show FPS on Screen +#endif + printToScreen = 1; // Show DEBUG text on screen + printToSD = 0; // Disable SD logging + frameLimit = 1; // Auto limit FPS + frameSkip = 0; // Disable frame skipping + iUseDither = 1; // Default dithering + saveEnabled = 0; // Don't save game + nativeSaveDevice = 0; // SD + saveStateDevice = 0; // SD + autoSave = 1; // Auto Save Game + creditsScrolling = 0; // Normal menu for now + dynacore = 0; // Dynarec + screenMode = 0; // Stretch FB horizontally + videoMode = VIDEOMODE_AUTO; + fileSortMode = FILESORT_DIRS_FIRST; + padAutoAssign = PADAUTOASSIGN_AUTOMATIC; + padType[0] = PADTYPE_NONE; + padType[1] = PADTYPE_NONE; + padAssign[0] = PADASSIGN_INPUT0; + padAssign[1] = PADASSIGN_INPUT1; + rumbleEnabled = RUMBLE_ENABLE; + loadButtonSlot = LOADBUTTON_DEFAULT; + controllerType = CONTROLLERTYPE_STANDARD; + numMultitaps = MULTITAPS_NONE; + menuActive = 1; + + //PCSX-specific defaults + memset(&Config, 0, sizeof(PcsxConfig)); + Config.Cpu=dynacore; //Dynarec core + strcpy(Config.Net,"Disabled"); + Config.PsxOut = 1; + Config.HLE = 1; + Config.Xa = 0; //XA enabled + Config.Cdda = 1; //CDDA disabled + iVolume = volume; //Volume="medium" in PEOPSspu + Config.PsxAuto = 1; //Autodetect + LoadCdBios = BOOTTHRUBIOS_NO; + + //config stuff + int (*configFile_init)(fileBrowser_file*) = fileBrowser_libfat_init; +#ifdef HW_RVL + if(argv[0][0] == 'u') { //assume USB + fileBrowser_file* configFile_file = &saveDir_libfat_USB; + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "usb:/wiisxrx/settings.cfg", "r" ); //attempt to open file + if(f) { //open ok, read it + readConfig(f); + fclose(f); + } + f = fopen( "usb:/wiisxrx/controlG.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_GC); //read in GC controller mappings + fclose(f); + } +#ifdef HW_RVL + f = fopen( "usb:/wiisxrx/controlC.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_Classic); //read in Classic controller mappings + fclose(f); + } + f = fopen( "usb:/wiisxrx/controlN.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_WiimoteNunchuk); //read in WM+NC controller mappings + fclose(f); + } + f = fopen( "usb:/wiisxrx/controlW.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_Wiimote); //read in Wiimote controller mappings + fclose(f); + } + f = fopen("usb:/wiisxrx/controlP.cfg", "r"); //attempt to open file + if (f) { + load_configurations(f, &controller_WiiUPro); //read in Wii U Pro controller mappings + fclose(f); + } +#endif //HW_RVL + } + } + else /*if((argv[0][0]=='s') || (argv[0][0]=='/'))*/ +#endif //HW_RVL + { //assume SD + fileBrowser_file* configFile_file = &saveDir_libfat_Default; + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "sd:/wiisxrx/settings.cfg", "r" ); //attempt to open file + if(f) { //open ok, read it + readConfig(f); + fclose(f); + } + f = fopen( "sd:/wiisxrx/controlG.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_GC); //read in GC controller mappings + fclose(f); + } +#ifdef HW_RVL + f = fopen( "sd:/wiisxrx/controlC.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_Classic); //read in Classic controller mappings + fclose(f); + } + f = fopen( "sd:/wiisxrx/controlN.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_WiimoteNunchuk); //read in WM+NC controller mappings + fclose(f); + } + f = fopen( "sd:/wiisxrx/controlW.cfg", "r" ); //attempt to open file + if(f) { + load_configurations(f, &controller_Wiimote); //read in Wiimote controller mappings + fclose(f); + } + f = fopen("sd:/wiisxrx/controlP.cfg", "r"); //attempt to open file + if (f) { + load_configurations(f, &controller_WiiUPro); //read in Wii U Pro controller mappings + fclose(f); + } +#endif //HW_RVL + } + } +#ifdef HW_RVL + // Handle options passed in through arguments + int i; + for(i=1; i>16)) + stop = 1; +} + +#ifdef HW_RVL +void ShutdownWii() +{ + shutdown = 1; + stop = 1; +} +#endif + +void video_mode_init(GXRModeObj *videomode,unsigned int *fb1, unsigned int *fb2) +{ + vmode = videomode; + xfb[0] = fb1; + xfb[1] = fb2; +} + +// Plugin structure +extern "C" { +#include "GamecubePlugins.h" +PluginTable plugins[] = + { PLUGIN_SLOT_0, + PLUGIN_SLOT_1, + PLUGIN_SLOT_2, + PLUGIN_SLOT_3, + PLUGIN_SLOT_4, + PLUGIN_SLOT_5, + PLUGIN_SLOT_6, + PLUGIN_SLOT_7 }; +} + +/**************************************************************************** + * IOS Check + ***************************************************************************/ +#ifdef HW_RVL +bool SupportedIOS(u32 ios) +{ + if(ios == 58 || ios == 61) + return true; + + return false; +} + +bool SaneIOS(u32 ios) +{ + bool res = false; + u32 num_titles=0; + u32 tmd_size; + + if(ios > 200) + return false; + + if (ES_GetNumTitles(&num_titles) < 0) + return false; + + if(num_titles < 1) + return false; + + u64 *titles = (u64 *)memalign(32, num_titles * sizeof(u64) + 32); + + if(!titles) + return false; + + if (ES_GetTitles(titles, num_titles) < 0) + { + free(titles); + return false; + } + + u32 *tmdbuffer = (u32 *)memalign(32, MAX_SIGNED_TMD_SIZE); + + if(!tmdbuffer) + { + free(titles); + return false; + } + + for(u32 n=0; n < num_titles; n++) + { + if((titles[n] & 0xFFFFFFFF) != ios) + continue; + + if (ES_GetStoredTMDSize(titles[n], &tmd_size) < 0) + break; + + if (tmd_size > 4096) + break; + + if (ES_GetStoredTMD(titles[n], (signed_blob *)tmdbuffer, tmd_size) < 0) + break; + + if (tmdbuffer[1] || tmdbuffer[2]) + { + res = true; + break; + } + } + free(tmdbuffer); + free(titles); + return res; +} +#endif + + +int main(int argc, char *argv[]) +{ + /* INITIALIZE */ +#ifdef HW_RVL + L2Enhance(); + + u32 ios = IOS_GetVersion(); + + if(!SupportedIOS(ios)) + { + s32 preferred = IOS_GetPreferredVersion(); + + if(SupportedIOS(preferred)) + IOS_ReloadIOS(preferred); + } + + #endif + + loadSettings(argc, argv); + MenuContext *menu = new MenuContext(vmode); + VIDEO_SetPostRetraceCallback (ScanPADSandReset); + +#ifndef WII + DVD_Init(); +#endif + +#ifdef DEBUGON + //DEBUG_Init(GDBSTUB_DEVICE_TCP,GDBSTUB_DEF_TCPPORT); //Default port is 2828 + DEBUG_Init(GDBSTUB_DEVICE_USB, 1); + _break(); +#endif + + control_info_init(); //Perform controller auto assignment at least once at startup. + + // Start up AESND (inited here because its used in SPU and CD) + AESND_Init(); + +#ifdef HW_RVL + // Initialize the network if the user has specified something in their SMB settings + if(strlen(&smbShareName[0]) && strlen(&smbIpAddr[0])) { + init_network_thread(); + } +#endif + + while (menu->isRunning()) {} + + // Shut down AESND + AESND_Reset(); + + delete menu; + + return 0; +} + +// loadISO loads an ISO file as current media to read from. +int loadISOSwap(fileBrowser_file* file) { + + // Refresh file pointers + memset(&isoFile, 0, sizeof(fileBrowser_file)); + memset(&cddaFile, 0, sizeof(fileBrowser_file)); + memset(&subFile, 0, sizeof(fileBrowser_file)); + + memcpy(&isoFile, file, sizeof(fileBrowser_file) ); + + //might need to insert code here to trigger a lid open/close interrupt + if(CDR_open() < 0) + return -1; + CheckCdrom(); + LoadCdrom(); + return 0; +} + + +// loadISO loads an ISO, resets the system and loads the save. +int loadISO(fileBrowser_file* file) +{ + // Refresh file pointers + memset(&isoFile, 0, sizeof(fileBrowser_file)); + memset(&cddaFile, 0, sizeof(fileBrowser_file)); + memset(&subFile, 0, sizeof(fileBrowser_file)); + + memcpy(&isoFile, file, sizeof(fileBrowser_file) ); + + if(hasLoadedISO) { + SysClose(); + hasLoadedISO = FALSE; + } + if(SysInit() < 0) + return -1; + hasLoadedISO = TRUE; + SysReset(); + + char *tempStr = &file->name[0]; + if((strstr(tempStr,".EXE")!=NULL) || (strstr(tempStr,".exe")!=NULL)) { + Load(file); + } + else { + CheckCdrom(); + LoadCdrom(); + } + + if(autoSave==AUTOSAVE_ENABLE) { + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + case NATIVESAVEDEVICE_USB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_SD) ? &saveDir_libfat_Default:&saveDir_libfat_USB; + saveFile_readFile = fileBrowser_libfat_readFile; + saveFile_writeFile = fileBrowser_libfat_writeFile; + saveFile_init = fileBrowser_libfat_init; + saveFile_deinit = fileBrowser_libfat_deinit; + break; + case NATIVESAVEDEVICE_CARDA: + case NATIVESAVEDEVICE_CARDB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_CARDA) ? &saveDir_CARD_SlotA:&saveDir_CARD_SlotB; + saveFile_readFile = fileBrowser_CARD_readFile; + saveFile_writeFile = fileBrowser_CARD_writeFile; + saveFile_init = fileBrowser_CARD_init; + saveFile_deinit = fileBrowser_CARD_deinit; + break; + } + // Try loading everything + int result = 0; + saveFile_init(saveFile_dir); + result += LoadMcd(1,saveFile_dir); + result += LoadMcd(2,saveFile_dir); + saveFile_deinit(saveFile_dir); + + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + if (result) autoSaveLoaded = NATIVESAVEDEVICE_SD; + break; + case NATIVESAVEDEVICE_USB: + if (result) autoSaveLoaded = NATIVESAVEDEVICE_USB; + break; + case NATIVESAVEDEVICE_CARDA: + if (result) autoSaveLoaded = NATIVESAVEDEVICE_CARDA; + break; + case NATIVESAVEDEVICE_CARDB: + if (result) autoSaveLoaded = NATIVESAVEDEVICE_CARDB; + break; + } + } + + return 0; +} + +void setOption(char* key, char* valuePointer){ + bool isString = valuePointer[0] == '"'; + char value = 0; + + if(isString) { + char* p = valuePointer++; + while(*++p != '"'); + *p = 0; + } else + value = atoi(valuePointer); + + for(unsigned int i=0; i= OPTIONS[i].min && value <= OPTIONS[i].max) + *OPTIONS[i].value = value; + break; + } + } +} + +void handleConfigPair(char* kv){ + char* vs = kv; + while(*vs != ' ' && *vs != '\t' && *vs != ':' && *vs != '=') + ++vs; + *(vs++) = 0; + while(*vs == ' ' || *vs == '\t' || *vs == ':' || *vs == '=') + ++vs; + + setOption(kv, vs); +} + +void readConfig(FILE* f){ + char line[256]; + while(fgets(line, 256, f)){ + if(line[0] == '#') continue; + handleConfigPair(line); + } +} + +void writeConfig(FILE* f){ + for(unsigned int i=0; iExecute(); +} + +int SysInit() { +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) + emuLog = fopen("/PSXISOS/emu.log", "w"); +#endif + Config.Cpu = dynacore; //cpu may have changed + psxInit(); + LoadPlugins(); + if(OpenPlugins() < 0) + return -1; + + //Init biosFile pointers and stuff + if(biosDevice != BIOSDEVICE_HLE) { + biosFile_dir = (biosDevice == BIOSDEVICE_SD) ? &biosDir_libfat_Default : &biosDir_libfat_USB; + biosFile_readFile = fileBrowser_libfat_readFile; + biosFile_open = fileBrowser_libfat_open; + biosFile_init = fileBrowser_libfat_init; + biosFile_deinit = fileBrowser_libfat_deinit; + if(biosFile) { + free(biosFile); + } + biosFile = (fileBrowser_file*)memalign(32,sizeof(fileBrowser_file)); + memcpy(biosFile,biosFile_dir,sizeof(fileBrowser_file)); + strcat(biosFile->name, "/SCPH1001.BIN"); + biosFile_init(biosFile); //initialize the bios device (it might not be the same as ISO device) + Config.HLE = BIOS_USER_DEFINED; + } else { + Config.HLE = BIOS_HLE; + } + + return 0; +} + +void SysReset() { + psxReset(); +} + +void SysStartCPU() { + Config.PsxOut = 0; + stop = 0; + psxCpu->Execute(); +} + +void SysClose() +{ + psxShutdown(); + ClosePlugins(); + ReleasePlugins(); +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) + if (emuLog != NULL) fclose(emuLog); +#endif +} + +void SysPrintf(const char *fmt, ...) +{ +#ifdef PRINTGECKO + va_list list; + char msg[512]; + + va_start(list, fmt); + vsprintf(msg, fmt, list); + va_end(list); + + //if (Config.PsxOut) printf ("%s", msg); + DEBUG_print(msg, DBG_USBGECKO); +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) + fprintf(emuLog, "%s", msg); +#endif +#endif +} + +void *SysLoadLibrary(char *lib) +{ + int i; + for(i=0; inumSyms; i++) + if(plugin->syms[i].sym && !strcmp(sym, plugin->syms[i].sym)) + return plugin->syms[i].pntr; + return NULL; +} + +int framesdone = 0; +void SysUpdate() +{ + framesdone++; +#ifdef PROFILE + refresh_stat(); +#endif +} + +void SysRunGui() {} +void SysMessage(char *fmt, ...) {} +void SysCloseLibrary(void *lib) {} +char *SysLibError() { return NULL; } + +} //extern "C" diff --git a/Gamecube/GamecubePlugins.h b/Gamecube/GamecubePlugins.h new file mode 100644 index 0000000..57c177b --- /dev/null +++ b/Gamecube/GamecubePlugins.h @@ -0,0 +1,530 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GAMECUBE_PLUGINS_H +#define GAMECUBE_PLUGINS_H + +#ifndef NULL +#define NULL ((void*)0) +#endif +#include "../decode_xa.h" +#include "../psemu_plugin_defs.h" +#include "../plugins.h" + +#define SYMS_PER_LIB 32 +typedef struct { + const char* lib; + int numSyms; + struct { + const char* sym; + void* pntr; + } syms[SYMS_PER_LIB]; +} PluginTable; +#define NUM_PLUGINS 8 + +/* SPU NULL */ +//typedef long (* SPUopen)(void); +void NULL_SPUwriteRegister(unsigned long reg, unsigned short val); +unsigned short NULL_SPUreadRegister(unsigned long reg); +unsigned short NULL_SPUreadDMA(void); +void NULL_SPUwriteDMA(unsigned short val); +void NULL_SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize); +void NULL_SPUreadDMAMem(unsigned short * pusPSXMem,int iSize); +void NULL_SPUplayADPCMchannel(xa_decode_t *xap); +long NULL_SPUinit(void); +long NULL_SPUopen(void); +void NULL_SPUsetConfigFile(char * pCfg); +long NULL_SPUclose(void); +long NULL_SPUshutdown(void); +long NULL_SPUtest(void); +void NULL_SPUregisterCallback(void (*callback)(void)); +void NULL_SPUregisterCDDAVolume(void (*CDDAVcallback)(unsigned short,unsigned short)); +char * NULL_SPUgetLibInfos(void); +void NULL_SPUabout(void); +long NULL_SPUfreeze(unsigned long ulFreezeMode,SPUFreeze_t *); + +/* SPU PEOPS 1.9 */ +//dma.c +unsigned short CALLBACK PEOPS_SPUreadDMA(void); +void CALLBACK PEOPS_SPUreadDMAMem(unsigned short * pusPSXMem,int iSize); +void CALLBACK PEOPS_SPUwriteDMA(unsigned short val); +void CALLBACK PEOPS_SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize); +//PEOPSspu.c +void CALLBACK PEOPS_SPUasync(unsigned long cycle); +void CALLBACK PEOPS_SPUupdate(void); +void CALLBACK PEOPS_SPUplayADPCMchannel(xa_decode_t *xap); +long CALLBACK PEOPS_SPUinit(void); +long PEOPS_SPUopen(void); +void PEOPS_SPUsetConfigFile(char * pCfg); +long CALLBACK PEOPS_SPUclose(void); +long CALLBACK PEOPS_SPUshutdown(void); +long CALLBACK PEOPS_SPUtest(void); +long CALLBACK PEOPS_SPUconfigure(void); +void CALLBACK PEOPS_SPUabout(void); +void CALLBACK PEOPS_SPUregisterCallback(void (CALLBACK *callback)(void)); +void CALLBACK PEOPS_SPUregisterCDDAVolume(void (CALLBACK *CDDAVcallback)(unsigned short,unsigned short)); +//registers.c +void CALLBACK PEOPS_SPUwriteRegister(unsigned long reg, unsigned short val); +unsigned short CALLBACK PEOPS_SPUreadRegister(unsigned long reg); +//freeze.c +long CALLBACK PEOPS_SPUfreeze(unsigned long ulFreezeMode,SPUFreeze_t * pF); + +/* franspu */ +//spu_registers.cpp +void FRAN_SPU_writeRegister(unsigned long reg, unsigned short val); +unsigned short FRAN_SPU_readRegister(unsigned long reg); +//spu_dma.cpp +unsigned short FRAN_SPU_readDMA(void); +void FRAN_SPU_readDMAMem(unsigned short * pusPSXMem,int iSize); +void FRAN_SPU_writeDMA(unsigned short val); +void FRAN_SPU_writeDMAMem(unsigned short * pusPSXMem,int iSize); +//spu.cpp +void FRAN_SPU_async(unsigned long cycle); +void FRAN_SPU_playADPCMchannel(xa_decode_t *xap); +long FRAN_SPU_init(void); +s32 FRAN_SPU_open(void); +long FRAN_SPU_close(void); +long FRAN_SPU_shutdown(void); +long FRAN_SPU_freeze(unsigned long ulFreezeMode,SPUFreeze_t * pF); +void FRAN_SPU_setConfigFile(char *cfgfile); +void FRAN_SPU_About(); +void FRAN_SPU_test(); +void FRAN_SPU_registerCallback(void (*callback)(void)); +void FRAN_SPU_registerCDDAVolume(void (*CDDAVcallback)(unsigned short,unsigned short)); + +/* CDR */ +long CDR__open(void); +long CDR__init(void); +long CDR__shutdown(void); +long CDR__open(void); +long CDR__close(void); +long CDR__getTN(unsigned char *); +long CDR__getTD(unsigned char , unsigned char *); +long CDR__readTrack(unsigned char *); +long CDR__play(unsigned char *sector); +long CDR__stop(void); +long CDR__getStatus(struct CdrStat *stat); +unsigned char *CDR__getBuffer(void); +unsigned char *CDR__getBufferSub(void); + +/* NULL GPU */ +//typedef long (* GPUopen)(unsigned long *, char *, char *); +long GPU__open(void); +long GPU__init(void); +long GPU__shutdown(void); +long GPU__close(void); +void GPU__writeStatus(unsigned long); +void GPU__writeData(unsigned long); +unsigned long GPU__readStatus(void); +unsigned long GPU__readData(void); +long GPU__dmaChain(unsigned long *,unsigned long); +void GPU__updateLace(void); + +/* PEOPS GPU */ +long PEOPS_GPUopen(unsigned long *, char *, char *); +long PEOPS_GPUinit(void); +long PEOPS_GPUshutdown(void); +long PEOPS_GPUclose(void); +void PEOPS_GPUwriteStatus(unsigned long); +void PEOPS_GPUwriteData(unsigned long); +void PEOPS_GPUwriteDataMem(unsigned long *, int); +unsigned long PEOPS_GPUreadStatus(void); +unsigned long PEOPS_GPUreadData(void); +void PEOPS_GPUreadDataMem(unsigned long *, int); +long PEOPS_GPUdmaChain(unsigned long *,unsigned long); +void PEOPS_GPUupdateLace(void); +void PEOPS_GPUdisplayText(char *); +long PEOPS_GPUfreeze(unsigned long,GPUFreeze_t *); + +/* PAD */ +//typedef long (* PADopen)(unsigned long *); +extern long PAD__init(long); +extern long PAD__shutdown(void); + +/* WiiSX PAD Plugin */ +extern long PAD__open(void); +extern long PAD__close(void); +unsigned char PAD__startPoll (int pad); +unsigned char PAD__poll (const unsigned char value); +long PAD__readPort1(PadDataS*); +long PAD__readPort2(PadDataS*); + +/* SSSPSX PAD Plugin */ +long SSS_PADopen (void *p); +long SSS_PADclose (void); +unsigned char SSS_PADstartPoll (int pad); +unsigned char SSS_PADpoll (const unsigned char value); +long SSS_PADreadPort1 (PadDataS* pads); +long SSS_PADreadPort2 (PadDataS* pads); + +/* Mooby28 CDR Plugin */ +void CALLBACK Mooby2CDRabout(void); +long CALLBACK Mooby2CDRtest(void); +long CALLBACK Mooby2CDRconfigure(void); +long CALLBACK Mooby2CDRclose(void); +long CALLBACK Mooby2CDRopen(void); +long CALLBACK Mooby2CDRshutdown(void); +long CALLBACK Mooby2CDRplay(unsigned char * sector); +long CALLBACK Mooby2CDRstop(void); +long CALLBACK Mooby2CDRgetStatus(struct CdrStat *stat) ; +char CALLBACK Mooby2CDRgetDriveLetter(void); +long CALLBACK Mooby2CDRinit(void); +long CALLBACK Mooby2CDRgetTN(unsigned char *buffer); +unsigned char * CALLBACK Mooby2CDRgetBufferSub(void); +long CALLBACK Mooby2CDRgetTD(unsigned char track, unsigned char *buffer); +long CALLBACK Mooby2CDRreadTrack(unsigned char *time); +unsigned char * CALLBACK Mooby2CDRgetBuffer(void); + +#define EMPTY_PLUGIN \ + { NULL, \ + 0, \ + { { NULL, \ + NULL }, } } + +#define PAD1_PLUGIN \ + { "PAD1", \ + 7, \ + { { "PADinit", \ + (void*)PAD__init }, \ + { "PADshutdown", \ + (void*)PAD__shutdown}, \ + { "PADopen", \ + (void*)PAD__open}, \ + { "PADclose", \ + (void*)PAD__close}, \ + { "PADpoll", \ + (void*)PAD__poll}, \ + { "PADstartPoll", \ + (void*)PAD__startPoll}, \ + { "PADreadPort1", \ + (void*)PAD__readPort1} \ + } } + +#define PAD2_PLUGIN \ + { "PAD2", \ + 7, \ + { { "PADinit", \ + (void*)PAD__init }, \ + { "PADshutdown", \ + (void*)PAD__shutdown}, \ + { "PADopen", \ + (void*)PAD__open}, \ + { "PADclose", \ + (void*)PAD__close}, \ + { "PADpoll", \ + (void*)PAD__poll}, \ + { "PADstartPoll", \ + (void*)PAD__startPoll}, \ + { "PADreadPort2", \ + (void*)PAD__readPort2} \ + } } + +#define SSS_PAD1_PLUGIN \ + { "PAD1", \ + 7, \ + { { "PADinit", \ + (void*)PAD__init }, \ + { "PADshutdown", \ + (void*)PAD__shutdown}, \ + { "PADopen", \ + (void*)SSS_PADopen}, \ + { "PADclose", \ + (void*)SSS_PADclose}, \ + { "PADpoll", \ + (void*)SSS_PADpoll}, \ + { "PADstartPoll", \ + (void*)SSS_PADstartPoll}, \ + { "PADreadPort1", \ + (void*)SSS_PADreadPort1} \ + } } + +#define SSS_PAD2_PLUGIN \ + { "PAD2", \ + 7, \ + { { "PADinit", \ + (void*)PAD__init }, \ + { "PADshutdown", \ + (void*)PAD__shutdown}, \ + { "PADopen", \ + (void*)SSS_PADopen}, \ + { "PADclose", \ + (void*)SSS_PADclose}, \ + { "PADpoll", \ + (void*)SSS_PADpoll}, \ + { "PADstartPoll", \ + (void*)SSS_PADstartPoll}, \ + { "PADreadPort2", \ + (void*)SSS_PADreadPort2} \ + } } + +#define MOOBY28_CDR_PLUGIN \ + { "CDR", \ + 12, \ + { { "CDRinit", \ + (void*)Mooby2CDRinit }, \ + { "CDRshutdown", \ + (void*)Mooby2CDRshutdown}, \ + { "CDRopen", \ + (void*)Mooby2CDRopen}, \ + { "CDRclose", \ + (void*)Mooby2CDRclose}, \ + { "CDRgetTN", \ + (void*)Mooby2CDRgetTN}, \ + { "CDRgetTD", \ + (void*)Mooby2CDRgetTD}, \ + { "CDRreadTrack", \ + (void*)Mooby2CDRreadTrack}, \ + { "CDRgetBuffer", \ + (void*)Mooby2CDRgetBuffer}, \ + { "CDRplay", \ + (void*)Mooby2CDRplay}, \ + { "CDRstop", \ + (void*)Mooby2CDRstop}, \ + { "CDRgetStatus", \ + (void*)Mooby2CDRgetStatus}, \ + { "CDRgetBufferSub", \ + (void*)Mooby2CDRgetBufferSub} \ + } } + +#define CDR_PLUGIN \ + { "CDR", \ + 12, \ + { { "CDRinit", \ + (void*)CDR__init }, \ + { "CDRshutdown", \ + (void*)CDR__shutdown}, \ + { "CDRopen", \ + (void*)CDR__open}, \ + { "CDRclose", \ + (void*)CDR__close}, \ + { "CDRgetTN", \ + (void*)CDR__getTN}, \ + { "CDRgetTD", \ + (void*)CDR__getTD}, \ + { "CDRreadTrack", \ + (void*)CDR__readTrack}, \ + { "CDRgetBuffer", \ + (void*)CDR__getBuffer}, \ + { "CDRplay", \ + (void*)CDR__play}, \ + { "CDRstop", \ + (void*)CDR__stop}, \ + { "CDRgetStatus", \ + (void*)CDR__getStatus}, \ + { "CDRgetBufferSub", \ + (void*)CDR__getBufferSub} \ + } } + +#define SPU_NULL_PLUGIN \ + { "SPU", \ + 17, \ + { { "SPUinit", \ + (void*)NULL_SPUinit }, \ + { "SPUshutdown", \ + (void*)NULL_SPUshutdown}, \ + { "SPUopen", \ + (void*)NULL_SPUopen}, \ + { "SPUclose", \ + (void*)NULL_SPUclose}, \ + { "SPUconfigure", \ + (void*)NULL_SPUsetConfigFile}, \ + { "SPUabout", \ + (void*)NULL_SPUabout}, \ + { "SPUtest", \ + (void*)NULL_SPUtest}, \ + { "SPUwriteRegister", \ + (void*)NULL_SPUwriteRegister}, \ + { "SPUreadRegister", \ + (void*)NULL_SPUreadRegister}, \ + { "SPUwriteDMA", \ + (void*)NULL_SPUwriteDMA}, \ + { "SPUreadDMA", \ + (void*)NULL_SPUreadDMA}, \ + { "SPUwriteDMAMem", \ + (void*)NULL_SPUwriteDMAMem}, \ + { "SPUreadDMAMem", \ + (void*)NULL_SPUreadDMAMem}, \ + { "SPUplayADPCMchannel", \ + (void*)NULL_SPUplayADPCMchannel}, \ + { "SPUfreeze", \ + (void*)NULL_SPUfreeze}, \ + { "SPUregisterCallback", \ + (void*)NULL_SPUregisterCallback}, \ + { "SPUregisterCDDAVolume", \ + (void*)NULL_SPUregisterCDDAVolume} \ + } } + +#define SPU_PEOPS_PLUGIN \ + { "SPU", \ + 18, \ + { { "SPUinit", \ + (void*)PEOPS_SPUinit }, \ + { "SPUshutdown", \ + (void*)PEOPS_SPUshutdown}, \ + { "SPUopen", \ + (void*)PEOPS_SPUopen}, \ + { "SPUclose", \ + (void*)PEOPS_SPUclose}, \ + { "SPUconfigure", \ + (void*)PEOPS_SPUsetConfigFile}, \ + { "SPUabout", \ + (void*)PEOPS_SPUabout}, \ + { "SPUtest", \ + (void*)PEOPS_SPUtest}, \ + { "SPUwriteRegister", \ + (void*)PEOPS_SPUwriteRegister}, \ + { "SPUreadRegister", \ + (void*)PEOPS_SPUreadRegister}, \ + { "SPUwriteDMA", \ + (void*)PEOPS_SPUwriteDMA}, \ + { "SPUreadDMA", \ + (void*)PEOPS_SPUreadDMA}, \ + { "SPUwriteDMAMem", \ + (void*)PEOPS_SPUwriteDMAMem}, \ + { "SPUreadDMAMem", \ + (void*)PEOPS_SPUreadDMAMem}, \ + { "SPUplayADPCMchannel", \ + (void*)PEOPS_SPUplayADPCMchannel}, \ + { "SPUfreeze", \ + (void*)PEOPS_SPUfreeze}, \ + { "SPUregisterCallback", \ + (void*)PEOPS_SPUregisterCallback}, \ + { "SPUregisterCDDAVolume", \ + (void*)PEOPS_SPUregisterCDDAVolume}, \ + { "SPUasync", \ + (void*)PEOPS_SPUasync} \ + } } + +#define FRANSPU_PLUGIN \ + { "SPU", \ + 18, \ + { { "SPUinit", \ + (void*)FRAN_SPU_init }, \ + { "SPUshutdown", \ + (void*)FRAN_SPU_shutdown}, \ + { "SPUopen", \ + (void*)FRAN_SPU_open}, \ + { "SPUclose", \ + (void*)FRAN_SPU_close}, \ + { "SPUconfigure", \ + (void*)FRAN_SPU_setConfigFile}, \ + { "SPUabout", \ + (void*)FRAN_SPU_About}, \ + { "SPUtest", \ + (void*)FRAN_SPU_test}, \ + { "SPUwriteRegister", \ + (void*)FRAN_SPU_writeRegister}, \ + { "SPUreadRegister", \ + (void*)FRAN_SPU_readRegister}, \ + { "SPUwriteDMA", \ + (void*)FRAN_SPU_writeDMA}, \ + { "SPUreadDMA", \ + (void*)FRAN_SPU_readDMA}, \ + { "SPUwriteDMAMem", \ + (void*)FRAN_SPU_writeDMAMem}, \ + { "SPUreadDMAMem", \ + (void*)FRAN_SPU_readDMAMem}, \ + { "SPUplayADPCMchannel", \ + (void*)FRAN_SPU_playADPCMchannel}, \ + { "SPUfreeze", \ + (void*)FRAN_SPU_freeze}, \ + { "SPUregisterCallback", \ + (void*)FRAN_SPU_registerCallback}, \ + { "SPUregisterCDDAVolume", \ + (void*)FRAN_SPU_registerCDDAVolume}, \ + { "SPUasync", \ + (void*)FRAN_SPU_async} \ + } } + +#define GPU_NULL_PLUGIN \ + { "GPU", \ + 10, \ + { { "GPUinit", \ + (void*)GPU__init }, \ + { "GPUshutdown", \ + (void*)GPU__shutdown}, \ + { "GPUopen", \ + (void*)GPU__open}, \ + { "GPUclose", \ + (void*)GPU__close}, \ + { "GPUwriteStatus", \ + (void*)GPU__writeStatus}, \ + { "GPUwriteData", \ + (void*)GPU__writeData}, \ + { "GPUreadStatus", \ + (void*)GPU__readStatus}, \ + { "GPUreadData", \ + (void*)GPU__readData}, \ + { "GPUdmaChain", \ + (void*)GPU__dmaChain}, \ + { "GPUupdateLace", \ + (void*)GPU__updateLace} \ + } } + +#define GPU_PEOPS_PLUGIN \ + { "GPU", \ + 14, \ + { { "GPUinit", \ + (void*)PEOPS_GPUinit }, \ + { "GPUshutdown", \ + (void*)PEOPS_GPUshutdown}, \ + { "GPUopen", \ + (void*)PEOPS_GPUopen}, \ + { "GPUclose", \ + (void*)PEOPS_GPUclose}, \ + { "GPUwriteStatus", \ + (void*)PEOPS_GPUwriteStatus}, \ + { "GPUwriteData", \ + (void*)PEOPS_GPUwriteData}, \ + { "GPUwriteDataMem", \ + (void*)PEOPS_GPUwriteDataMem}, \ + { "GPUreadStatus", \ + (void*)PEOPS_GPUreadStatus}, \ + { "GPUreadData", \ + (void*)PEOPS_GPUreadData}, \ + { "GPUreadDataMem", \ + (void*)PEOPS_GPUreadDataMem}, \ + { "GPUdmaChain", \ + (void*)PEOPS_GPUdmaChain}, \ + { "GPUdisplayText", \ + (void*)PEOPS_GPUdisplayText}, \ + { "GPUfreeze", \ + (void*)PEOPS_GPUfreeze}, \ + { "GPUupdateLace", \ + (void*)PEOPS_GPUupdateLace} \ + } } + +#define PLUGIN_SLOT_0 EMPTY_PLUGIN +//#define PLUGIN_SLOT_1 PAD1_PLUGIN +#define PLUGIN_SLOT_1 SSS_PAD1_PLUGIN +//#define PLUGIN_SLOT_2 PAD2_PLUGIN +#define PLUGIN_SLOT_2 SSS_PAD2_PLUGIN +//#define PLUGIN_SLOT_3 CDR_PLUGIN +#define PLUGIN_SLOT_3 MOOBY28_CDR_PLUGIN +//#define PLUGIN_SLOT_4 SPU_NULL_PLUGIN +//#define PLUGIN_SLOT_4 SPU_PEOPS_PLUGIN +#define PLUGIN_SLOT_4 FRANSPU_PLUGIN +//#define PLUGIN_SLOT_5 GPU_NULL_PLUGIN +#define PLUGIN_SLOT_5 GPU_PEOPS_PLUGIN +#define PLUGIN_SLOT_6 EMPTY_PLUGIN +#define PLUGIN_SLOT_7 EMPTY_PLUGIN + + + +#endif + diff --git a/Gamecube/MEM2.h b/Gamecube/MEM2.h new file mode 100644 index 0000000..cf36c2b --- /dev/null +++ b/Gamecube/MEM2.h @@ -0,0 +1,38 @@ +/* MEM2.h - MEM2 boundaries for different chunks of memory + by Mike Slegeir for Mupen64-Wii adapted for WiiSX by emu_kidid + */ + +#ifndef MEM2_H +#define MEM2_H + +// Define a MegaByte +#define KB (1024) +#define MB (1024*1024) + +// MEM2 begins at MEM2_LO, the Starlet's Dedicated Memory begins at MEM2_HI +#define MEM2_LO ((char*)0x90080000) +#define MEM2_HI ((char*)0x933E0000) +#define MEM2_SIZE (MEM2_HI - MEM2_LO) + +// We want 128KB for our MEMCARD 1 +#define MCD1_SIZE (128*KB) +#define MCD1_LO (MEM2_LO) +#define MCD1_HI (MCD1_LO + MCD1_SIZE) + +// We want 128KB for our MEMCARD 2 +#define MCD2_SIZE (128*KB) +#define MCD2_LO (MCD1_HI) +#define MCD2_HI (MCD2_LO + MCD2_SIZE) + +// We want 256KB for fontFont +#define FONT_SIZE (256*KB) +#define FONT_LO (MCD2_HI) +#define FONT_HI (FONT_LO + FONT_SIZE) + +// We want 256KB for fontFont +#define FONTWORK_SIZE (128*KB) +#define FONTWORK_LO (FONT_HI) +#define FONTWORK_HI (FONTWORK_LO + FONTWORK_SIZE) + + +#endif diff --git a/Gamecube/Makefile_GC b/Gamecube/Makefile_GC new file mode 100644 index 0000000..5a618b8 --- /dev/null +++ b/Gamecube/Makefile_GC @@ -0,0 +1,146 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/gamecube_rules + +#--------------------------------------------------------------------------------- +# GPU Plugin (GX or Soft) +# For example, run "make GPU=GX" for GX +#--------------------------------------------------------------------------------- +GPU = Soft + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := CubeSXRX +BUILD := build +SOURCES := . ../cdrmooby28/ ./gc_input/ ./libgui/ ./menu/ ./fileBrowser/ .. ../ppc/ ../Peops$(GPU)GPU/ ../franspu/ + +DATA := data + +INCLUDES := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -g -flto -O3 -ffast-math -Wall $(MACHDEP) $(INCLUDE) -D__GAMECUBE__ -DHW_DOL -D__ppc__ \ + -D__GX__ -DEMBEDDED_FONTS \ + -DTHREADED_AUDIO -DRELEASE #-DSHOW_DEBUG -DPROFILE + +CXXFLAGS = $(CFLAGS) + +ASFLAGS := -DHW_DOL + +LDFLAGS = -g $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -laesnd -lz -lm -lfat -logc + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) \ + -I$(DEVKITPRO)/libogc/include, -I$(DEVKITPRO)/libfat/libogc/include + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) \ + -L$(DEVKITPRO)/libogc/lib/cube, -L$(DEVKITPRO)/libfat/libogc/lib/cube + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile_GC + @echo creating ... $(notdir $(OUTPUT)).dol + @$(DEVKITPPC)/bin/elf2dol $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/Gamecube/Makefile_Wii b/Gamecube/Makefile_Wii new file mode 100644 index 0000000..8aae1af --- /dev/null +++ b/Gamecube/Makefile_Wii @@ -0,0 +1,146 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules + +#--------------------------------------------------------------------------------- +# GPU Plugin (GX or Soft) +# For example, run "make GPU=GX" for GX +#--------------------------------------------------------------------------------- +GPU = Soft + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := WiiSXRX +BUILD := build +SOURCES := . ../cdrmooby28/ ./gc_input/ ./libgui/ ./menu/ ./fileBrowser/ .. ../ppc/ ../Peops$(GPU)GPU/ ../franspu/ + +DATA := data + +INCLUDES := + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -g -flto -O3 -ffast-math -Wall $(MACHDEP) $(INCLUDE) -D__GAMECUBE__ -DWII -DHW_RVL -D__ppc__ \ + -D__GX__ -DEMBEDDED_FONTS \ + -DTHREADED_AUDIO #-DRELEASE -DSHOW_DEBUG -DDEBUGON -DPROFILE -DPRINTGECKO + +CXXFLAGS = $(CFLAGS) + +ASFLAGS := -DHW_RVL + +LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_register + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -laesnd -ldi -liso9660 -lm -lfat -ldb -lwiiuse -lwupc -lbte -logc -lz -ltinysmb + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) \ + -I$(DEVKITPRO)/libogc/include, -I$(DEVKITPRO)/libfat/libogc/include + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) \ + -L$(DEVKITPRO)/libogc/lib/wii, -L$(DEVKITPRO)/libfat/libogc/lib/wii + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile_Wii + @echo creating ... $(notdir $(OUTPUT)).dol + @$(DEVKITPPC)/bin/elf2dol $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/Gamecube/PadSSSPSX.c b/Gamecube/PadSSSPSX.c new file mode 100644 index 0000000..5ccb6a0 --- /dev/null +++ b/Gamecube/PadSSSPSX.c @@ -0,0 +1,488 @@ +/** + * WiiSX - PadSSSPSX.c + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Basic Analog PAD plugin for WiiSX + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * sepp256@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../plugins.h" +#include "../psxcommon.h" +#include "../psemu_plugin_defs.h" +#include "gc_input/controller.h" +#include "wiiSXconfig.h" +#include "PadSSSPSX.h" + +//static BUTTONS PAD_1; +//static BUTTONS PAD_2; +extern PadDataS lastport1; +extern PadDataS lastport2; +static int pad_initialized = 0; + +static struct +{ + SSSConfig config; //unused? + //int devcnt; //unused + u16 padStat[2]; //Digital Buttons + int padID[2]; + int padMode1[2]; //0 = digital, 1 = analog + int padMode2[2]; + int padModeE[2]; //Config/Escape mode?? + int padModeC[2]; + int padModeF[2]; + int padVib0[2]; //Command byte for small motor + int padVib1[2]; //Command byte for large motor + int padVibF[2][4]; //Sm motor value; Big motor value; Sm motor running?; Big motor running? + //int padVibC[2]; //unused + u64 padPress[2][16];//unused? + int curPad; //0=pad1; 1=pad2 + int curByte; //current command/data byte + int curCmd; //current command from PSX/PS2 + int cmdLen; //# of bytes in pad reply +} global; + +extern void SysPrintf(char *fmt, ...); +extern int stop; + +/* Controller type, later do this by a Variable in the GUI */ +//extern char controllerType = 0; // 0 = standard, 1 = analog (analog fails on old games) +extern long PadFlags; + +extern virtualControllers_t virtualControllers[2]; + +// Use to invoke func on the mapped controller with args +#define DO_CONTROL(Control,func,args...) \ + virtualControllers[Control].control->func( \ + virtualControllers[Control].number, ## args) + +void assign_controller(int wv, controller_t* type, int wp); + +static void PADsetMode (const int pad, const int mode) //mode = 0 (digital) or 1 (analog) +{ + static const u8 padID[] = { 0x41, 0x73, 0x41, 0x79 }; + global.padMode1[pad] = mode; + global.padVib0[pad] = 0; + global.padVib1[pad] = 0; + global.padVibF[pad][0] = 0; + global.padVibF[pad][1] = 0; + global.padID[pad] = padID[global.padMode2[pad] * 2 + mode]; +} + +static void UpdateState (const int pad) //Note: pad = 0 or 1 +{ + const int vib0 = global.padVibF[pad][0] ? 1 : 0; + const int vib1 = global.padVibF[pad][1] ? 1 : 0; + static BUTTONS PAD_Data; + + //TODO: Rework/simplify the following code & reset BUTTONS when no controller in use + int Control = pad; +#if defined(WII) && !defined(NO_BT) + //Need to switch between Classic and WiimoteNunchuck if user swapped extensions + if (padType[virtualControllers[Control].number] == PADTYPE_WII) + { + if (virtualControllers[Control].control != &controller_WiiUPro) + { + if (virtualControllers[Control].control == &controller_Classic && + !controller_Classic.available[virtualControllers[Control].number] && + controller_WiimoteNunchuk.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_WiimoteNunchuk, virtualControllers[Control].number); + else if (virtualControllers[Control].control == &controller_WiimoteNunchuk && + !controller_WiimoteNunchuk.available[virtualControllers[Control].number] && + controller_Classic.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_Classic, virtualControllers[Control].number); + } + } +#endif + + if (global.padMode1[pad] != controllerType) + PADsetMode( pad, controllerType == CONTROLLERTYPE_ANALOG ? 1 : 0); + + if(virtualControllers[Control].inUse) + { + if(DO_CONTROL(Control, GetKeys, (BUTTONS*)&PAD_Data, virtualControllers[Control].config)) + stop = 1; + } + else + { //TODO: Emulate no controller present in this case. + //Reset buttons & sticks if PAD is not in use + PAD_Data.btns.All = 0xFFFF; + PAD_Data.leftStickX = PAD_Data.leftStickY = PAD_Data.rightStickX = PAD_Data.rightStickY = 128; + } + + global.padStat[pad] = (((PAD_Data.btns.All>>8)&0xFF) | ( (PAD_Data.btns.All<<8) & 0xFF00 )) &0xFFFF; + + if (pad==0) + { + lastport1.leftJoyX = PAD_Data.leftStickX; lastport1.leftJoyY = PAD_Data.leftStickY; + lastport1.rightJoyX = PAD_Data.rightStickX; lastport1.rightJoyY = PAD_Data.rightStickY; + lastport1.buttonStatus = global.padStat[pad]; + } + else + { + lastport2.leftJoyX = PAD_Data.leftStickX; lastport2.leftJoyY = PAD_Data.leftStickY; + lastport2.rightJoyX = PAD_Data.rightStickX; lastport2.rightJoyY = PAD_Data.rightStickY; + lastport2.buttonStatus = global.padStat[pad]; + } + + /* Small Motor */ + if ((global.padVibF[pad][2] != vib0) ) + { + global.padVibF[pad][2] = vib0; + DO_CONTROL(pad, rumble, global.padVibF[pad][0]); + } + /* Big Motor */ + if ((global.padVibF[pad][3] != vib1) ) + { + global.padVibF[pad][3] = vib1; + DO_CONTROL(pad, rumble, global.padVibF[pad][1]); + } +} + +long SSS_PADopen (void *p) +{ + if (!pad_initialized) + { + memset (&global, 0, sizeof (global)); + memset( &lastport1, 0, sizeof(lastport1) ) ; + memset( &lastport2, 0, sizeof(lastport2) ) ; + global.padStat[0] = 0xffff; + global.padStat[1] = 0xffff; + PADsetMode (0, controllerType == CONTROLLERTYPE_ANALOG ? 1 : 0); //port 0, analog + PADsetMode (1, controllerType == CONTROLLERTYPE_ANALOG ? 1 : 0); //port 1, analog + } + return 0; +} + +long SSS_PADclose (void) +{ + if (pad_initialized) { + pad_initialized=0; + } + return 0 ; +} + +long SSS_PADquery (void) +{ + return 3; +} + +unsigned char SSS_PADstartPoll (int pad) +{ + global.curPad = pad -1; + global.curByte = 0; + return 0xff; +} + +static const u8 cmd40[8] = +{ + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a +}; +static const u8 cmd41[8] = //Find out what buttons are included in poll response +{ + 0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a, +}; +static const u8 cmd44[8] = //Switch modes between digital and analog +{ + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd45[8] = //Get more status info +{ // DS LED ON + 0xff, 0x5a, 0x03, 0x02, 0x01, 0x02, 0x01, 0x00, +}; +// Following commands always issued in sequence: 46, 46, 47, 4C, 4C; Also, only works in config mode (0xF3) +static const u8 cmd46[8] = //Read unknown constant value from controller (called twice) +{ //Note this is the first 5 bytes for Katana Wireless pad. + //May need to change or implement 2nd response, which is indicated by 4th command byte + 0xff, 0x5a, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0a, +}; +static const u8 cmd47[8] = //Read unknown constant value from controller (called once) +{ //Note this is response for Katana Wireless pad + 0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, +}; +static const u8 cmd4c[8] = //Read unknown constant value from controller (called twice) +{ //Note this response seems to be incorrect. May also need to implement 1st/2nd responses + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const u8 cmd4d[8] = //Map bytes in 42 command to actuate motors; only works in config mode (0xF3) +{ //These data bytes should be changed to 00 or 01 if currently mapped to a motor + 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; +static const u8 cmd4f[8] = //Enable/disable digital/analog responses bits; only works in config mode (0xF3) +{ // FF FF 03 <- each bit here corresponds to response byte + 0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, +}; + +unsigned char SSS_PADpoll (const unsigned char value) +{ + const int pad = global.curPad; + const int cur = global.curByte; + +//Pragma to avoid packing on "buffer" union +//Not sure if necessary on PPC +#pragma pack(push,1) + union buffer + { + u16 b16[10]; + u8 b8[20]; + }; + + static union buffer buf; + if (cur == 0) + { + global.curByte++; + global.curCmd = value; + switch (value) + { + case 0x40: + global.cmdLen = sizeof (cmd40); + memcpy (buf.b8, cmd40, sizeof (cmd40)); + return 0xf3; + case 0x41: + global.cmdLen = sizeof (cmd41); + memcpy (buf.b8, cmd41, sizeof (cmd41)); + return 0xf3; + case 0x42: + UpdateState (pad); + case 0x43: + global.cmdLen = 2 + 2 * (global.padID[pad] & 0x0f); + buf.b8[1] = global.padModeC[pad] ? 0x00 : 0x5a; + buf.b16[1] = global.padStat[pad]; + if (value == 0x43 && global.padModeE[pad]) + { + buf.b16[2] = 0; + buf.b16[3] = 0; + return 0xf3; + } + else + { + buf.b8[4] = pad ? lastport2.rightJoyX : lastport1.rightJoyX ; + buf.b8[5] = pad ? lastport2.rightJoyY : lastport1.rightJoyY ; + buf.b8[6] = pad ? lastport2.leftJoyX : lastport1.leftJoyX ; + buf.b8[7] = pad ? lastport2.leftJoyY : lastport1.leftJoyY ; + //if (global.padID[pad] == 0x79) + //{ + // do some pressure stuff (this is for PS2 only!) + //} + return (u8)global.padID[pad]; + } + break; + case 0x44: + global.cmdLen = sizeof (cmd44); + memcpy (buf.b8, cmd44, sizeof (cmd44)); + return 0xf3; + case 0x45: + global.cmdLen = sizeof (cmd45); + memcpy (buf.b8, cmd45, sizeof (cmd45)); + buf.b8[4] = (u8)global.padMode1[pad]; + return 0xf3; + case 0x46: + global.cmdLen = sizeof (cmd46); + memcpy (buf.b8, cmd46, sizeof (cmd46)); + return 0xf3; + case 0x47: + global.cmdLen = sizeof (cmd47); + memcpy (buf.b8, cmd47, sizeof (cmd47)); + return 0xf3; + case 0x4c: + global.cmdLen = sizeof (cmd4c); + memcpy (buf.b8, cmd4c, sizeof (cmd4c)); + return 0xf3; + case 0x4d: + global.cmdLen = sizeof (cmd4d); + memcpy (buf.b8, cmd4d, sizeof (cmd4d)); + return 0xf3; + case 0x4f: + global.padID[pad] = 0x79; + global.padMode2[pad] = 1; + global.cmdLen = sizeof (cmd4f); + memcpy (buf.b8, cmd4f, sizeof (cmd4f)); + return 0xf3; + } + } + switch (global.curCmd) + { + case 0x42: + if (cur == global.padVib0[pad]) + global.padVibF[pad][0] = value; + if (cur == global.padVib1[pad]) + global.padVibF[pad][1] = value; + break; + case 0x43: + if (cur == 2) + { + global.padModeE[pad] = value; // cmd[3]==1 ? enter : exit escape mode + global.padModeC[pad] = 0; + } + break; + case 0x44: + if (cur == 2) + PADsetMode (pad, value); // cmd[3]==1 ? analog : digital + if (cur == 3) + global.padModeF[pad] = (value == 3); //cmd[4]==3 ? lock : don't log analog/digital button + break; + case 0x46: + if (cur == 2) + { + switch(value) + { + case 0x00: + buf.b8[5] = 0x02; + buf.b8[6] = 0x00; + buf.b8[7] = 0x0A; + break; + case 0x01: + buf.b8[5] = 0x01; + buf.b8[6] = 0x01; + buf.b8[7] = 0x14; + break; + } + } + break; + case 0x4c: + if (cur == 2) + { + static const u8 buf5[] = { 0x04, 0x07, 0x02, 0x05 }; + buf.b8[5] = buf5[value & 0x03]; + } + break; + case 0x4d: + if (cur >= 2) + { + if (cur == global.padVib0[pad]) + buf.b8[cur] = 0x00; + else if (cur == global.padVib1[pad]) + buf.b8[cur] = 0x01; + + switch (value) + { + case 0x00: + global.padVib0[pad] = cur; + case 0x01: + if ((global.padID[pad] & 0x0f) < (cur - 1) / 2) + global.padID[pad] = (global.padID[pad] & 0xf0) + (cur - 1) / 2; + if(value) global.padVib1[pad] = cur; + } + } + break; + } + if (cur >= global.cmdLen) + return 0; + return buf.b8[global.curByte++]; +//Revert packing +#pragma pack(pop) +} + +long SSS_PADreadPort1 (PadDataS* pads) +{ + //#PADreadPort1 not used in PCSX +/* + pads->buttonStatus = global.padStat[0]; + + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[0] & 0xf0) == 0x40) + { + pads->rightJoyX = pads->rightJoyY = pads->leftJoyX = pads->leftJoyY = 128 ; + pads->controllerType = PSE_PAD_TYPE_STANDARD; + } + else + { + pads->controllerType = PSE_PAD_TYPE_ANALOGPAD; + int Control = 0; +#if defined(WII) && !defined(NO_BT) + //Need to switch between Classic and WiimoteNunchuck if user swapped extensions + if (padType[virtualControllers[Control].number] == PADTYPE_WII) + { + if (virtualControllers[Control].control == &controller_Classic && + !controller_Classic.available[virtualControllers[Control].number] && + controller_WiimoteNunchuk.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_WiimoteNunchuk, virtualControllers[Control].number); + else if (virtualControllers[Control].control == &controller_WiimoteNunchuk && + !controller_WiimoteNunchuk.available[virtualControllers[Control].number] && + controller_Classic.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_Classic, virtualControllers[Control].number); + } +#endif + if(virtualControllers[Control].inUse) + if(DO_CONTROL(Control, GetKeys, (BUTTONS*)&PAD_1, virtualControllers[Control].config)) + stop = 1; + + pads->leftJoyX = PAD_1.leftStickX; pads->leftJoyY = PAD_1.leftStickY; + pads->rightJoyX = PAD_1.rightStickX; pads->rightJoyY = PAD_1.rightStickY; + } + + memcpy( &lastport1, pads, sizeof( lastport1 ) ) ; +*/ + return 0; +} + +long SSS_PADreadPort2 (PadDataS* pads) +{ + //#PADreadPort2 not used in PCSX +/* + pads->buttonStatus = global.padStat[1]; + + memset (pads, 0, sizeof (PadDataS)); + if ((global.padID[1] & 0xf0) == 0x40) + { + pads->rightJoyX = pads->rightJoyY = pads->leftJoyX = pads->leftJoyY = 128 ; + pads->controllerType = PSE_PAD_TYPE_STANDARD; + } + else + { + pads->controllerType = PSE_PAD_TYPE_ANALOGPAD; + int Control = 1; +#if defined(WII) && !defined(NO_BT) + //Need to switch between Classic and WiimoteNunchuck if user swapped extensions + if (padType[virtualControllers[Control].number] == PADTYPE_WII) + { + if (virtualControllers[Control].control == &controller_Classic && + !controller_Classic.available[virtualControllers[Control].number] && + controller_WiimoteNunchuk.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_WiimoteNunchuk, virtualControllers[Control].number); + else if (virtualControllers[Control].control == &controller_WiimoteNunchuk && + !controller_WiimoteNunchuk.available[virtualControllers[Control].number] && + controller_Classic.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_Classic, virtualControllers[Control].number); + } +#endif + if(virtualControllers[Control].inUse) + if(DO_CONTROL(Control, GetKeys, (BUTTONS*)&PAD_2, virtualControllers[Control].config)) + stop = 1; + + pads->leftJoyX = PAD_2.leftStickX; pads->leftJoyY = PAD_2.leftStickY; + pads->rightJoyX = PAD_2.rightStickX; pads->rightJoyY = PAD_2.rightStickY; + } + + memcpy( &lastport2, pads, sizeof( lastport1 ) ) ; +*/ + return 0; +} diff --git a/Gamecube/PadSSSPSX.h b/Gamecube/PadSSSPSX.h new file mode 100644 index 0000000..ec830a0 --- /dev/null +++ b/Gamecube/PadSSSPSX.h @@ -0,0 +1,33 @@ +/* PADwin + * Copyright (C) 2002-2004 PADwin Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __PADSSS_H__ +#define __PADSSS_H__ + +typedef struct +{ + u32 key; + u32 event; +} keyEvent; + +typedef struct +{ + u32 keys[2][21]; +} SSSConfig; + +#endif diff --git a/Gamecube/PadWiiSX.c b/Gamecube/PadWiiSX.c new file mode 100644 index 0000000..580fe56 --- /dev/null +++ b/Gamecube/PadWiiSX.c @@ -0,0 +1,273 @@ +/** + * WiiSX - PadWiiSX.c + * Copyright (C) 1999-2002 Pcsx Team + * Copyright (C) 2010 sepp256 + * + * PAD plugin for WiiSX based on Pcsxbox sources + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include +#include + +#include "../psxcommon.h" +#include "../psemu_plugin_defs.h" +#include "gc_input/controller.h" +#include "wiiSXconfig.h" + +extern virtualControllers_t virtualControllers[2]; +extern int stop; + +// Use to invoke func on the mapped controller with args +#define DO_CONTROL(Control,func,args...) \ + virtualControllers[Control].control->func( \ + virtualControllers[Control].number, ## args) + +void assign_controller(int wv, controller_t* type, int wp); + +static BUTTONS PAD_1; +static BUTTONS PAD_2; + +//extern unsigned int m_psxfix_controller1 ; +//extern unsigned int m_psxfix_controller2 ; +//extern unsigned int m_psxfix_controller3 ; +//extern unsigned int m_psxfix_controller4 ; +//extern unsigned int m_psxfix_multitap ; + + +static unsigned char buf[256]; +unsigned char stdpar[10] = { 0x00, 0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +unsigned char mousepar[8] = { 0x00, 0x12, 0x5a, 0xff, 0xff, 0xff, 0xff }; +unsigned char analogpar[10] = { 0x00, 0xff, 0x5a, 0xff, 0xff,0xff,0xff,0xff,0xff }; +//unsigned char multipar[36] = { 0x00, 0x80, 0x5a, 0xff, 0xff,0xff,0xff,0xff,0xff }; + +static int bufcount, bufc; + +//PadDataS padd1, padd2; +//int readnopoll( int port ); +//void xbox_read_sticks( unsigned int port, unsigned char *lx, unsigned char *ly, unsigned char *rx, unsigned char *ry ) ; + +long PAD__readPort1(PadDataS* ppad) +{ + int Control = 0; +#if defined(WII) && !defined(NO_BT) + //Need to switch between Classic and WiimoteNunchuck if user swapped extensions + if (padType[virtualControllers[Control].number] == PADTYPE_WII) + { + if (virtualControllers[Control].control != &controller_WiiUPro) + { + if (virtualControllers[Control].control == &controller_Classic && + !controller_Classic.available[virtualControllers[Control].number] && + controller_WiimoteNunchuk.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_WiimoteNunchuk, virtualControllers[Control].number); + else if (virtualControllers[Control].control == &controller_WiimoteNunchuk && + !controller_WiimoteNunchuk.available[virtualControllers[Control].number] && + controller_Classic.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_Classic, virtualControllers[Control].number); + } + } +#endif + if(virtualControllers[Control].inUse) + if(DO_CONTROL(Control, GetKeys, (BUTTONS*)&PAD_1, virtualControllers[Control].config)) + stop = 1; + + + ppad->buttonStatus = (PAD_1.btns.All&0xFFFF); + if ( controllerType == CONTROLLERTYPE_ANALOG ) + { + ppad->controllerType = PSE_PAD_TYPE_ANALOGPAD; + //ppad->controllerType = PSE_PAD_TYPE_ANALOGJOY ; + ppad->leftJoyX = PAD_1.leftStickX; ppad->leftJoyY = PAD_1.leftStickY; + ppad->rightJoyX = PAD_1.rightStickX; ppad->rightJoyY = PAD_1.rightStickY; + } + else + { + ppad->controllerType = PSE_PAD_TYPE_STANDARD; // standard + ppad->rightJoyX = ppad->rightJoyY = ppad->leftJoyX = ppad->leftJoyY = 128 ; + } + + return 0 ; +} + +long PAD__readPort2(PadDataS* ppad) +{ + int Control = 1; +#if defined(WII) && !defined(NO_BT) + //Need to switch between Classic and WiimoteNunchuck if user swapped extensions + if (padType[virtualControllers[Control].number] == PADTYPE_WII) + { + if (virtualControllers[Control].control != &controller_WiiUPro) + { + if (virtualControllers[Control].control == &controller_Classic && + !controller_Classic.available[virtualControllers[Control].number] && + controller_WiimoteNunchuk.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_WiimoteNunchuk, virtualControllers[Control].number); + else if (virtualControllers[Control].control == &controller_WiimoteNunchuk && + !controller_WiimoteNunchuk.available[virtualControllers[Control].number] && + controller_Classic.available[virtualControllers[Control].number]) + assign_controller(Control, &controller_Classic, virtualControllers[Control].number); + } + } +#endif + if(virtualControllers[Control].inUse) + if(DO_CONTROL(Control, GetKeys, (BUTTONS*)&PAD_2, virtualControllers[Control].config)) + stop = 1; + + + ppad->buttonStatus = (PAD_2.btns.All&0xFFFF); + if ( controllerType == CONTROLLERTYPE_ANALOG ) + { + ppad->controllerType = PSE_PAD_TYPE_ANALOGPAD; + //ppad->controllerType = PSE_PAD_TYPE_ANALOGJOY ; + ppad->leftJoyX = PAD_2.leftStickX; ppad->leftJoyY = PAD_2.leftStickY; + ppad->rightJoyX = PAD_2.rightStickX; ppad->rightJoyY = PAD_2.rightStickY; + } + else + { + ppad->controllerType = PSE_PAD_TYPE_STANDARD; // standard + ppad->rightJoyX = ppad->rightJoyY = ppad->leftJoyX = ppad->leftJoyY = 128 ; + } + + return 0 ; +} + +unsigned char _PADstartPoll(PadDataS *pad, unsigned int ismultitap) { + //int i ; + //unsigned short value ; + bufc = 0; + + if ( ismultitap ) + { +/* TODO: Implement 0,1,or 2 multitaps and integrate with gc_input + buf[0] = 0x00 ; + buf[1] = 0x80 ; + buf[2] = 0x5a ; + + for ( i = 0 ; i < 4 ; i++ ) + { + value = readnopoll( i ) ; + buf[ (i*8) + 3] = 0x41 ; + buf[ (i*8) + 4] = 0x5a ; + buf[ (i*8) + 5] = value & 0xff ; + buf[ (i*8) + 6] = value >> 8 ; + buf[ (i*8) + 7] = 0xFF ; + buf[ (i*8) + 8] = 0xFF ; + buf[ (i*8) + 9] = 0xFF ; + buf[ (i*8) + 10]= 0xFF ; + } + + if ( m_psxfix_controller1 ) + { + buf[ (0*8) + 3] = 0x73 ; +// xbox_read_sticks( 0, &(buf[ (0*8) + 9]), &(buf[ (0*8) + 10]), &(buf[ (0*8) + 7]), &(buf[ (0*8) + 8]) ) ; + } + if ( m_psxfix_controller2 ) + { + buf[ (1*8) + 3] = 0x73 ; +// xbox_read_sticks( 1, &(buf[ (1*8) + 9]), &(buf[ (1*8) + 10]), &(buf[ (1*8) + 7]), &(buf[ (1*8) + 8]) ) ; + } + if ( m_psxfix_controller3 ) + { + buf[ (2*8) + 3] = 0x73 ; +// xbox_read_sticks( 2, &(buf[ (2*8) + 9]), &(buf[ (2*8) + 10]), &(buf[ (2*8) + 7]), &(buf[ (2*8) + 8]) ) ; + } + if ( m_psxfix_controller4 ) + { + buf[ (3*8) + 3] = 0x73 ; +// xbox_read_sticks( 3, &(buf[ (3*8) + 9]), &(buf[ (3*8) + 10]), &(buf[ (3*8) + 7]), &(buf[ (3*8) + 8]) ) ; + } + bufcount = 34; +*/ + } + else + { + switch (pad->controllerType) { + case PSE_PAD_TYPE_MOUSE: + mousepar[3] = pad->buttonStatus & 0xff; + mousepar[4] = pad->buttonStatus >> 8; + mousepar[5] = pad->moveX; + mousepar[6] = pad->moveY; + + memcpy(buf, mousepar, 7); + bufcount = 6; + break; + case PSE_PAD_TYPE_ANALOGPAD: // scph1150 + analogpar[1] = 0x73; + analogpar[3] = pad->buttonStatus & 0xff; + analogpar[4] = pad->buttonStatus >> 8; + analogpar[5] = pad->rightJoyX; + analogpar[6] = pad->rightJoyY; + analogpar[7] = pad->leftJoyX; + analogpar[8] = pad->leftJoyY; + + memcpy(buf, analogpar, 9); + bufcount = 8; + break; + case PSE_PAD_TYPE_ANALOGJOY: // scph1110 + analogpar[1] = 0x53; + analogpar[3] = pad->buttonStatus & 0xff; + analogpar[4] = pad->buttonStatus >> 8; + analogpar[5] = pad->rightJoyX; + analogpar[6] = pad->rightJoyY; + analogpar[7] = pad->leftJoyX; + analogpar[8] = pad->leftJoyY; + + memcpy(buf, analogpar, 9); + bufcount = 8; + break; + case 0 : //nothing plugged in + buf[0] = 0xFF ; + buf[1] = 0xFF ; + buf[2] = 0xFF ; + buf[3] = 0xFF ; + buf[4] = 0xFF ; + bufcount = 4 ; + break ; + case PSE_PAD_TYPE_STANDARD: + default: + stdpar[3] = pad->buttonStatus & 0xff; + stdpar[4] = pad->buttonStatus >> 8; + + memcpy(buf, stdpar, 5); + bufcount = 4; + } + } + + //writexbox("ending padpoll\r\n") ; + return buf[bufc++]; +} + +unsigned char PAD__poll(const unsigned char value) { + //writexbox("padpoll\r\n") ; + if (bufc > bufcount) return 0xff; + return buf[bufc++]; +} + +unsigned char PAD__startPoll(int pad) { + PadDataS padd; + + //writexbox("pad1 startpoll\r\n") ; + + memset( &padd, 0, sizeof(padd) ) ; + + if (pad == 1) PAD__readPort1(&padd); + else PAD__readPort2(&padd); + +// return _PADstartPoll(&padd, m_psxfix_multitap); + return _PADstartPoll(&padd, 0); +} diff --git a/Gamecube/PlugCD.c b/Gamecube/PlugCD.c new file mode 100644 index 0000000..68f03e4 --- /dev/null +++ b/Gamecube/PlugCD.c @@ -0,0 +1,463 @@ +/* super basic CD plugin for PCSX Gamecube + by emu_kidid based on the DC port + + TODO: Fix Missing CDDA support(?) +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../plugins.h" +#include "PlugCD.h" +#include "../psxcommon.h" +#include "DEBUG.h" + + +static s32 voice = SND_INVALID; + +extern void SysPrintf(char *fmt, ...); + + +static _CD CD; //Current CD struct +static int isCDDAPlaying = 0; + +//from PeopsCdr104 +#define btoi(b) ((b)/16*10 + (b)%16) +__inline unsigned long time2addrB(unsigned char *time) +{ + unsigned long addr; + + addr = btoi(time[0])*60; + addr = (addr + btoi(time[1]))*75; + addr += btoi(time[2]); + addr -= 150; + return addr; +} + +__inline unsigned long time2addr(unsigned char *time) +{ + unsigned long addr; + + addr = time[0]*60; + addr = (addr + time[1])*75; + addr += time[2]; + addr -= 150; + return addr; +} + +// Gets track number +long getTN(unsigned char* buffer) +{ + int numtracks = getNumTracks(); + sprintf(txtbuffer, "getTN: cd.tl[0].num %i numtracks %i",CD.tl[0].num, numtracks); + DEBUG_print(txtbuffer, DBG_CDR4); + if (-1 == numtracks) { + buffer[0]=buffer[1]=1; + return -1; + } + + buffer[0]=CD.tl[0].num; // First Track + buffer[1]=numtracks; // Last Track + return 0; +} + +// if track==0 -> return total length of cd +// otherwise return start in bcd time format +long getTD(int track, unsigned char* buffer) +{ + + if (track == 0) { // 0 case == last track + buffer[0] = CD.tl[CD.numtracks-1].end[0]; + buffer[1] = CD.tl[CD.numtracks-1].end[1]; + buffer[2] = CD.tl[CD.numtracks-1].end[2]; + } + else { //else any track + buffer[0] = CD.tl[track-1].start[0]; + buffer[1] = CD.tl[track-1].start[1]; + buffer[2] = CD.tl[track-1].start[2]; + } + + sprintf(txtbuffer, "getTD %i: [%u][%u][%u]",track,buffer[0],buffer[1],buffer[2]); + DEBUG_print(txtbuffer, DBG_CDR3); + + // bcd encode it + buffer[0] = intToBCD(buffer[0]); + buffer[1] = intToBCD(buffer[1]); + buffer[2] = intToBCD(buffer[2]); + return 0; +} + +void addBinTrackInfo() +{ + CD.tl = realloc(CD.tl, (CD.numtracks + 1) * sizeof(Track)); + CD.tl[CD.numtracks].end[0] = CD.tl[0].end[0]; + CD.tl[CD.numtracks].end[1] = CD.tl[0].end[1]; + CD.tl[CD.numtracks].end[2] = CD.tl[0].end[2]; + CD.tl[CD.numtracks].start[0] = CD.tl[0].start[0]; + CD.tl[CD.numtracks].start[1] = CD.tl[0].start[1]; + CD.tl[CD.numtracks].start[2] = CD.tl[0].start[2]; +} + +// opens a binary cd image and calculates its length +void openBin(fileBrowser_file* file) +{ + long blocks; + + isoFile_seekFile(file,0,SEEK_SET); + blocks = file->size / 2352; + + // put the track length info in the track list + CD.tl = (Track*) malloc(sizeof(Track)); + + CD.tl[0].type = Mode2; + CD.tl[0].num = 1; + CD.tl[0].start[0] = 0; + CD.tl[0].start[1] = 0; + CD.tl[0].start[2] = 0; + CD.tl[0].end[2] = blocks % 75; + CD.tl[0].end[1] = ((blocks - CD.tl[0].end[2]) / 75) % 60; + CD.tl[0].end[0] = (((blocks - CD.tl[0].end[2]) / 75) - CD.tl[0].end[1]) / 60; + + CD.tl[0].start[1] += 2; + CD.tl[0].end[1] += 2; + + normalizeTime(CD.tl[0].end); + + CD.numtracks = 1; + CD.bufferPos = 0x7FFFFFFF; +} + +// Given a cue sheet fileBrowser_file pointer, parse its track info +void openCue(fileBrowser_file* cueFile) +{ + + // Create a buffer large enough to hold the text and a terminating null + char* cueText = malloc(cueFile->size +1); + if(!cueText) { + SysPrintf("Failed to malloc %dB\n", cueFile->size +1); + while(1); + } + + // Read in the text and end the string with a null + isoFile_readFile(cueFile,cueText,cueFile->size); + cueText[cueFile->size] = 0; + isoFile_deinit(cueFile); + + // FIXME: Make sure we don't have an old tl we're leaking + CD.tl = malloc(sizeof(Track)); + CD.numtracks = 1; + int num_tracks_seen = 0; + char bin_filename[256]; + // Get the first token + char* token = strtok(cueText, " \t\n\r"); + // nxttok() is just shorthand for using strtok to get the next + #define nxttok() strtok(NULL, " \t\n\r") + // Read and parse the cue sheet + while(token){ + // Check against keywords we're intested in and handle if necessary + if( !strcmp(token, "FILE") ){ + // Read in the (first) token for the bin filename + char* temp = nxttok(); + if(temp[0] != '"') + // The filename isn't quoted, just strcpy it to bin_filename + strncpy(bin_filename, temp, 80); + else { + // Read in the quoted string tokens to bin_filename + char* dst = bin_filename; + do { + if(!(*(++temp))){ temp = nxttok(); *(dst++) = ' '; } + *(dst++) = *temp; + } while(*temp != '"'); + *(dst-1) = 0; + } + // FIXME: Byteswap based on BINARY vs MOTOROLA? + /* file_type = */ nxttok(); + + } else if( !strcmp(token, "TRACK") ){ + if(++num_tracks_seen > CD.numtracks) + CD.tl = realloc(CD.tl, ++CD.numtracks * sizeof(Track)); + /* track_num = */ nxttok(); + + char* track_type = nxttok(); + if( !strcmp(track_type, "AUDIO") ) + CD.tl[CD.numtracks-1].type = Audio; + else if( !strcmp(track_type, "MODE1/2352") ) + CD.tl[CD.numtracks-1].type = Mode1; + else if( !strcmp(track_type, "MODE2/2352") ) + CD.tl[CD.numtracks-1].type = Mode2; + else + CD.tl[CD.numtracks-1].type = unknown; + + } else if( !strcmp(token, "INDEX") ){ + nxttok(); // Read and discard the "01" + char* track_start = nxttok(); // mm:ss:ff format + SysPrintf("Track beginning at %s\n", track_start); + track_start[2] = track_start[4] = 0; // Null out the ':' + // Parse the start index to the start value + CD.tl[CD.numtracks-1].start[0] = atoi(track_start+0); + CD.tl[CD.numtracks-1].start[1] = atoi(track_start+3); + CD.tl[CD.numtracks-1].start[2] = atoi(track_start+6); + // If we've already seen another track, this is its end + if(CD.numtracks > 1){ + CD.tl[CD.numtracks-2].end[0] = CD.tl[CD.numtracks-1].start[0]; + CD.tl[CD.numtracks-2].end[1] = CD.tl[CD.numtracks-1].start[1]; + CD.tl[CD.numtracks-2].end[2] = CD.tl[CD.numtracks-1].start[2]; + } + CD.tl[CD.numtracks-1].num = CD.numtracks; + + } + // Get the next token + token = nxttok(); + } + #undef nxttok + // Free the buffer + free(cueText); + + // Create a string with the bin filename based on the cue's path + char relative[256]; + sprintf(relative, "%s/%s", isoFile_topLevel->name, bin_filename); + // Determine relative vs absolute path and get the stat + fileBrowser_file tmpFile; + memset(&tmpFile, 0, sizeof(fileBrowser_file)); + strcpy(&tmpFile.name[0],relative); + if( isoFile_open(&tmpFile) == FILE_BROWSER_ERROR_NO_FILE ){ + SysPrintf("Failed to open %s\n", relative); + // The relative path failed, try absolute + strcpy(&tmpFile.name[0], bin_filename); + if( isoFile_open(&tmpFile) == FILE_BROWSER_ERROR_NO_FILE ){ + SysPrintf("Failed to open %s\n", bin_filename); + while(1); //fix me. + } + } + // Fill out the last track's end based on size + unsigned int blocks = tmpFile.size / 2352; + CD.tl[CD.numtracks-1].end[2] = blocks % 75; + CD.tl[CD.numtracks-1].end[1] = ((blocks - CD.tl[CD.numtracks-1].end[2]) / 75) % 60; + CD.tl[CD.numtracks-1].end[0] = (((blocks - CD.tl[CD.numtracks-1].end[2]) / 75) + - CD.tl[CD.numtracks-1].end[1]) / 60; + normalizeTime(CD.tl[CD.numtracks-1].end); + + // setup the isoFile to now point to the .iso + memcpy(&isoFile, &tmpFile, sizeof(fileBrowser_file)); + SysPrintf("Loaded bin from cue: %s size: %d\n", isoFile.name, isoFile.size); + +} + +// new file types should be added here and in the CDOpen function +void newCD(fileBrowser_file *file) +{ + const char* ext = file->name + strlen(file->name) - 4; + SysPrintf("Opening file with extension %s size: %d\n", ext, file->size); + + if(( !strcmp(ext, ".cue") ) || ( !strcmp(ext, ".CUE") )){ + CD.type = Cue; + openCue(file); //if we open a .cue, the isoFile global will be redirected + } else { + CD.type = Bin; + openBin(file); //setup tracks + addBinTrackInfo(); + } + + CD.bufferPos = 0x7FFFFFFF; + seekSector(0); +} + +// return the sector address - the buffer address + 12 bytes for offset. +unsigned char* getSector(int subchannel) +{ + return CD.buffer + (CD.sector - CD.bufferPos) + ((subchannel) ? 0 : 12); +} + +// returns the number of tracks +char getNumTracks() +{ + return CD.numtracks; +} + +void readit(unsigned long addr) +{ + + // fakie ISO support. iso is just cd-xa data without the ecc and header. + // read in the same number of sectors then space it out to look like cd-xa + /* if (CD.type == Iso) + { + unsigned char temptime[3]; + long tempsector = (( (m * 60) + (s - 2)) * 75 + f) * 2048; + fs_seek(CD.cd, tempsector, SEEK_SET); + fs_read(CD.buffer, sizeof(unsigned char), 2048*BUFFER_SECTORS, CD.cd); + + // spacing out the data here... + for(tempsector = BUFFER_SECTORS - 1; tempsector >= 0; tempsector--) + { + memcpy(&CD.buffer[tempsector*2352 + 24],&CD.buffer[tempsector*2048], 2048); + + // two things - add the m/s/f flags in case anyone is looking + // and change the xa mode to 1 + temptime[0] = m; + temptime[1] = s; + temptime[2] = f + (unsigned char)tempsector; + + normalizeTime(temptime); + CD.buffer[tempsector*2352+12] = intToBCD(temptime[0]); + CD.buffer[tempsector*2352+12+1] = intToBCD(temptime[1]); + CD.buffer[tempsector*2352+12+2] = intToBCD(temptime[2]); + CD.buffer[tempsector*2352+12+3] = 0x01; + } + } + else */ + { + isoFile_seekFile(&isoFile,CD.sector, FILE_BROWSER_SEEK_SET); + if(CD.sector + BUFFER_SIZE > isoFile.size) + isoFile_readFile(&isoFile,CD.buffer,isoFile.size-CD.sector); //read till the end + else + isoFile_readFile(&isoFile,CD.buffer,BUFFER_SIZE); //read buffer size + } + + CD.bufferPos = CD.sector; +} + + +void seekSector(unsigned long addr) +{ + // calc byte to search for + CD.sector = addr * 2352; + + // is it cached? + if ((CD.sector >= CD.bufferPos) && (CD.sector < (CD.bufferPos + BUFFER_SIZE)) ) + { + return; + } + // not cached - read a few blocks into the cache + else + { + readit(addr); + } +} + +long CDR__open(void) +{ + newCD(&isoFile); + return 0; +} + +long CDR__init(void) { + // Get a voice for CDDA + voice = ASND_GetFirstUnusedVoice(); + return 0; +} + +long CDR__shutdown(void) { + // Free our CDDA voice + ASND_StopVoice(voice); + return 0; +} + +long CDR__close(void) { + if(CD.tl) + free(CD.tl); + return 0; +} + +long CDR__getTN(unsigned char *buffer) { + return getTN(buffer); +} + +long CDR__getTD(unsigned char track, unsigned char *buffer) { + + unsigned char temp[3]; + int result = getTD((int)track, temp); + + if (result == -1) return -1; + + buffer[1] = temp[1]; + buffer[2] = temp[0]; + return 0; +} + +/* called when the psx requests a read */ +long CDR__readTrack(unsigned char *time) { + seekSector(time2addrB(time)); + return PSE_CDR_ERR_SUCCESS; +} + +/* called after the read should be finished, and the data is needed */ +unsigned char *CDR__getBuffer(void) { + return getSector(0); +} + +unsigned char *CDR__getBufferSub(void) { + return getSector(1); +} + +//static playCDDA(s32 voice) { + // If voice == -1, this is the start of the track + // TODO: Read in some CDDA, and send it to ASND +//} + +long CDR__play(unsigned char *msf) { + //unsigned long byteSector = ( msf[0] * 75 * 60 ) + ( msf[1] * 75 ) + msf[2]; //xbox way +#ifdef SHOW_DEBUG + unsigned int byteSector = time2addr(msf); //peops way + sprintf(txtbuffer,"CDR play %08X",byteSector); + DEBUG_print(txtbuffer, DBG_CDR1); +#endif + // Time will need to be updated in a thread. + //isCDDAPlaying will need to made 0 on track end (threaded). + isCDDAPlaying = 1; + return PSE_CDR_ERR_SUCCESS; +} +long CDR__stop(void) { + DEBUG_print("CDR Stop", DBG_CDR1); + isCDDAPlaying = 0; + return PSE_CDR_ERR_SUCCESS; +} + + + +// reads cdr status +// type: +// 0x00 - unknown +// 0x01 - data +// 0x02 - audio +// 0xff - no cdrom +// status: +// 0x00 - unknown +// 0x02 - error +// 0x08 - seek error +// 0x10 - shell open +// 0x20 - reading +// 0x40 - seeking +// 0x80 - playing +// time: +// byte 0 - minute +// byte 1 - second +// byte 2 - frame + +long CDR__getStatus(struct CdrStat *stat) { + DEBUG_print("CDR getStatus", DBG_CDR2); + + stat->Status = 0; // Ok so far + + if(isCDDAPlaying) { + stat->Type = 0x02; // Audio + stat->Status|=0x80; // Playing flag + // Time will need to be updated in a thread. + stat->Time[0] = 0; // current play time + stat->Time[1] = 0; + stat->Time[2] = 0; + } + else { + stat->Type = 0x01; // Data + } + + return 0; +} + diff --git a/Gamecube/PlugCD.h b/Gamecube/PlugCD.h new file mode 100644 index 0000000..ea4a23f --- /dev/null +++ b/Gamecube/PlugCD.h @@ -0,0 +1,107 @@ +#ifndef _PLUGCD_H_ +#define _PLUGCD_H_ + +#include +#include +#include "fileBrowser/fileBrowser.h" +#define CHAR_LEN 256 + +// 2352 is a sector size, so cache is 50 sectors +#define BUFFER_SECTORS 32 +#define BUFFER_SIZE BUFFER_SECTORS*2352 +#define BZIP_BUFFER_SECTORS 10 + +// 74 minutes * 60 sex/min * 75 frames/sec * 96 bytes needed per frame +#define TOTAL_CD_LENGTH 74*60*75 +#define BYTES_PER_SUBCHANNEL_FRAME 96 +#define MAX_SUBCHANNEL_DATA TOTAL_CD_LENGTH*BYTES_PER_SUBCHANNEL_FRAME + +typedef struct { + char dn[128]; + char fn[128]; +} cd_conf; + +cd_conf CDConfiguration; + +enum TrackType +{ + unknown, Mode1, Mode2, Audio, Pregap = 0x80 +}; + +enum CDType +{ + unk, Bin, Cue, Rar, IndexBZ, IndexZ, SBI, M3S +}; + +typedef struct +{ + enum TrackType type; + char num; + unsigned char start[3]; + unsigned char end[3]; +} Track; + +typedef struct +{ + fileBrowser_file* cd; + fileBrowser_file* cdda; + int numtracks; + long bufferPos; + long sector; + Track* tl; + unsigned char buffer[BUFFER_SIZE]; + enum CDType type; +} _CD; + +void CDDAclose(void); + +// function headers for cdreader.c +void openCue(fileBrowser_file* file); +void openBin(fileBrowser_file* file); +void openIso(fileBrowser_file* filename); +char getNumTracks(); +void seekSector(unsigned long addr); +unsigned char* getSector(); +void newCD(fileBrowser_file* filename); +void readit(unsigned long addr); + + +// subtracts two times in integer format (non-BCD) -> l - r = a +#define sub(l, r, a)\ + a[1] = 0;\ + a[0] = 0;\ + a[2] = l[2] - r[2];\ + if ((char)a[2] < 0)\ + {\ + a[2] += 75;\ + a[1] -= 1;\ + }\ + a[1] += l[1] - r[1];\ + if ((char)a[1] < 0)\ + {\ + a[1] += 60;\ + a[0] -= 1;\ + }\ + a[0] += l[0] - r[0];\ + +// converts a time like 17:61:00 to 18:01:00 +#define normalizeTime(c)\ + while(c[2] > 75)\ + {\ + c[2] -= 75;\ + c[1] += 1;\ + }\ + while(c[1] > 60)\ + {\ + c[1] -= 60;\ + c[0] += 1;\ + } + +// converts uchar in c to BCD character +#define intToBCD(c) (unsigned char)((c%10) | ((c/10)<<4)) + +// converts BCD number in c to uchar +#define BCDToInt(c) (unsigned char)((c & 0x0F) + 10 * ((c & 0xF0) >> 4)) + +#endif + diff --git a/Gamecube/PlugGPU.c b/Gamecube/PlugGPU.c new file mode 100644 index 0000000..935089c --- /dev/null +++ b/Gamecube/PlugGPU.c @@ -0,0 +1,20 @@ +/* NULL GFX for cubeSX by emu_kidid + +*/ + +#include +#include +#include +#include +#include "../plugins.h" + +long GPU__open(void) { return 0; } +long GPU__init(void) { return 0; } +long GPU__shutdown(void) { return 0; } +long GPU__close(void) { return 0; } +void GPU__writeStatus(unsigned long a){} +void GPU__writeData(unsigned long a){} +unsigned long GPU__readStatus(void) { return 0; } +unsigned long GPU__readData(void) { return 0; } +long GPU__dmaChain(unsigned long *a ,unsigned long b) { return 0; } +void GPU__updateLace(void) { } diff --git a/Gamecube/PlugPAD.c b/Gamecube/PlugPAD.c new file mode 100644 index 0000000..0429fa0 --- /dev/null +++ b/Gamecube/PlugPAD.c @@ -0,0 +1,332 @@ +/** + * WiiSX - PlugPAD.c + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Basic Analog PAD plugin for WiiSX + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * sepp256@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../plugins.h" +#include "../psxcommon.h" +#include "../psemu_plugin_defs.h" +#include "gc_input/controller.h" +#include "wiiSXconfig.h" +#include "PadSSSPSX.h" + +PadDataS lastport1; +PadDataS lastport2; + +extern void SysPrintf(char *fmt, ...); +extern int stop; + +/* Controller type, later do this by a Variable in the GUI */ +//extern char controllerType = 0; // 0 = standard, 1 = analog (analog fails on old games) +long PadFlags = 0; + +virtualControllers_t virtualControllers[2]; + +controller_t* controller_ts[num_controller_t] = +#if defined(WII) && !defined(NO_BT) + { &controller_GC, &controller_Classic, + &controller_WiimoteNunchuk, + &controller_Wiimote, + &controller_WiiUPro, + }; +#else + { &controller_GC, + }; +#endif + +// Use to invoke func on the mapped controller with args +#define DO_CONTROL(Control,func,args...) \ + virtualControllers[Control].control->func( \ + virtualControllers[Control].number, ## args) + +void control_info_init(void){ + //Call once during emulator start to auto assign controllers + init_controller_ts(); + auto_assign_controllers(); +} + +void pauseInput(void){ + int i; + for(i=0; i<2; ++i) + if(virtualControllers[i].inUse) DO_CONTROL(i, pause); +} + +void resumeInput(void){ + int i; + for(i=0; i<2; ++i) + if(virtualControllers[i].inUse) DO_CONTROL(i, resume); +} + +void init_controller_ts(void){ + int i, j; + for(i=0; irefreshAvailable(); + + for(j=0; j<4; ++j){ + memcpy(&controller_ts[i]->config[j], + &controller_ts[i]->config_default, + sizeof(controller_config_t)); + memcpy(&controller_ts[i]->config_slot[j], + &controller_ts[i]->config_default, + sizeof(controller_config_t)); + } + } +} + +void assign_controller(int wv, controller_t* type, int wp){ + virtualControllers[wv].control = type; + virtualControllers[wv].inUse = 1; + virtualControllers[wv].number = wp; + virtualControllers[wv].config = &type->config[wv]; + + type->assign(wp,wv); +} + +void unassign_controller(int wv){ + virtualControllers[wv].control = NULL; + virtualControllers[wv].inUse = 0; + virtualControllers[wv].number = -1; +} + +void auto_assign_controllers(void) +{ + //TODO: Map 5 or 8 controllers if multitaps are used. + int i,t,w; + int num_assigned[num_controller_t]; + +// init_controller_ts(); + + memset(num_assigned, 0, sizeof(num_assigned)); + + // Map controllers in the priority given + // Outer loop: virtual controllers + for(i=0; i<2; ++i){ + // Middle loop: controller type + for(t=0; trefreshAvailable(); + + // Inner loop: which controller + for(w=num_assigned[t]; w<4 && !type->available[w]; ++w, ++num_assigned[t]); + // If we've exhausted this type, move on + if(w == 4) continue; + + assign_controller(i, type, w); + padType[i] = type == &controller_GC ? PADTYPE_GAMECUBE : PADTYPE_WII; + padAssign[i] = w; + + // Don't assign the next type over this one or the same controller + ++num_assigned[t]; + break; + } + if(t == num_controller_t) + break; + } + + // 'Initialize' the unmapped virtual controllers + for(; i<2; ++i){ + unassign_controller(i); + padType[i] = PADTYPE_NONE; + } +} + +int load_configurations(FILE* f, controller_t* controller){ + int i; + char magic[4] = { + 'W', 'X', controller->identifier, CONTROLLER_CONFIG_VERSION + }; + char actual[4]; + fread(actual, 1, 4, f); + if(memcmp(magic, actual, 4)) + return 0; + + inline button_t* getPointer(button_t* list, int size){ + int index; + fread(&index, 4, 1, f); + return list + (index % size); + } + inline button_t* getButton(void){ + return getPointer(controller->buttons, controller->num_buttons); + } + + for(i=0; i<4; ++i){ + controller->config_slot[i].SQU = getButton(); + controller->config_slot[i].CRO = getButton(); + controller->config_slot[i].CIR = getButton(); + controller->config_slot[i].TRI = getButton(); + + controller->config_slot[i].R1 = getButton(); + controller->config_slot[i].L1 = getButton(); + controller->config_slot[i].R2 = getButton(); + controller->config_slot[i].L2 = getButton(); + controller->config_slot[i].R3 = getButton(); + controller->config_slot[i].L3 = getButton(); + + controller->config_slot[i].DL = getButton(); + controller->config_slot[i].DR = getButton(); + controller->config_slot[i].DU = getButton(); + controller->config_slot[i].DD = getButton(); + + controller->config_slot[i].START = getButton(); + controller->config_slot[i].SELECT = getButton(); + + controller->config_slot[i].analogL = + getPointer(controller->analog_sources, controller->num_analog_sources); + controller->config_slot[i].analogR = + getPointer(controller->analog_sources, controller->num_analog_sources); + controller->config_slot[i].exit = + getPointer(controller->menu_combos, controller->num_menu_combos); + fread(&controller->config_slot[i].invertedYL, 4, 1, f); + fread(&controller->config_slot[i].invertedYR, 4, 1, f); + } + + if (loadButtonSlot != LOADBUTTON_DEFAULT) { + int j; + for(j=0; j<4; ++j) + memcpy(&controller->config[j], + &controller->config_slot[(int)loadButtonSlot], + sizeof(controller_config_t)); + } + + return 1; +} + +void save_configurations(FILE* f, controller_t* controller){ + int i; + char magic[4] = { + 'W', 'X', controller->identifier, CONTROLLER_CONFIG_VERSION + }; + fwrite(magic, 1, 4, f); + + for(i=0; i<4; ++i){ + fwrite(&controller->config_slot[i].SQU->index, 4, 1, f); + fwrite(&controller->config_slot[i].CRO->index, 4, 1, f); + fwrite(&controller->config_slot[i].CIR->index, 4, 1, f); + fwrite(&controller->config_slot[i].TRI->index, 4, 1, f); + + fwrite(&controller->config_slot[i].R1->index, 4, 1, f); + fwrite(&controller->config_slot[i].L1->index, 4, 1, f); + fwrite(&controller->config_slot[i].R2->index, 4, 1, f); + fwrite(&controller->config_slot[i].L2->index, 4, 1, f); + fwrite(&controller->config_slot[i].R3->index, 4, 1, f); + fwrite(&controller->config_slot[i].L3->index, 4, 1, f); + + fwrite(&controller->config_slot[i].DL->index, 4, 1, f); + fwrite(&controller->config_slot[i].DR->index, 4, 1, f); + fwrite(&controller->config_slot[i].DU->index, 4, 1, f); + fwrite(&controller->config_slot[i].DD->index, 4, 1, f); + + fwrite(&controller->config_slot[i].START->index, 4, 1, f); + fwrite(&controller->config_slot[i].SELECT->index, 4, 1, f); + + fwrite(&controller->config_slot[i].analogL->index, 4, 1, f); + fwrite(&controller->config_slot[i].analogR->index, 4, 1, f); + fwrite(&controller->config_slot[i].exit->index, 4, 1, f); + fwrite(&controller->config_slot[i].invertedYL, 4, 1, f); + fwrite(&controller->config_slot[i].invertedYR, 4, 1, f); + } +} + +long PAD__init(long flags) { + PadFlags |= flags; + + return PSE_PAD_ERR_SUCCESS; +} + +long PAD__shutdown(void) { + return PSE_PAD_ERR_SUCCESS; +} + +long PAD__open(void) +{ + return PSE_PAD_ERR_SUCCESS; +} + +long PAD__close(void) { + return PSE_PAD_ERR_SUCCESS; +} +/* +long PAD__readPort1(PadDataS* pad) { + //TODO: Multitap support; Light Gun support + + if( virtualControllers[0].inUse && DO_CONTROL(0, GetKeys, (BUTTONS*)&PAD_1) ) { + stop = 1; + } + + if(controllerType == CONTROLLERTYPE_STANDARD) { + pad->controllerType = PSE_PAD_TYPE_STANDARD; // Standard Pad + } + else if(controllerType == CONTROLLERTYPE_ANALOG) { + pad->controllerType = PSE_PAD_TYPE_ANALOGPAD; // Analog Pad (Right JoyStick) + pad->leftJoyX = PAD_1.leftStickX; + pad->leftJoyY = PAD_1.leftStickY; + pad->rightJoyX = PAD_1.rightStickX; + pad->rightJoyY = PAD_1.rightStickY; + } + else { + //TODO: Light Gun + } + + pad->buttonStatus = PAD_1.btns.All; //set the buttons + + return PSE_PAD_ERR_SUCCESS; +} + +long PAD__readPort2(PadDataS* pad) { + //TODO: Multitap support; Light Gun support + + if( virtualControllers[1].inUse && DO_CONTROL(1, GetKeys, (BUTTONS*)&PAD_2) ) { + stop = 1; + } + + if(controllerType == CONTROLLERTYPE_STANDARD) { + pad->controllerType = PSE_PAD_TYPE_STANDARD; // Standard Pad + } + else if(controllerType == CONTROLLERTYPE_ANALOG) { + pad->controllerType = PSE_PAD_TYPE_ANALOGPAD; // Analog Pad (Right JoyStick) + pad->leftJoyX = PAD_2.leftStickX; + pad->leftJoyY = PAD_2.leftStickY; + pad->rightJoyX = PAD_2.rightStickX; + pad->rightJoyY = PAD_2.rightStickY; + } + else { + //TODO: Light Gun + } + + pad->buttonStatus = PAD_2.btns.All; //set the buttons + + return PSE_PAD_ERR_SUCCESS; +} +*/ diff --git a/Gamecube/Plugin.c b/Gamecube/Plugin.c new file mode 100644 index 0000000..362ab4d --- /dev/null +++ b/Gamecube/Plugin.c @@ -0,0 +1,304 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "../psxcommon.h" +#include "fileBrowser/fileBrowser.h" + +#include "../plugins.h" +#include "../spu.h" +#ifndef __GX__ +#include "NoPic.h" +#endif //!__GX__ + +void OnFile_Exit(){} + +unsigned long gpuDisp; + +int StatesC = 0; +extern int UseGui; +int cdOpenCase = 0; +int ShowPic=0; + +void gpuShowPic() { + /*char Text[255]; + gzFile f; + + if (!ShowPic) { + unsigned char *pMem; + + pMem = (unsigned char *) malloc(128*96*3); + if (pMem == NULL) return; + sprintf(Text, "sstates/%10.10s.%3.3d", CdromLabel, StatesC); + + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + + f = gzopen(Text, "rb"); + if (f != NULL) { + gzseek(f, 32, SEEK_SET); // skip header + gzread(f, pMem, 128*96*3); + gzclose(f); + } else { + memcpy(pMem, NoPic_Image.pixel_data, 128*96*3); + DrawNumBorPic(pMem, StatesC+1); + } + GPU_showScreenPic(pMem); + + free(pMem); + ShowPic = 1; + } else { GPU_showScreenPic(NULL); ShowPic = 0; }*/ +} + +void PADhandleKey(int key) { +/* char Text[255]; + int ret; + + switch (key) { + case 0: break; + case XK_F1: + sprintf(Text, "sstates/%10.10s.%3.3d", CdromLabel, StatesC); + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + ret = SaveState(Text); + if (ret == 0) + sprintf(Text, _("*PCSX*: Saved State %d"), StatesC+1); + else sprintf(Text, _("*PCSX*: Error Saving State %d"), StatesC+1); + GPU_displayText(Text); + if (ShowPic) { ShowPic = 0; gpuShowPic(); } + break; + case XK_F2: + if (StatesC < 4) StatesC++; + else StatesC = 0; + GPU_freeze(2, (GPUFreeze_t *)&StatesC); + if (ShowPic) { ShowPic = 0; gpuShowPic(); } + break; + case XK_F3: + sprintf (Text, "sstates/%10.10s.%3.3d", CdromLabel, StatesC); + ret = LoadState(Text); + if (ret == 0) + sprintf(Text, _("*PCSX*: Loaded State %d"), StatesC+1); + else sprintf(Text, _("*PCSX*: Error Loading State %d"), StatesC+1); + GPU_displayText(Text); + break; + case XK_F4: + gpuShowPic(); + break; + case XK_F5: + Config.Sio ^= 0x1; + if (Config.Sio) + sprintf(Text, _("*PCSX*: Sio Irq Always Enabled")); + else sprintf(Text, _("*PCSX*: Sio Irq Not Always Enabled")); + GPU_displayText(Text); + break; + case XK_F6: + Config.Mdec ^= 0x1; + if (Config.Mdec) + sprintf(Text, _("*PCSX*: Black&White Mdecs Only Enabled")); + else sprintf(Text, _("*PCSX*: Black&White Mdecs Only Disabled")); + GPU_displayText(Text); + break; + case XK_F7: + Config.Xa ^= 0x1; + if (Config.Xa == 0) + sprintf (Text, _("*PCSX*: Xa Enabled")); + else sprintf (Text, _("*PCSX*: Xa Disabled")); + GPU_displayText(Text); + break; + case XK_F8: + GPU_makeSnapshot(); + break; + case XK_F9: + cdOpenCase = 1; + break; + case XK_F10: + cdOpenCase = 0; + break; + case XK_Escape: + ClosePlugins(); + UpdateMenuSlots(); + if (!UseGui) OnFile_Exit(); + RunGui(); + break; + default: + GPU_keypressed(key); + if (Config.UseNet) NET_keypressed(key); + }*/ +} + +long PAD1__open(void) { + return PAD1_open(&gpuDisp); +} + +long PAD2__open(void) { + return PAD2_open(&gpuDisp); +} + +void OnFile_Exit(); + +void SignalExit(int sig) { + ClosePlugins(); + OnFile_Exit(); +} + +void SPUirq(void); + +int NetOpened = 0; + +#define PARSEPATH(dst, src) \ + ptr = src + strlen(src); \ + while (*ptr != '\\' && ptr != src) ptr--; \ + if (ptr != src) { \ + strcpy(dst, ptr+1); \ + } + +int _OpenPlugins() { + int ret; + +/* signal(SIGINT, SignalExit); + signal(SIGPIPE, SignalExit);*/ + + GPU_clearDynarec(clearDynarec); + + ret = CDR_open(); + if (ret < 0) { SysPrintf("Error Opening CDR Plugin\n"); return -1; } + ret = SPU_open(); + if (ret < 0) { SysPrintf("Error Opening SPU Plugin\n"); return -1; } + SPU_registerCallback(SPUirq); + ret = GPU_open(&gpuDisp, "PCSX", NULL); + if (ret < 0) { SysPrintf("Error Opening GPU Plugin\n"); return -1; } + ret = PAD1_open(&gpuDisp); + if (ret < 0) { SysPrintf("Error Opening PAD1 Plugin\n"); return -1; } + ret = PAD2_open(&gpuDisp); + if (ret < 0) { SysPrintf("Error Opening PAD2 Plugin\n"); return -1; } + + if (Config.UseNet && NetOpened == 0) { + netInfo info; + char path[256]; + + strcpy(info.EmuName, "PCSX v1.5b3"); + strncpy(info.CdromID, CdromId, 9); + strncpy(info.CdromLabel, CdromLabel, 9); + info.psxMem = psxM; + info.GPU_showScreenPic = GPU_showScreenPic; + info.GPU_displayText = GPU_displayText; + info.GPU_showScreenPic = GPU_showScreenPic; + info.PAD_setSensitive = PAD1_setSensitive; + sprintf(path, "%s%s", Config.BiosDir, Config.Bios); + strcpy(info.BIOSpath, path); + strcpy(info.MCD1path, Config.Mcd1); + strcpy(info.MCD2path, Config.Mcd2); + sprintf(path, "%s%s", Config.PluginsDir, Config.Gpu); + strcpy(info.GPUpath, path); + sprintf(path, "%s%s", Config.PluginsDir, Config.Spu); + strcpy(info.SPUpath, path); + sprintf(path, "%s%s", Config.PluginsDir, Config.Cdr); + strcpy(info.CDRpath, path); + NET_setInfo(&info); + + ret = NET_open(&gpuDisp); + if (ret < 0) { + if (ret == -2) { + // -2 is returned when something in the info + // changed and needs to be synced + char *ptr; + + PARSEPATH(Config.Bios, info.BIOSpath); + PARSEPATH(Config.Gpu, info.GPUpath); + PARSEPATH(Config.Spu, info.SPUpath); + PARSEPATH(Config.Cdr, info.CDRpath); + + strcpy(Config.Mcd1, info.MCD1path); + strcpy(Config.Mcd2, info.MCD2path); + return -2; + } else { + Config.UseNet = 0; + } + } else { + if (NET_queryPlayer() == 1) { + if (SendPcsxInfo() == -1) Config.UseNet = 0; + } else { + if (RecvPcsxInfo() == -1) Config.UseNet = 0; + } + } + NetOpened = 1; + } else if (Config.UseNet) { + NET_resume(); + } + + return 0; +} + +int OpenPlugins() { + int ret; + + while ((ret = _OpenPlugins()) == -2) { + ReleasePlugins(); + if (LoadPlugins() == -1) return -1; + } + return ret; +} + +void ClosePlugins() { + int ret; + + ret = CDR_close(); + if (ret < 0) { SysPrintf("Error Closing CDR Plugin\n"); return; } + ret = SPU_close(); + if (ret < 0) { SysPrintf("Error Closing SPU Plugin\n"); return; } + ret = PAD1_close(); + if (ret < 0) { SysPrintf("Error Closing PAD1 Plugin\n"); return; } + ret = PAD2_close(); + if (ret < 0) { SysPrintf("Error Closing PAD2 Plugin\n"); return; } + ret = GPU_close(); + if (ret < 0) { SysPrintf("Error Closing GPU Plugin\n"); return; } + + if (Config.UseNet) { + NET_pause(); + } +} + +void ResetPlugins() { + int ret; + + CDR_shutdown(); + GPU_shutdown(); + SPU_shutdown(); + PAD1_shutdown(); + PAD2_shutdown(); + if (Config.UseNet) NET_shutdown(); + + ret = CDR_init(); + if (ret < 0) { SysPrintf("CDRinit error: %d\n", ret); return; } + ret = GPU_init(); + if (ret < 0) { SysPrintf("GPUinit error: %d\n", ret); return; } + ret = SPU_init(); + if (ret < 0) { SysPrintf("SPUinit error: %d\n", ret); return; } + ret = PAD1_init(1); + if (ret < 0) { SysPrintf("PAD1init error: %d\n", ret); return; } + ret = PAD2_init(2); + if (ret < 0) { SysPrintf("PAD2init error: %d\n", ret); return; } + if (Config.UseNet) { + ret = NET_init(); + if (ret < 0) { SysPrintf("NETinit error: %d\n", ret); return; } + } + + NetOpened = 0; +} + diff --git a/Gamecube/Plugin.h b/Gamecube/Plugin.h new file mode 100644 index 0000000..7f6f548 --- /dev/null +++ b/Gamecube/Plugin.h @@ -0,0 +1,26 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2002 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// Linux Specifyc Plugin Functions + +#ifndef __PLUGIN_H__ +#define __PLUGIN_H__ + +typedef long (* NETopen)(unsigned long *); + +#endif /* __PLUGIN_H__ */ diff --git a/Gamecube/TEXT.c b/Gamecube/TEXT.c new file mode 100644 index 0000000..c029442 --- /dev/null +++ b/Gamecube/TEXT.c @@ -0,0 +1,66 @@ +/* TEXT.c - Helper functions for reformatting text + by Mike Slegeir for Mupen64-GC + */ + +#include "TEXT.h" + +char TEXT_split_lines[TEXT_MAX_SPLIT][TEXT_WIDTH]; + +int TEXT_split(char* string){ + int current_line = 0, i = 0; + while( *string != 0 ){ + if( *string == '\n'){ + TEXT_split_lines[current_line][i] = 0; + if(++current_line >= TEXT_MAX_SPLIT) return current_line; + i = 0; + } else if(i == TEXT_WIDTH-1){ + // If we run out of space for this line, throw away characters + // until we reach a new line or the end of the string + // FIXME: If we'd rather have the string continue on the next + // line, simply put this if test or'ed in the above + // conditional, and it will treat it like a newline + while( *string != '\n' && *string != 0 ) ++string; + continue; + } else TEXT_split_lines[current_line][i++] = *string; + + ++string; + } + + // Null out the last byte + TEXT_split_lines[current_line][i] = 0; + + // Return the number of lines created + // the boolean checks whether the last line + // contains any characters or not, hence + // whether or not to count it + //return current_line + 1; + return current_line + ((i == 0) ? 0 : 1); +} + +void TEXT_expand(char* string){ + // Although it'd be nice to get this in one sweep, it'd probably not be a good idea + + // First determine if every tab is expandable without overflow + int i, spaces = 0; + for(i=0; string[i] != 0; ++i) + if(string[i] == '\t') spaces += TEXT_SPACE_PER_TAB - 1; + + if( TEXT_WIDTH - i > spaces ){ // We have the space to expand + while(i >= 0){ + if(string[i] == '\t'){ // Expand this tab + int j; + for(j=0; j +#include +#include +#include +#include +#include "fileBrowser.h" +#include "imagedata/mupenIcon.h" //32x32 icon + +unsigned char *SysArea = NULL; +void card_removed_cb(s32 chn, s32 result){ CARD_Unmount(chn); } + +fileBrowser_file topLevel_CARD_SlotA = + { "\0", // file name + CARD_SLOTA, // slot + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file topLevel_CARD_SlotB = + { "\0", // file name + CARD_SLOTB, // slot + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +int mount_card(int slot) { + /* Pass company identifier and number */ + CARD_Init ("N64E", "OS"); + if(!SysArea) SysArea = memalign(32,CARD_WORKAREA); + int Slot_error = CARD_Mount (slot, SysArea, card_removed_cb); + + /* Lets try 50 times to mount it. Sometimes it takes a while */ + if (Slot_error < 0) { + int i = 0; + for(i = 0; i<50; i++) + Slot_error = CARD_Mount (slot, SysArea, card_removed_cb); + } + return Slot_error; +} + +int fileBrowser_CARD_readDir(fileBrowser_file* file, fileBrowser_file** dir){ + return 0; /* Not required, use IPL to delete/copy files */ +} + +int fileBrowser_CARD_seekFile(fileBrowser_file* file, unsigned int where, unsigned int type){ + if(type == FILE_BROWSER_SEEK_SET) file->offset = where; + else if(type == FILE_BROWSER_SEEK_CUR) file->offset += where; + else file->offset = file->size + where; + + return 0; +} + +int fileBrowser_CARD_readFile(fileBrowser_file* file, void* buffer, unsigned int length){ + card_file CardFile; + int slot = file->discoffset; + unsigned int SectorSize = 0; + CARD_GetSectorSize (slot, &SectorSize); + + if(CARD_Open(slot, (const char*)file->name, &CardFile) != CARD_ERROR_NOFILE){ + /* Allocate a temporary buffer */ + char *tbuffer = memalign(32,CardFile.len); + /* Read the file */ + if(CARD_Read(&CardFile,tbuffer, CardFile.len, 0) == 0){ + file->offset += length; + memcpy(buffer,tbuffer+0x40+sizeof(CARDIcon),length); + } + else /* card removed or read failed */ + { + if(tbuffer) + free(tbuffer); + CARD_Close(&CardFile); + return -1; + } + if(tbuffer) + free(tbuffer); + return length; /* success! */ + } + return -1; /* file doesn't exist or other error */ +} + +int fileBrowser_CARD_writeFile(fileBrowser_file* file, void* buffer, unsigned int length){ + + card_file CardFile; + card_stat CardStat; + int slot = file->discoffset; + char *tmpBuffer = NULL; + unsigned int status,SectorSize,newLength; + + newLength = length + sizeof(CARDIcon) + 0x40; + + CARD_GetSectorSize (slot, &SectorSize); + + /* Round the size up to the SectorSize if needed, else leave it */ + if(newLength % SectorSize) + newLength = (((newLength/SectorSize)*SectorSize) + SectorSize); + + status = CARD_Open(slot, (const char*)file->name, &CardFile); + /* if the open failed, then try to create it */ + if(status == CARD_ERROR_NOFILE) + status = CARD_Create(slot, (const char*)file->name, newLength, &CardFile); + + if(status == CARD_ERROR_READY) { + /* Clear out the status */ + memset(&CardStat, 0, sizeof(card_stat)); + /* update status from the new file */ + CARD_GetStatus(slot,CardFile.filenum,&CardStat); + + time_t gc_time; + gc_time = time (NULL); + CardStat.icon_fmt = 2; + CardStat.icon_speed = 1; + CardStat.comment_addr = 0; + CardStat.banner_fmt = 0; + CardStat.icon_addr = 0x40; + tmpBuffer = memalign(32,newLength); + //memset(tmpBuffer,0,newLength); + strcpy(tmpBuffer,ctime (&gc_time)); + strcpy(tmpBuffer+0x20,file->name); + memcpy(tmpBuffer+0x40,CARDIcon,sizeof(CARDIcon)); // copy icon + memcpy(tmpBuffer+0x40+sizeof(CARDIcon),buffer,length); // copy file data + //if space remaining, set to zero + unsigned int endoffset = 0x40+sizeof(CARDIcon)+length; + if(newLength > endoffset) + memset(tmpBuffer+endoffset,0,newLength-endoffset); + status = CARD_SetStatus(slot,CardFile.filenum,&CardStat); + } + + if(status == CARD_ERROR_READY) { + if(CARD_Write(&CardFile, tmpBuffer, newLength, 0) == CARD_ERROR_READY) { + file->offset += length; + CARD_Close(&CardFile); + if(tmpBuffer) + free(tmpBuffer); + return length; + } + } + if(tmpBuffer) + free(tmpBuffer); + return -1; /* failed to find or create a new file */ +} + +int fileBrowser_CARD_init(fileBrowser_file* file) { + int slot = file->discoffset; + return mount_card(slot); //mount via slot number +} + +int fileBrowser_CARD_deinit(fileBrowser_file* file) { + int slot = file->discoffset; + CARD_Unmount(slot); //unmount via slot number + if(SysArea){ + free(SysArea); SysArea = NULL; + } + return 0; +} + diff --git a/Gamecube/fileBrowser/fileBrowser-CARD.h b/Gamecube/fileBrowser/fileBrowser-CARD.h new file mode 100644 index 0000000..b272f57 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-CARD.h @@ -0,0 +1,42 @@ +/** + * WiiSX - fileBrowser-CARD.h + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * fileBrowser module for Nintendo Gamecube Memory Cards + * + * Wii64 homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef FILE_BROWSER_CARD_H +#define FILE_BROWSER_CARD_H + +#include "fileBrowser.h" + +extern fileBrowser_file topLevel_CARD_SlotA; +extern fileBrowser_file topLevel_CARD_SlotB; +#define saveDir_CARD_SlotA topLevel_CARD_SlotA +#define saveDir_CARD_SlotB topLevel_CARD_SlotB + +int fileBrowser_CARD_readDir(fileBrowser_file*, fileBrowser_file**); +int fileBrowser_CARD_readFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_CARD_writeFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_CARD_seekFile(fileBrowser_file*, unsigned int, unsigned int); +int fileBrowser_CARD_init(fileBrowser_file* file); +int fileBrowser_CARD_deinit(fileBrowser_file* file); + +#endif + diff --git a/Gamecube/fileBrowser/fileBrowser-DVD.c b/Gamecube/fileBrowser/fileBrowser-DVD.c new file mode 100644 index 0000000..51f8766 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-DVD.c @@ -0,0 +1,121 @@ +/** + * WiiSX - fileBrowser-DVD.c + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * fileBrowser module for ISO9660 DVD Discs + * + * Wii64 homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#include +#include +#include +#include +#include +#include "fileBrowser.h" +#include "../gc_dvd.h" +#ifdef HW_RVL +#include +#endif + +/* DVD Globals */ +int dvd_init = 0; +int num_entries = 0; + +fileBrowser_file topLevel_DVD = + { "\\", // file name + 0ULL, // discoffset (u64) + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +int fileBrowser_DVD_readDir(fileBrowser_file* ffile, fileBrowser_file** dir){ + + num_entries = 0; + + if(dvd_get_error() || !dvd_init) { //if some error + int ret = init_dvd(); + if(ret) { //try init + return ret; //fail + } + dvd_init = 1; + } + + // Call the corresponding DVD function + num_entries = dvd_read_directoryentries(ffile->discoffset,ffile->size); + + // If it was not successful, just return the error + if(num_entries <= 0) return FILE_BROWSER_ERROR; + + // Convert the DVD "file" data to fileBrowser_files + *dir = malloc( num_entries * sizeof(fileBrowser_file) ); + int i; + for(i=0; iname[0], &DVDToc.file[i].name[0]) == 0) { + //we found the file, fill out info for it + file->discoffset = (uint64_t)(((uint64_t)DVDToc.file[i].sector)*2048); + file->offset = 0; + file->size = DVDToc.file[i].size; + return 0; + } + } + return FILE_BROWSER_ERROR_NO_FILE; +} + +int fileBrowser_DVD_seekFile(fileBrowser_file* file, unsigned int where, unsigned int type){ + if(type == FILE_BROWSER_SEEK_SET) file->offset = where; + else if(type == FILE_BROWSER_SEEK_CUR) file->offset += where; + else file->offset = file->size + where; + return 0; +} + +int fileBrowser_DVD_readFile(fileBrowser_file* file, void* buffer, unsigned int length){ + int bytesread = read_safe(buffer,file->discoffset+file->offset,length); + if(bytesread > 0) + file->offset += bytesread; + return bytesread; +} + +int fileBrowser_DVD_init(fileBrowser_file* file){ + return 0; +} + +int fileBrowser_DVD_deinit(fileBrowser_file* file) { + return 0; +} + diff --git a/Gamecube/fileBrowser/fileBrowser-DVD.h b/Gamecube/fileBrowser/fileBrowser-DVD.h new file mode 100644 index 0000000..d45aef7 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-DVD.h @@ -0,0 +1,39 @@ +/** + * WiiSX - fileBrowser-DVD.h + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * fileBrowser module for ISO9660 DVD Discs + * + * Wii64 homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef FILE_BROWSER_DVD_H +#define FILE_BROWSER_DVD_H + +#include "fileBrowser.h" + +extern fileBrowser_file topLevel_DVD; + +int fileBrowser_DVD_readDir(fileBrowser_file*, fileBrowser_file**); +int fileBrowser_DVD_open(fileBrowser_file* file); +int fileBrowser_DVD_readFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_DVD_seekFile(fileBrowser_file*, unsigned int, unsigned int); +int fileBrowser_DVD_init(fileBrowser_file* file); +int fileBrowser_DVD_deinit(fileBrowser_file* file); + +#endif + diff --git a/Gamecube/fileBrowser/fileBrowser-SMB.c b/Gamecube/fileBrowser/fileBrowser-SMB.c new file mode 100644 index 0000000..8caa692 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-SMB.c @@ -0,0 +1,188 @@ +/** + * WiiSX - fileBrowser-SMB.c + * Copyright (C) 2010 emu_kidid + * + * fileBrowser module for Samba based shares + * + * WiiSX homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifdef HW_RVL + +#include +#include +#include +#include +#include +#include +#include "../wiiSXconfig.h" +#include "fileBrowser.h" +#include "fileBrowser-libfat.h" +#include "fileBrowser-SMB.h" + +/* SMB Globals */ +int net_initialized = 0; +int smb_initialized = 0; +// net init thread +static lwp_t initnetthread = LWP_THREAD_NULL; +static int netInitHalted = 0; +static int netInitPending = 0; + +extern char smbUserName[]; +extern char smbPassWord[]; +extern char smbShareName[]; +extern char smbIpAddr[]; + +fileBrowser_file topLevel_SMB = + { "smb:/", // file name + 0ULL, // discoffset (u64) + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +void resume_netinit_thread() { + if(initnetthread != LWP_THREAD_NULL) { + netInitHalted = 0; + LWP_ResumeThread(initnetthread); + } +} + +void pause_netinit_thread() { + if(initnetthread != LWP_THREAD_NULL) { + netInitHalted = 1; + + if(netInitPending) { + return; + } + + // until it's completed for this iteration. + while(!LWP_ThreadIsSuspended(initnetthread)) { + usleep(100); + } + } +} + + +// Init the GC/Wii net interface (wifi/bba/etc) +static void* init_network(void *args) { + + char ip[16]; + int res = 0, netsleep = 1*1000*1000; + + while(netsleep > 0) { + if(netInitHalted) { + LWP_SuspendThread(initnetthread); + } + usleep(100); + netsleep -= 100; + } + + while(1) { + + if(!net_initialized) { + netInitPending = 1; + res = if_config(ip, NULL, NULL, true, 5); + if(res >= 0) { + net_initialized = 1; + } + else { + net_initialized = 0; + } + netInitPending = 0; + } + + netsleep = 1000*1000; // 1 sec + while(netsleep > 0) { + if(netInitHalted) { + LWP_SuspendThread(initnetthread); + } + usleep(100); + netsleep -= 100; + } + } + return NULL; +} + +void init_network_thread() { + LWP_CreateThread (&initnetthread, init_network, NULL, NULL, 0, 40); +} + +// Connect to the share specified in settings.cfg +void init_samba() { + + int res = 0; + + if(smb_initialized) { + return; + } + res = smbInit(&smbUserName[0], &smbPassWord[0], &smbShareName[0], &smbIpAddr[0]); + if(res) { + smb_initialized = 1; + } + else { + smb_initialized = 0; + } +} + + +int fileBrowser_SMB_readDir(fileBrowser_file* ffile, fileBrowser_file** dir){ + + // We need at least a share name and ip addr in the settings filled out + if(!strlen(&smbShareName[0]) || !strlen(&smbIpAddr[0])) { + return SMB_SMBCFGERR; + } + + if(!net_initialized) { //Init if we have to + return SMB_NETINITERR; + } + + if(!smb_initialized) { //Connect to the share + init_samba(); + if(!smb_initialized) { + return SMB_SMBERR; //fail + } + } + + // Call the corresponding FAT function + return fileBrowser_libfat_readDir(ffile, dir); +} + +int fileBrowser_SMB_open(fileBrowser_file* file) { + return fileBrowser_libfat_open(file); +} + +int fileBrowser_SMB_seekFile(fileBrowser_file* file, unsigned int where, unsigned int type){ + return fileBrowser_libfat_seekFile(file,where,type); +} + +int fileBrowser_SMB_readFile(fileBrowser_file* file, void* buffer, unsigned int length){ + return fileBrowser_libfatROM_readFile(file,buffer,length); +} + +int fileBrowser_SMB_init(fileBrowser_file* file){ + return 0; +} + +int fileBrowser_SMB_deinit(fileBrowser_file* file) { + /*if(smb_initialized) { + smbClose("smb"); + smb_initialized = 0; + }*/ + return fileBrowser_libfatROM_deinit(file); +} + +#endif diff --git a/Gamecube/fileBrowser/fileBrowser-SMB.h b/Gamecube/fileBrowser/fileBrowser-SMB.h new file mode 100644 index 0000000..f7b5205 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-SMB.h @@ -0,0 +1,48 @@ +/** + * WiiSX - fileBrowser-SMB.h + * Copyright (C) 2010 emu_kidid + * + * fileBrowser module for Samba based shares + * + * WiiSX homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef FILE_BROWSER_SMB_H +#define FILE_BROWSER_SMB_H + +#include "fileBrowser.h" + +// error codes +#define SMB_NETINITERR -110 +#define SMB_SMBCFGERR -111 +#define SMB_SMBERR -112 + +extern fileBrowser_file topLevel_SMB; + +int fileBrowser_SMB_readDir(fileBrowser_file*, fileBrowser_file**); +int fileBrowser_SMB_open(fileBrowser_file* file); +int fileBrowser_SMB_readFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_SMB_seekFile(fileBrowser_file*, unsigned int, unsigned int); +int fileBrowser_SMB_init(fileBrowser_file* file); +int fileBrowser_SMB_deinit(fileBrowser_file* file); + +void init_network_thread(); +void pause_netinit_thread(); +void resume_netinit_thread(); + +#endif + diff --git a/Gamecube/fileBrowser/fileBrowser-libfat.c b/Gamecube/fileBrowser/fileBrowser-libfat.c new file mode 100644 index 0000000..dc432e1 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-libfat.c @@ -0,0 +1,409 @@ +/** + * WiiSX - fileBrowser-libfat.c + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * fileBrowser for any devices using libfat + * + * Wii64 homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#include +#include +#include +#include +#include +#include +#include "fileBrowser.h" +#include + +extern BOOL hasLoadedROM; +extern int stop; + +#ifdef HW_RVL +#define DEVICE_REMOVAL_THREAD +#endif + +#ifdef HW_RVL +#include +#include +const DISC_INTERFACE* frontsd = &__io_wiisd; +const DISC_INTERFACE* usb = &__io_usbstorage; +#endif +const DISC_INTERFACE* carda = &__io_gcsda; +const DISC_INTERFACE* cardb = &__io_gcsdb; + +// Threaded insertion/removal detection +#define THREAD_SLEEP 100 +#define FRONTSD 1 +#define CARD_A 2 +#define CARD_B 3 +static lwp_t removalThread = LWP_THREAD_NULL; +static int rThreadRun = 0; +static int rThreadCreated = 0; +static char sdMounted = 0; +static char sdNeedsUnmount = 0; +static char usbMounted = 0; +static char usbNeedsUnmount = 0; + +fileBrowser_file topLevel_libfat_Default = + { "sd:/wiisxrx/isos", // file name + 0, // sector + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file topLevel_libfat_USB = + { "usb:/wiisxrx/isos", // file name + 0, // sector + 0, // offset + 0, // size + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file saveDir_libfat_Default = + { "sd:/wiisxrx/saves", + 0, + 0, + 0, + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file saveDir_libfat_USB = + { "usb:/wiisxrx/saves", + 0, + 0, + 0, + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file biosDir_libfat_Default = + { "sd:/wiisxrx/bios", + 0, + 0, + 0, + FILE_BROWSER_ATTR_DIR + }; + +fileBrowser_file biosDir_libfat_USB = + { "usb:/wiisxrx/bios", + 0, + 0, + 0, + FILE_BROWSER_ATTR_DIR + }; + +void continueRemovalThread() +{ +#ifdef DEVICE_REMOVAL_THREAD + if(rThreadRun) + return; + rThreadRun = 1; + LWP_ResumeThread(removalThread); +#endif +} + +void pauseRemovalThread() +{ +#ifdef DEVICE_REMOVAL_THREAD + if(!rThreadRun) + return; + rThreadRun = 0; + + // wait for thread to finish + while(!LWP_ThreadIsSuspended(removalThread)) usleep(THREAD_SLEEP); +#endif +} + +static int devsleep = 1*1000*1000; + +static void *removalCallback (void *arg) +{ + while(devsleep > 0) + { + if(!rThreadRun) + LWP_SuspendThread(removalThread); + usleep(THREAD_SLEEP); + devsleep -= THREAD_SLEEP; + } + + while (1) + { + switch(sdMounted) //some kind of SD is mounted + { +#ifdef HW_RVL + case FRONTSD: //check which one, if removed, set as unmounted + if(!frontsd->isInserted()) { + sdNeedsUnmount=sdMounted; + sdMounted=0; + } + break; +#endif +/* //Polling EXI is bad with locks, so lets not do it. + case CARD_A: //check which one, if removed, set as unmounted + if(!carda->isInserted()) { + sdNeedsUnmount=sdMounted; + sdMounted=0; + } + break; + case CARD_B: //check which one, if removed, set as unmounted + if(!cardb->isInserted()) { + sdNeedsUnmount=sdMounted; + sdMounted=0; + } + break; +*/ + } +#ifdef HW_RVL + if(usbMounted) // check if the device was removed + if(!usb->isInserted()) { + usbMounted = 0; + usbNeedsUnmount=1; + } +#endif + + devsleep = 1000*1000; // 1 sec + while(devsleep > 0) + { + if(!rThreadRun) + LWP_SuspendThread(removalThread); + usleep(THREAD_SLEEP); + devsleep -= THREAD_SLEEP; + } + } + return NULL; +} + +void InitRemovalThread() +{ +#ifdef DEVICE_REMOVAL_THREAD + LWP_CreateThread (&removalThread, removalCallback, NULL, NULL, 0, 40); + rThreadCreated = 1; +#endif +} + +int fileBrowser_libfat_readDir(fileBrowser_file* file, fileBrowser_file** dir){ + + pauseRemovalThread(); + + DIR* dp = opendir( file->name ); + if(!dp) return FILE_BROWSER_ERROR; + struct dirent * temp = NULL; + + // Set everything up to read + //char filename[MAXPATHLEN]; + int num_entries = 2, i = 0; + *dir = malloc( num_entries * sizeof(fileBrowser_file) ); + // Read each entry of the directory + while( (temp = readdir(dp)) && (temp != NULL) ){ + // Make sure we have room for this one + if(i == num_entries){ + ++num_entries; + *dir = realloc( *dir, num_entries * sizeof(fileBrowser_file) ); + } + sprintf((*dir)[i].name, "%s/%s", file->name, temp->d_name); + (*dir)[i].offset = 0; + (*dir)[i].size = 0; //TODO + (*dir)[i].attr = (temp->d_type & DT_DIR) ? + FILE_BROWSER_ATTR_DIR : 0; + ++i; + } + + continueRemovalThread(); + + return num_entries; +} + +int fileBrowser_libfat_open(fileBrowser_file* file) { + struct stat fileInfo; + if(!stat(&file->name[0], &fileInfo)){ + file->offset = 0; + file->discoffset = 0; + file->size = fileInfo.st_size; + return 0; + } + return FILE_BROWSER_ERROR_NO_FILE; +} + +int fileBrowser_libfat_seekFile(fileBrowser_file* file, unsigned int where, unsigned int type){ + if(type == FILE_BROWSER_SEEK_SET) file->offset = where; + else if(type == FILE_BROWSER_SEEK_CUR) file->offset += where; + else file->offset = file->size + where; + + return 0; +} + +int fileBrowser_libfat_readFile(fileBrowser_file* file, void* buffer, unsigned int length){ + pauseRemovalThread(); + FILE* f = fopen( file->name, "rb" ); + if(!f) return FILE_BROWSER_ERROR; + + fseek(f, file->offset, SEEK_SET); + int bytes_read = fread(buffer, 1, length, f); + if(bytes_read > 0) file->offset += bytes_read; + + fclose(f); + continueRemovalThread(); + return bytes_read; +} + +int fileBrowser_libfat_writeFile(fileBrowser_file* file, void* buffer, unsigned int length){ + pauseRemovalThread(); + FILE* f = fopen( file->name, "wb" ); + if(!f) return FILE_BROWSER_ERROR; + + fseek(f, file->offset, SEEK_SET); + int bytes_read = fwrite(buffer, 1, length, f); + if(bytes_read > 0) file->offset += bytes_read; + + fclose(f); + continueRemovalThread(); + return bytes_read; +} + +/* call fileBrowser_libfat_init as much as you like for all devices + - returns 0 on device not present/error + - returns 1 on ok +*/ +int fileBrowser_libfat_init(fileBrowser_file* f){ + + if(!rThreadCreated) InitRemovalThread(); +#ifdef HW_RVL + int res = 0; + if(f->name[0] == 's') { //SD + if(!sdMounted) { //if there's nothing currently mounted + pauseRemovalThread(); + if(sdNeedsUnmount) { + fatUnmount("sd"); + if(sdNeedsUnmount==FRONTSD) + frontsd->shutdown(); + else if(sdNeedsUnmount==CARD_A) + carda->shutdown(); + else if(sdNeedsUnmount==CARD_B) + cardb->shutdown(); + sdNeedsUnmount = 0; + } + if(fatMountSimple ("sd", frontsd)) { + sdMounted = FRONTSD; + res = 1; + } + else if(fatMountSimple ("sd", carda)) { + sdMounted = CARD_A; + res = 1; + } + else if(fatMountSimple ("sd", cardb)) { + sdMounted = CARD_B; + res = 1; + } + continueRemovalThread(); + return res; + } + else + return 1; + } + else if(f->name[0] == 'u') { + if(!usbMounted) { + pauseRemovalThread(); + if(usbNeedsUnmount) { + fatUnmount("usb"); + usb->shutdown(); + usbNeedsUnmount=0; + } + if(fatMountSimple ("usb", usb)) + usbMounted = 1; + continueRemovalThread(); + return usbMounted; + } + else + return 1; + } + return res; +#else + if(!sdMounted) { //GC has only SD + int res = 0; + + if(sdNeedsUnmount) fatUnmount("sd"); + switch(sdNeedsUnmount){ //unmount previous devices + case CARD_A: + carda->shutdown(); + break; + case CARD_B: + cardb->shutdown(); + break; + } + if(carda->startup()) { + res |= fatMountSimple ("sd", carda); + if(res) + sdMounted = CARD_A; + } + else if(cardb->startup() && !res) { + res |= fatMountSimple ("sd", cardb); + if(res) + sdMounted = CARD_B; + } + + return res; + } + return 1; //we're always ok +#endif +} + +int fileBrowser_libfat_deinit(fileBrowser_file* f){ + //we can't support multiple device re-insertion + //because there's no device removed callbacks + return 0; +} + + +/* Special for ISO,CDDA,SUB file reading only + * - Holds the same fat file handle to avoid fopen/fclose + * - Modified to keep 3 file handles open at once, + * type is determined via attr value. + */ +#define FILE_BROWSER_MAX_FILE_PTRS 3 +static FILE* fd[FILE_BROWSER_MAX_FILE_PTRS]; + +int fileBrowser_libfatROM_deinit(fileBrowser_file* f){ + pauseRemovalThread(); + + if(fd[f->attr]) { + fclose(fd[f->attr]); + } + + fd[f->attr] = NULL; + continueRemovalThread(); + return 0; +} + +int fileBrowser_libfatROM_readFile(fileBrowser_file* file, void* buffer, unsigned int length){ + if(stop) //do this only in the menu + pauseRemovalThread(); + if(!fd[file->attr]) fd[file->attr] = fopen( file->name, "rb"); + + fseek(fd[file->attr], file->offset, SEEK_SET); + int bytes_read = fread(buffer, 1, length, fd[file->attr]); + if(bytes_read > 0) { + file->offset += bytes_read; + } + + if(stop) + continueRemovalThread(); + return bytes_read; +} + diff --git a/Gamecube/fileBrowser/fileBrowser-libfat.h b/Gamecube/fileBrowser/fileBrowser-libfat.h new file mode 100644 index 0000000..81bddbf --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser-libfat.h @@ -0,0 +1,50 @@ +/** + * WiiSX - fileBrowser-libfat.h + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * fileBrowser for any devices using libfat + * + * Wii64 homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef FILE_BROWSER_LIBFAT_H +#define FILE_BROWSER_LIBFAT_H + +extern fileBrowser_file topLevel_libfat_Default; //GC SD Slots & Wii Front SD Slot +extern fileBrowser_file topLevel_libfat_USB; //Wii only, USB +extern fileBrowser_file saveDir_libfat_Default; //GC SD Slots & Wii Front SD Slot +extern fileBrowser_file saveDir_libfat_USB; //Wii only, USB +extern fileBrowser_file biosDir_libfat_Default; //GC SD Slots & Wii Front SD Slot +extern fileBrowser_file biosDir_libfat_USB; //Wii only, USB + +int fileBrowser_libfat_readDir(fileBrowser_file*, fileBrowser_file**); +int fileBrowser_libfat_open(fileBrowser_file* f); +int fileBrowser_libfat_readFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_libfat_writeFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_libfat_seekFile(fileBrowser_file*, unsigned int, unsigned int); +int fileBrowser_libfat_init(fileBrowser_file* f); +int fileBrowser_libfat_deinit(fileBrowser_file* f); + +int fileBrowser_libfatROM_readFile(fileBrowser_file*, void*, unsigned int); +int fileBrowser_libfatROM_deinit(fileBrowser_file* f); + +void pauseRemovalThread(); +void continueRemovalThread(); + +#endif diff --git a/Gamecube/fileBrowser/fileBrowser.c b/Gamecube/fileBrowser/fileBrowser.c new file mode 100644 index 0000000..8d2b878 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser.c @@ -0,0 +1,49 @@ +/** + * WiiSX - fileBrowser.c + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Actual declarations of all the fileBrowser function pointers, etc + * + * Wii64 homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "fileBrowser.h" + +#define NULL 0 + +fileBrowser_file* isoFile_topLevel; +fileBrowser_file* saveFile_dir; +fileBrowser_file* biosFile_dir; + +int (*isoFile_init)(fileBrowser_file*) = NULL; +int (*isoFile_open)(fileBrowser_file*) = NULL; +int (*isoFile_readDir)(fileBrowser_file*, fileBrowser_file**) = NULL; +int (*isoFile_readFile)(fileBrowser_file*, void*, unsigned int) = NULL; +int (*isoFile_seekFile)(fileBrowser_file*, unsigned int, unsigned int) = NULL; +int (*isoFile_deinit)(fileBrowser_file*) = NULL; + +int (*saveFile_init)(fileBrowser_file*) = NULL; +//int (*saveFile_exists)(fileBrowser_file*) = NULL; +int (*saveFile_readFile)(fileBrowser_file*, void*, unsigned int) = NULL; +int (*saveFile_writeFile)(fileBrowser_file*, void*, unsigned int) = NULL; +int (*saveFile_deinit)(fileBrowser_file*) = NULL; + +int (*biosFile_init)(fileBrowser_file*) = NULL; +int (*biosFile_open)(fileBrowser_file*) = NULL; +int (*biosFile_readFile)(fileBrowser_file*, void*, unsigned int) = NULL; +int (*biosFile_deinit)(fileBrowser_file*) = NULL; diff --git a/Gamecube/fileBrowser/fileBrowser.h b/Gamecube/fileBrowser/fileBrowser.h new file mode 100644 index 0000000..9cb7462 --- /dev/null +++ b/Gamecube/fileBrowser/fileBrowser.h @@ -0,0 +1,111 @@ +/** + * WiiSX - fileBrowser.h + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Standard protoypes for accessing files from anywhere + * + * Wii64 homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef FILE_BROWSER_H +#define FILE_BROWSER_H + +#include + +#define FILE_BROWSER_MAX_PATH_LEN 128 + +#define FILE_BROWSER_ATTR_DIR 0x10 + +#define FILE_BROWSER_ERROR -1 +#define FILE_BROWSER_ERROR_NO_FILE -2 + +#define FILE_BROWSER_SEEK_SET 1 +#define FILE_BROWSER_SEEK_CUR 2 +#define FILE_BROWSER_SEEK_END 3 + +#define FILE_BROWSER_ISO_FILE_PTR 0 +#define FILE_BROWSER_CDDA_FILE_PTR 1 +#define FILE_BROWSER_SUB_FILE_PTR 2 + +typedef struct { + char name[FILE_BROWSER_MAX_PATH_LEN]; + uint64_t discoffset; // Only necessary for DVD + unsigned int offset; // Keep track of our offset in the file + unsigned int size; + unsigned int attr; +} fileBrowser_file; + +// When you invoke a fileBrowser for ISOs, it should be invoked with this +extern fileBrowser_file* isoFile_topLevel; + +// Set this to directory for memory cards & save states +extern fileBrowser_file* saveFile_dir; + +// Set this to directory for the bios file(s) +extern fileBrowser_file* biosFile_dir; + +// This is the currently loaded CD image +extern fileBrowser_file isoFile; +// This is the currently selected bios file +extern fileBrowser_file* biosFile; + +// -- isoFile function pointers -- +/* Must be called before any using other functions */ +extern int (*isoFile_init)(fileBrowser_file*); + +/* open checks if a file exists and fills out the fileBrowser_file* */ +extern int (*isoFile_open)(fileBrowser_file*); + +/* readDir functions should return the number of directory entries + or an error of the given file pointer and fill out the file array */ +extern int (*isoFile_readDir)(fileBrowser_file*, fileBrowser_file**); + +/* readFile returns the status of the read and reads if it can + arguments: file*, buffer, length */ +extern int (*isoFile_readFile)(fileBrowser_file*, void*, unsigned int); + +/* seekFile returns the status of the seek and seeks if it can + arguments: file*, offset, seek type */ +extern int (*isoFile_seekFile)(fileBrowser_file*, unsigned int, unsigned int); + +/* Should be called after done using other functions */ +extern int (*isoFile_deinit)(fileBrowser_file*); + +// -- saveFile function pointers -- +extern int (*saveFile_init)(fileBrowser_file*); + +/* Checks whether the file exists, and fills out any inconsistent info */ +//extern int (*saveFile_exists)(fileBrowser_file*); + +extern int (*saveFile_readFile)(fileBrowser_file*, void*, unsigned int); + +extern int (*saveFile_writeFile)(fileBrowser_file*, void*, unsigned int); + +extern int (*saveFile_deinit)(fileBrowser_file*); + +// -- biosFile function pointers -- +extern int (*biosFile_init)(fileBrowser_file*); + +extern int (*biosFile_open)(fileBrowser_file*); + +extern int (*biosFile_readFile)(fileBrowser_file*, void*, unsigned int); + +extern int (*biosFile_deinit)(fileBrowser_file*); + +#endif + diff --git a/Gamecube/fileBrowser/imagedata/icon.png b/Gamecube/fileBrowser/imagedata/icon.png new file mode 100644 index 0000000..8f3274e Binary files /dev/null and b/Gamecube/fileBrowser/imagedata/icon.png differ diff --git a/Gamecube/fileBrowser/imagedata/mupenIcon.h b/Gamecube/fileBrowser/imagedata/mupenIcon.h new file mode 100644 index 0000000..817d6a7 --- /dev/null +++ b/Gamecube/fileBrowser/imagedata/mupenIcon.h @@ -0,0 +1,132 @@ +unsigned char CARDIcon[2048] = { + + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x90, 0x84, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88, 0x42, 0x80, 0x00, 0x88, 0x42, 0x90, 0x84, 0xB1, 0x8C, + 0x98, 0xC6, 0xBD, 0xEF, 0xDE, 0xD6, 0xC1, 0xCE, 0xCE, 0x73, 0xEF, 0x5A, 0xDA, 0x94, 0xDA, 0x94, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xA5, 0x29, 0x8C, 0x63, 0x84, 0x21, 0x80, 0x00, + 0xCE, 0x31, 0xD2, 0x94, 0xAD, 0x6B, 0x8C, 0x63, 0xDA, 0x94, 0xDE, 0xB5, 0xF7, 0x9C, 0xA1, 0x08, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x84, 0x21, 0x80, 0x00, 0x80, 0x00, 0x8C, 0x63, 0xB1, 0x8C, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88, 0x42, 0x90, 0x84, 0x80, 0x00, + 0x98, 0xC6, 0xB9, 0xCE, 0xB5, 0xAD, 0x98, 0xC6, 0xDA, 0xB5, 0xCA, 0x10, 0xBD, 0xAD, 0xD6, 0x94, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xA1, 0x08, 0x80, 0x00, 0x80, 0x00, 0x8C, 0x63, 0xC6, 0x10, + 0x88, 0x42, 0x80, 0x00, 0xA1, 0x08, 0xC1, 0xEF, 0xBD, 0xEF, 0x94, 0xA5, 0xB5, 0x8D, 0xA4, 0xE7, + 0xEB, 0x39, 0xF7, 0x7B, 0xFB, 0xBD, 0xFF, 0xDE, 0xD6, 0x73, 0xE2, 0xD6, 0xEF, 0x39, 0xFF, 0xDE, + 0xC1, 0xCE, 0xCE, 0x31, 0xE6, 0xF7, 0xEA, 0x74, 0xB1, 0x4A, 0xBD, 0xAD, 0xE6, 0x73, 0xDD, 0xAD, + 0xFF, 0xDE, 0xFB, 0xBD, 0xF3, 0x7B, 0xD2, 0x74, 0xFB, 0xBD, 0xEF, 0x5A, 0xE6, 0xF7, 0xDE, 0xD6, + 0xEE, 0xD6, 0xE2, 0xD6, 0xD6, 0x73, 0xCE, 0x31, 0xD9, 0x09, 0xE2, 0xD6, 0xCA, 0x10, 0xBD, 0xAD, + 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xAD, 0x4A, 0x84, 0x21, 0x80, 0x00, 0x80, 0x00, + 0xCA, 0x31, 0x90, 0x84, 0x84, 0x21, 0x8C, 0x63, 0xBD, 0xAD, 0xA9, 0x4A, 0xA5, 0x29, 0xCE, 0x52, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x88, 0x42, 0x80, 0x00, 0x80, 0x00, + 0xA1, 0x08, 0xB9, 0xCE, 0x9C, 0xE7, 0x8C, 0x63, 0xCE, 0x52, 0xBD, 0xAD, 0xD2, 0x73, 0xC2, 0x10, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x9C, 0xE7, 0x84, 0x21, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0xB1, 0x8C, 0xF3, 0x39, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xD4, 0xC6, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xD0, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xD0, 0xA5, + 0xE7, 0x18, 0xE2, 0xF7, 0xE2, 0xD6, 0xE2, 0xF7, 0xE1, 0x8C, 0xF7, 0x5A, 0xFF, 0xDE, 0xFF, 0xDE, + 0xD0, 0x21, 0xD4, 0x42, 0xF7, 0x18, 0xFB, 0xBD, 0xCC, 0x21, 0xD4, 0x21, 0xE1, 0x2A, 0xF3, 0x5A, + 0xF3, 0x7B, 0xF7, 0x9C, 0xB5, 0x6C, 0x94, 0x42, 0xFF, 0xDE, 0xFB, 0xBD, 0xF2, 0xB5, 0xAD, 0x29, + 0xF3, 0x5B, 0xE7, 0x18, 0xF2, 0x94, 0xE9, 0x6B, 0xE2, 0xD6, 0xD6, 0x73, 0xDA, 0x94, 0xE8, 0xE7, + 0x9C, 0xA5, 0xC5, 0xEF, 0xD8, 0xE7, 0xDD, 0x8D, 0x94, 0x63, 0xE2, 0x10, 0xD0, 0x21, 0xDD, 0x8D, + 0xD6, 0x73, 0xDC, 0xA6, 0xD0, 0x21, 0xDD, 0x8D, 0xE0, 0x84, 0xD8, 0x21, 0xD8, 0xC6, 0xE2, 0x73, + 0xCC, 0x63, 0xE6, 0x52, 0xBD, 0xAD, 0xB1, 0x4A, 0xCC, 0x63, 0xD8, 0xC6, 0xCE, 0x31, 0xA4, 0xE7, + 0xCC, 0x63, 0xD0, 0x21, 0xE6, 0x10, 0xDE, 0x52, 0xDD, 0xAD, 0xD0, 0x42, 0xD8, 0x63, 0xE0, 0x64, + 0xA4, 0xE7, 0xDE, 0xD6, 0xF3, 0x9C, 0xEB, 0x39, 0xD6, 0x31, 0xF3, 0x39, 0xE6, 0xF7, 0xF3, 0x7B, + 0xED, 0x8D, 0xD6, 0x94, 0xD6, 0x94, 0xE2, 0xF7, 0xE2, 0x52, 0xBD, 0xAD, 0xCA, 0x10, 0xD6, 0x73, + 0xE2, 0xF7, 0xE2, 0xD6, 0xE2, 0xF7, 0xEB, 0x39, 0xFF, 0xDE, 0xFF, 0xDE, 0xEE, 0x94, 0xD8, 0xC6, + 0xF3, 0x7B, 0xE5, 0x4A, 0xD4, 0x21, 0xD0, 0x21, 0xEE, 0xB5, 0xD8, 0x21, 0xD4, 0x21, 0xCC, 0x21, + 0xDE, 0xB5, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xD1, 0x8D, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0xD1, 0x8D, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xD1, 0x8D, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xCC, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xCC, 0xA5, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xCC, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xCC, 0xA5, + 0xCC, 0x21, 0xD0, 0x21, 0xD8, 0x21, 0xEE, 0xB5, 0xCC, 0x21, 0xD0, 0x21, 0xD4, 0x21, 0xE1, 0x08, + 0xC8, 0x21, 0xD0, 0x21, 0xD4, 0x21, 0xD8, 0x21, 0xC8, 0x21, 0xD0, 0x42, 0xE5, 0x8C, 0xD8, 0x21, + 0xD2, 0x52, 0xC5, 0xEF, 0xB9, 0x8C, 0xE6, 0x31, 0xCE, 0x52, 0xB1, 0x4B, 0xA9, 0x08, 0xCA, 0x10, + 0xE2, 0x31, 0xA0, 0xC6, 0xB5, 0x6B, 0xF1, 0x8C, 0xE4, 0xE7, 0xCE, 0x31, 0xED, 0x6B, 0xEC, 0x00, + 0xE4, 0xA5, 0xEA, 0x32, 0xDA, 0x94, 0xC1, 0xEF, 0xFA, 0x31, 0xF6, 0xD7, 0xEF, 0x39, 0xEB, 0x39, + 0xF4, 0x00, 0xF4, 0x01, 0xF9, 0x4A, 0xFF, 0x39, 0xF0, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF9, 0x8D, + 0xCA, 0x31, 0xE6, 0xB5, 0xE5, 0x6B, 0xE5, 0x4A, 0xEB, 0x39, 0xEF, 0x39, 0xFA, 0x73, 0xEE, 0x94, + 0xFE, 0x53, 0xF8, 0x84, 0xF4, 0x00, 0xF4, 0x43, 0xF8, 0x43, 0xF4, 0x00, 0xF4, 0x00, 0xF0, 0x00, + 0xB5, 0x6B, 0xB1, 0x4A, 0xBD, 0xAD, 0xD6, 0x94, 0x9C, 0xA5, 0xA0, 0xC6, 0xB1, 0x4A, 0xE6, 0x52, + 0xE2, 0x10, 0xA0, 0xC6, 0xC1, 0xCE, 0xE4, 0xE7, 0xEC, 0x22, 0xE6, 0x10, 0xE6, 0x11, 0xDC, 0x01, + 0xE5, 0x08, 0xD4, 0x21, 0xD0, 0x21, 0xCC, 0x21, 0xD8, 0x21, 0xD4, 0x21, 0xD0, 0x21, 0xCC, 0x21, + 0xD8, 0x21, 0xD4, 0x21, 0xD0, 0x21, 0xC8, 0x21, 0xD8, 0x42, 0xE1, 0x8C, 0xCC, 0x21, 0xC8, 0x21, + 0xD1, 0x8D, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC8, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC8, 0xA5, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC8, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC8, 0xA5, + 0xC8, 0x21, 0xD0, 0x63, 0xFB, 0x39, 0xD8, 0x43, 0xC4, 0x21, 0xCC, 0x63, 0xFA, 0x31, 0xE9, 0x8C, + 0xC4, 0x22, 0xCC, 0x63, 0xF9, 0xAE, 0xF5, 0xCE, 0xC4, 0x22, 0xCC, 0x63, 0xF9, 0xAE, 0xF8, 0x84, + 0xDC, 0x01, 0xE4, 0xC6, 0xE4, 0x01, 0xEC, 0x00, 0xDC, 0x01, 0xE0, 0x01, 0xE4, 0x01, 0xE8, 0x00, + 0xDC, 0x42, 0xDC, 0x01, 0xE4, 0x01, 0xE8, 0x22, 0xED, 0xCF, 0xE0, 0x42, 0xE4, 0x42, 0xEE, 0x31, + 0xF0, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF9, 0x8D, 0xF0, 0x00, 0xF4, 0x00, 0xF4, 0x00, 0xF9, 0x8D, + 0xF5, 0xAD, 0xF4, 0x00, 0xF4, 0x00, 0xF9, 0x8D, 0xEE, 0x52, 0xF0, 0x00, 0xF4, 0x00, 0xF9, 0x8D, + 0xF8, 0x43, 0xF4, 0x00, 0xF4, 0x00, 0xF0, 0x00, 0xF8, 0x43, 0xF4, 0x00, 0xF4, 0x00, 0xF0, 0x00, + 0xF8, 0x43, 0xF4, 0x00, 0xF4, 0xA5, 0xF1, 0x29, 0xF8, 0x43, 0xF4, 0x00, 0xF5, 0x08, 0xEE, 0x94, + 0xEC, 0x00, 0xE8, 0x21, 0xE0, 0x43, 0xDC, 0x01, 0xE8, 0x00, 0xE4, 0x01, 0xE0, 0x01, 0xDC, 0x22, + 0xE8, 0x00, 0xE4, 0x01, 0xDC, 0x01, 0xE9, 0x4B, 0xED, 0x4A, 0xE0, 0x01, 0xE4, 0xC7, 0xF5, 0xCE, + 0xE9, 0x8C, 0xEA, 0x11, 0xCC, 0x21, 0xC8, 0x21, 0xF5, 0xEF, 0xE9, 0xCF, 0xCC, 0x21, 0xC4, 0x21, + 0xF8, 0xA5, 0xE9, 0xCF, 0xC8, 0x21, 0xC4, 0x22, 0xF4, 0x01, 0xE9, 0xCF, 0xC8, 0x21, 0xC4, 0x22, + 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xCD, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC4, 0xA5, 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC4, 0xA6, + 0x80, 0x00, 0x80, 0x00, 0xB5, 0xAD, 0xC4, 0xA6, 0x80, 0x00, 0x80, 0x00, 0xA9, 0x4A, 0xD2, 0x31, + 0xC4, 0x22, 0xC8, 0x63, 0xF9, 0xAE, 0xF4, 0x00, 0xC0, 0x22, 0xC8, 0x63, 0xF9, 0xAE, 0xF4, 0x00, + 0xC0, 0x22, 0xC8, 0x63, 0xF9, 0xAE, 0xF4, 0x00, 0xCC, 0xE8, 0xC8, 0x63, 0xF9, 0xAE, 0xF8, 0x43, + 0xF8, 0x43, 0xFA, 0xF7, 0xF7, 0x18, 0xCA, 0x31, 0xF4, 0x00, 0xC9, 0xAD, 0xA5, 0x29, 0x90, 0x84, + 0xF4, 0x00, 0xC1, 0x6B, 0x80, 0x00, 0x80, 0x00, 0xE9, 0x8C, 0xA9, 0x29, 0x80, 0x00, 0x80, 0x00, + 0xD6, 0x10, 0xF0, 0x00, 0xF4, 0x00, 0xF9, 0x8D, 0xC9, 0x8C, 0xF0, 0x00, 0xF4, 0x00, 0xF9, 0x8D, + 0xC9, 0x8C, 0xEC, 0x00, 0xF4, 0x00, 0xF9, 0x8D, 0xC9, 0x8D, 0xEC, 0x00, 0xF0, 0x00, 0xF9, 0x8D, + 0xF8, 0x43, 0xF4, 0x00, 0xF5, 0x08, 0xB1, 0x8C, 0xF8, 0x43, 0xF4, 0x00, 0xF5, 0x08, 0xAD, 0x6B, + 0xF8, 0x43, 0xF4, 0x00, 0xF1, 0x08, 0xAD, 0x6B, 0xF8, 0x43, 0xF0, 0x00, 0xF1, 0x08, 0xAD, 0x6B, + 0xDA, 0xB5, 0xEA, 0x52, 0xF5, 0xCE, 0xF4, 0x00, 0x8C, 0x63, 0x94, 0xA5, 0xE0, 0xC6, 0xF4, 0x00, + 0x80, 0x00, 0x94, 0xA5, 0xE0, 0xC6, 0xF4, 0x00, 0x80, 0x00, 0x94, 0xA5, 0xC5, 0x6B, 0xF4, 0xE7, + 0xF4, 0x01, 0xE9, 0xEF, 0xC8, 0x21, 0xC4, 0x22, 0xF4, 0x01, 0xE5, 0xEF, 0xC8, 0x21, 0xC0, 0x22, + 0xF4, 0x01, 0xE5, 0xEF, 0xC4, 0x22, 0xC0, 0x22, 0xF8, 0x21, 0xE5, 0xEF, 0xC8, 0x63, 0xD5, 0x8C, + 0xC9, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xC9, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0xC9, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0xB9, 0xAD, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x84, 0x21, 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xB5, 0xAD, 0xDE, 0x52, 0xEE, 0xB5, 0xB9, 0x8C, 0x88, 0x42, 0x98, 0xC6, 0x98, 0xC6, 0x8C, 0x63, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x8C, 0x63, 0x84, 0x21, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xC9, 0x8D, 0xEC, 0x00, 0xF0, 0x00, 0xF9, 0x8D, 0xC9, 0x8D, 0xE8, 0x00, 0xF0, 0x00, 0xF9, 0x8D, + 0xC9, 0x8D, 0xE8, 0x00, 0xEC, 0x00, 0xF9, 0x8D, 0xC9, 0xAD, 0xE8, 0x00, 0xEC, 0x00, 0xF5, 0x8D, + 0xF4, 0x43, 0xF0, 0x00, 0xF1, 0x08, 0xAD, 0x6B, 0xF4, 0x43, 0xF0, 0x00, 0xF1, 0x08, 0xAD, 0x6B, + 0xF4, 0x43, 0xEC, 0x00, 0xF1, 0x08, 0xAD, 0x6B, 0xF4, 0x43, 0xEC, 0x00, 0xED, 0x08, 0xAD, 0x6B, + 0x80, 0x00, 0x80, 0x00, 0x8C, 0x63, 0xA1, 0x08, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x84, 0x21, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xD5, 0xCE, 0xEE, 0xD6, 0xC5, 0xEF, 0x9C, 0xE7, 0x90, 0x84, 0x9C, 0xE7, 0x8C, 0x63, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xB1, 0x8C, 0xEE, 0x10, 0xEC, 0x64, 0xF5, 0x8D, 0x90, 0x84, 0x9C, 0xE7, 0xC1, 0xCE, 0xF2, 0xD6, + 0x80, 0x00, 0x80, 0x00, 0x84, 0x21, 0x90, 0x84, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0xF0, 0x63, 0xF1, 0x29, 0xDE, 0x52, 0xA1, 0x08, 0xDA, 0x10, 0xA9, 0x4A, 0x94, 0xA5, 0x84, 0x21, + 0x8C, 0x63, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, + 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00 +}; + diff --git a/Gamecube/gc_dvd.c b/Gamecube/gc_dvd.c new file mode 100644 index 0000000..7aaa407 --- /dev/null +++ b/Gamecube/gc_dvd.c @@ -0,0 +1,499 @@ +/** + * Wii64/Cube64 - gc_dvd.c + * Copyright (C) 2007, 2008, 2009, 2010 emu_kidid + * + * DVD Reading support for GC/Wii + * + * Wii64 homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "gc_dvd.h" + +#ifdef WII +#include +#endif + +/* DVD Stuff */ +u32 dvd_hard_init = 0; +static u32 read_cmd = NORMAL; +static int last_current_dir = -1; +int is_unicode,files; +file_entries DVDToc; + +#ifdef HW_DOL +#define mfpvr() ({unsigned int rval; \ + asm volatile("mfpvr %0" : "=r" (rval)); rval;}) +#endif +#ifdef HW_RVL +volatile unsigned long* dvd = (volatile unsigned long*)0xCD806000; +#else +volatile unsigned long* dvd = (volatile unsigned long*)0xCC006000; +#endif + +int have_hw_access() { + if((*(volatile unsigned int*)HW_ARMIRQMASK)&&(*(volatile unsigned int*)HW_ARMIRQFLAG)) { + return 1; + } + return 0; +} + +int init_dvd() { +// Gamecube Mode +#ifdef HW_DOL + if(mfpvr()!=GC_CPU_VERSION) //GC mode on Wii, modchip required + { + DVD_Reset(DVD_RESETHARD); + dvd_read_id(); + if(!dvd_get_error()) { + return 0; //we're ok + } + } + else //GC, no modchip even required :) + { + DVD_Reset(DVD_RESETHARD); + DVD_Mount (); + if(!dvd_get_error()) { + return 0; //we're ok + } + } + if(dvd_get_error()>>24) { + return NO_DISC; + } + return -1; + +#endif +// Wii (Wii mode) +#ifdef HW_RVL + if(!have_hw_access()) { + return NO_HW_ACCESS; + } + if((dvd_get_error()>>24) == 1) { + return NO_DISC; + } + + if((!dvd_hard_init) || (dvd_get_error())) { + DI_Mount(); + while(DI_GetStatus() & DVD_INIT) usleep(20000); + dvd_hard_init=1; + } + + if((dvd_get_error()&0xFFFFFF)==0x053000) { + read_cmd = DVDR; + } + else { + read_cmd = NORMAL; + } + return 0; +#endif +} + +int dvd_read_id() +{ +#ifdef HW_RVL + DVD_LowRead64((void*)0x80000000, 32, 0ULL); //for easter egg disc support + return 0; +#endif + dvd[0] = 0x2E; + dvd[1] = 0; + dvd[2] = 0xA8000040; + dvd[3] = 0; + dvd[4] = 0x20; + dvd[5] = 0x80000000; + dvd[6] = 0x20; + dvd[7] = 3; // enable reading! + while (dvd[7] & 1); + if (dvd[0] & 0x4) + return 1; + return 0; +} + +unsigned int dvd_get_error(void) +{ + dvd[2] = 0xE0000000; + dvd[8] = 0; + dvd[7] = 1; // IMM + while (dvd[7] & 1); + return dvd[8]; +} + + +void dvd_motor_off() +{ + dvd[0] = 0x2E; + dvd[1] = 0; + dvd[2] = 0xe3000000; + dvd[3] = 0; + dvd[4] = 0; + dvd[5] = 0; + dvd[6] = 0; + dvd[7] = 1; // IMM + while (dvd[7] & 1); +} + +/* +DVD_LowRead64(void* dst, unsigned int len, uint64_t offset) + Read Raw, needs to be on sector boundaries + Has 8,796,093,020,160 byte limit (8 TeraBytes) + Synchronous function. + return -1 if offset is out of range +*/ +int DVD_LowRead64(void* dst, unsigned int len, uint64_t offset) +{ + if(offset>>2 > 0xFFFFFFFF) + return -1; + + if ((((int)dst) & 0xC0000000) == 0x80000000) // cached? + dvd[0] = 0x2E; + dvd[1] = 0; + dvd[2] = read_cmd; + dvd[3] = read_cmd == DVDR ? offset>>11 : offset >> 2; + dvd[4] = read_cmd == DVDR ? len>>11 : len; + dvd[5] = (unsigned long)dst; + dvd[6] = len; + dvd[7] = 3; // enable reading! + DCInvalidateRange(dst, len); + while (dvd[7] & 1); + + if (dvd[0] & 0x4) + return 1; + return 0; +} + +static char error_str[256]; +char *dvd_error_str() +{ + unsigned int err = dvd_get_error(); + if(!err) return "OK"; + + memset(&error_str[0],0,256); + switch(err>>24) { + case 0: + break; + case 1: + strcpy(&error_str[0],"Lid open"); + break; + case 2: + strcpy(&error_str[0],"No disk/Disk changed"); + break; + case 3: + strcpy(&error_str[0],"No disk"); + break; + case 4: + strcpy(&error_str[0],"Motor off"); + break; + case 5: + strcpy(&error_str[0],"Disk not initialized"); + break; + } + switch(err&0xFFFFFF) { + case 0: + break; + case 0x020400: + strcat(&error_str[0]," Motor Stopped"); + break; + case 0x020401: + strcat(&error_str[0]," Disk ID not read"); + break; + case 0x023A00: + strcat(&error_str[0]," Medium not present / Cover opened"); + break; + case 0x030200: + strcat(&error_str[0]," No Seek complete"); + break; + case 0x031100: + strcat(&error_str[0]," UnRecoverd read error"); + break; + case 0x040800: + strcat(&error_str[0]," Transfer protocol error"); + break; + case 0x052000: + strcat(&error_str[0]," Invalid command operation code"); + break; + case 0x052001: + strcat(&error_str[0]," Audio Buffer not set"); + break; + case 0x052100: + strcat(&error_str[0]," Logical block address out of range"); + break; + case 0x052400: + strcat(&error_str[0]," Invalid Field in command packet"); + break; + case 0x052401: + strcat(&error_str[0]," Invalid audio command"); + break; + case 0x052402: + strcat(&error_str[0]," Configuration out of permitted period"); + break; + case 0x053000: + strcat(&error_str[0]," DVD-R"); //? + break; + case 0x053100: + strcat(&error_str[0]," Wrong Read Type"); //? + break; + case 0x056300: + strcat(&error_str[0]," End of user area encountered on this track"); + break; + case 0x062800: + strcat(&error_str[0]," Medium may have changed"); + break; + case 0x0B5A01: + strcat(&error_str[0]," Operator medium removal request"); + break; + } + if(!error_str[0]) + sprintf(&error_str[0],"Unknown %08X",err); + return &error_str[0]; + +} + + +int read_sector(void* buffer, uint32_t sector) +{ + return DVD_LowRead64(buffer, 2048, sector * 2048); +} + +int read_safe(void* dst, uint64_t offset, int len) +{ + int ret = 0, len_read = 0; + unsigned char* sector_buffer = (unsigned char*)memalign(32,2048); + + // if required, align the start and read it + if(offset&2047) { + int alignment = offset&2047; + int amount_to_copy = len > 2048-alignment ? 2048-alignment : len-alignment; + ret |= DVD_LowRead64(sector_buffer, 2048, offset - alignment); + memcpy(dst, sector_buffer+alignment, amount_to_copy ); + + len_read += amount_to_copy; + offset += amount_to_copy; + len -= amount_to_copy; + dst += amount_to_copy; + } + + //if required, do aligned reads now until the end. + while (len) + { + ret |= DVD_LowRead64(sector_buffer, 2048, offset); + int amount_to_copy = len > 2048 ? 2048 : len; + memcpy(dst, sector_buffer, amount_to_copy); + + len_read += amount_to_copy; + offset += amount_to_copy; + len -= amount_to_copy; + dst += amount_to_copy; + } + free(sector_buffer); + if((ret) || (dvd_get_error())) { + return -1; + } + + return len_read; +} + +int read_direntry(unsigned char* direntry) +{ + int nrb = *direntry++; + ++direntry; + + int sector; + + direntry += 4; + sector = (*direntry++) << 24; + sector |= (*direntry++) << 16; + sector |= (*direntry++) << 8; + sector |= (*direntry++); + + int size; + + direntry += 4; + + size = (*direntry++) << 24; + size |= (*direntry++) << 16; + size |= (*direntry++) << 8; + size |= (*direntry++); + + direntry += 7; // skip date + + int flags = *direntry++; + ++direntry; ++direntry; direntry += 4; + + int nl = *direntry++; + + char* name = &DVDToc.file[files].name[0]; + + DVDToc.file[files].sector = sector; + DVDToc.file[files].size = size; + DVDToc.file[files].flags = flags; + + if ((nl == 1) && (direntry[0] == 1)) // ".." + { + DVDToc.file[files].name[0] = 0; + if (last_current_dir != sector) + files++; + } + else if ((nl == 1) && (direntry[0] == 0)) + { + last_current_dir = sector; + } + else + { + if (is_unicode) + { + int i; + for (i = 0; i < (nl / 2); ++i) + name[i] = direntry[i * 2 + 1]; + name[i] = 0; + nl = i; + } + else + { + memcpy(name, direntry, nl); + name[nl] = 0; + } + + if (!(flags & 2)) + { + if (name[nl - 2] == ';') + name[nl - 2] = 0; + + int i = nl; + while (i >= 0) + if (name[i] == '.') + break; + else + --i; + + ++i; + + } + else + { + name[nl++] = '/'; + name[nl] = 0; + } + + files++; + } + + return nrb; +} + + + +void read_directory(int sector, int len) +{ + int ptr = 0; + unsigned char *sector_buffer = (unsigned char*)memalign(32,2048); + read_sector(sector_buffer, sector); + + files = 0; + memset(&DVDToc,0,sizeof(file_entries)); + while (len > 0) + { + ptr += read_direntry(sector_buffer + ptr); + if (ptr >= 2048 || !sector_buffer[ptr]) + { + len -= 2048; + sector++; + read_sector(sector_buffer, sector); + ptr = 0; + } + } + free(sector_buffer); +} + +int dvd_read_directoryentries(uint64_t offset, int size) { + int sector = 16; + unsigned char *bufferDVD = (unsigned char*)memalign(32,2048); + struct pvd_s* pvd = 0; + struct pvd_s* svd = 0; + + while (sector < 32) + { + if (read_sector(bufferDVD, sector)) + { + free(bufferDVD); + return FATAL_ERROR; + } + if (!memcmp(((struct pvd_s *)bufferDVD)->id, "\2CD001\1", 8)) + { + svd = (void*)bufferDVD; + break; + } + ++sector; + } + + + if (!svd) + { + sector = 16; + while (sector < 32) + { + if (read_sector(bufferDVD, sector)) + { + free(bufferDVD); + return FATAL_ERROR; + } + + if (!memcmp(((struct pvd_s *)bufferDVD)->id, "\1CD001\1", 8)) + { + pvd = (void*)bufferDVD; + break; + } + ++sector; + } + } + + if ((!pvd) && (!svd)) + { + free(bufferDVD); + return NO_ISO9660_DISC; + } + + files = 0; + if (svd) + { + is_unicode = 1; + read_direntry(svd->root_direntry); + } + else + { + is_unicode = 0; + read_direntry(pvd->root_direntry); + } + + if((size + offset) == 0) // enter root + read_directory(DVDToc.file[0].sector, DVDToc.file[0].size); + else + read_directory(offset>>11, size); + + free(bufferDVD); + if(files>0) + return files; + return NO_FILES; +} + + + + diff --git a/Gamecube/gc_dvd.h b/Gamecube/gc_dvd.h new file mode 100644 index 0000000..a681676 --- /dev/null +++ b/Gamecube/gc_dvd.h @@ -0,0 +1,87 @@ +/** + * Wii64/Cube64 - gc_dvd.h + * Copyright (C) 2007, 2008, 2009, 2010 emu_kidid + * + * DVD Reading support for GC/Wii + * + * Wii64 homepage: http://www.emulatemii.com + * email address: emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ +#ifndef GC_DVD_H +#define GC_DVD_H + +#include +//Used in ISO9660 Parsing +#define NO_FILES -1 +#define NO_ISO9660_DISC -2 +#define FATAL_ERROR -3 +#define MAXIMUM_ENTRIES_PER_DIR 512 + +#define GC_CPU_VERSION 0x00083214 +#define NO_HW_ACCESS -1000 +#define NO_DISC -1001 +#define NORMAL 0xA8000000 +#define DVDR 0xD0000000 +#define HW_REG_BASE 0xcd800000 +#define HW_ARMIRQMASK (HW_REG_BASE + 0x03c) +#define HW_ARMIRQFLAG (HW_REG_BASE + 0x038) + +typedef struct +{ + char name[128]; + int flags; + int sector, size; +} file_entry; + +typedef struct +{ + file_entry file[MAXIMUM_ENTRIES_PER_DIR]; +} file_entries; + +extern file_entries DVDToc; + +int init_dvd(); +void dvd_motor_off(); +unsigned int dvd_get_error(void); +int dvd_read_directoryentries(uint64_t offset, int size); +void read_directory(int sector, int len); +int read_safe(void* dst, uint64_t offset, int len); +int read_direntry(unsigned char* direntry); +int read_sector(void* buffer, uint32_t sector); +int dvd_read(void* dst,unsigned int len, unsigned int offset); +int dvd_read_id(); +int DVD_LowRead64(void* dst, unsigned int len, uint64_t offset); + +struct pvd_s +{ + char id[8]; + char system_id[32]; + char volume_id[32]; + char zero[8]; + unsigned long total_sector_le, total_sect_be; + char zero2[32]; + unsigned long volume_set_size, volume_seq_nr; + unsigned short sector_size_le, sector_size_be; + unsigned long path_table_len_le, path_table_len_be; + unsigned long path_table_le, path_table_2nd_le; + unsigned long path_table_be, path_table_2nd_be; + unsigned char root_direntry[34]; + char volume_set_id[128], publisher_id[128], data_preparer_id[128], application_id[128]; + char copyright_file_id[37], abstract_file_id[37], bibliographical_file_id[37]; + // some additional dates, but we don't care for them :) +} __attribute__((packed)); + +#endif + diff --git a/Gamecube/gc_input/controller-Classic.c b/Gamecube/gc_input/controller-Classic.c new file mode 100644 index 0000000..2367b2d --- /dev/null +++ b/Gamecube/gc_input/controller-Classic.c @@ -0,0 +1,292 @@ +/** + * WiiSX - controller-Classic.c + * Copyright (C) 2007, 2008, 2009, 2010 Mike Slegeir + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Classic controller input module + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * sepp256@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifdef HW_RVL + +#include +#include +#include +#include "controller.h" +#include "../wiiSXconfig.h" + +#ifndef PI +#define PI 3.14159f +#endif + +enum { STICK_X, STICK_Y }; +static int getStickValue(joystick_t* j, int axis, int maxAbsValue){ + float angle = PI * j->ang/180.0f; + float magnitude = (j->mag > 1.0f) ? 1.0f : + (j->mag < -1.0f) ? -1.0f : j->mag; + float value; + if(axis == STICK_X) + value = magnitude * sin( angle ); + else + value = magnitude * cos( angle ); + return (int)(value * maxAbsValue); +} + +enum { + L_STICK_AS_ANALOG = 1, R_STICK_AS_ANALOG = 2, +}; + +enum { + L_STICK_L = 0x01 << 16, + L_STICK_R = 0x02 << 16, + L_STICK_U = 0x04 << 16, + L_STICK_D = 0x08 << 16, + R_STICK_L = 0x10 << 16, + R_STICK_R = 0x20 << 16, + R_STICK_U = 0x40 << 16, + R_STICK_D = 0x80 << 16, +}; + +static button_t buttons[] = { + { 0, ~0, "None" }, + { 1, CLASSIC_CTRL_BUTTON_UP, "D-Up" }, + { 2, CLASSIC_CTRL_BUTTON_LEFT, "D-Left" }, + { 3, CLASSIC_CTRL_BUTTON_RIGHT, "D-Right" }, + { 4, CLASSIC_CTRL_BUTTON_DOWN, "D-Down" }, + { 5, CLASSIC_CTRL_BUTTON_FULL_L, "L" }, + { 6, CLASSIC_CTRL_BUTTON_FULL_R, "R" }, + { 7, CLASSIC_CTRL_BUTTON_ZL, "Left Z" }, + { 8, CLASSIC_CTRL_BUTTON_ZR, "Right Z" }, + { 9, CLASSIC_CTRL_BUTTON_A, "A" }, + { 10, CLASSIC_CTRL_BUTTON_B, "B" }, + { 11, CLASSIC_CTRL_BUTTON_X, "X" }, + { 12, CLASSIC_CTRL_BUTTON_Y, "Y" }, + { 13, CLASSIC_CTRL_BUTTON_PLUS, "+" }, + { 14, CLASSIC_CTRL_BUTTON_MINUS, "-" }, + { 15, CLASSIC_CTRL_BUTTON_HOME, "Home" }, + { 16, R_STICK_U, "RS-Up" }, + { 17, R_STICK_L, "RS-Left" }, + { 18, R_STICK_R, "RS-Right" }, + { 19, R_STICK_D, "RS-Down" }, + { 20, L_STICK_U, "LS-Up" }, + { 21, L_STICK_L, "LS-Left" }, + { 22, L_STICK_R, "LS-Right" }, + { 23, L_STICK_D, "LS-Down" }, +}; + +static button_t analog_sources[] = { + { 0, L_STICK_AS_ANALOG, "Left Stick" }, + { 1, R_STICK_AS_ANALOG, "Right Stick" }, +}; + +static button_t menu_combos[] = { + { 0, CLASSIC_CTRL_BUTTON_X|CLASSIC_CTRL_BUTTON_Y, "X+Y" }, + { 1, CLASSIC_CTRL_BUTTON_ZL|CLASSIC_CTRL_BUTTON_ZR, "ZL+ZR" }, + { 2, CLASSIC_CTRL_BUTTON_HOME, "Home" }, +}; + + +static unsigned int getButtons(classic_ctrl_t* controller) +{ + unsigned int b = (unsigned)controller->btns; + s8 stickX = getStickValue(&controller->ljs, STICK_X, 7); + s8 stickY = getStickValue(&controller->ljs, STICK_Y, 7); + s8 substickX = getStickValue(&controller->rjs, STICK_X, 7); + s8 substickY = getStickValue(&controller->rjs, STICK_Y, 7); + + if(stickX < -3) b |= L_STICK_L; + if(stickX > 3) b |= L_STICK_R; + if(stickY > 3) b |= L_STICK_U; + if(stickY < -3) b |= L_STICK_D; + + if(substickX < -3) b |= R_STICK_L; + if(substickX > 3) b |= R_STICK_R; + if(substickY > 3) b |= R_STICK_U; + if(substickY < -3) b |= R_STICK_D; + + return b; +} + +static int available(int Control) { + int err; + u32 expType; + err = WPAD_Probe(Control, &expType); + if(err == WPAD_ERR_NONE && + expType == WPAD_EXP_CLASSIC){ + controller_Classic.available[Control] = 1; + return 1; + } else { + controller_Classic.available[Control] = 0; + if(err == WPAD_ERR_NONE && + expType == WPAD_EXP_NUNCHUK){ + controller_WiimoteNunchuk.available[Control] = 1; + } + else if (err == WPAD_ERR_NONE && + expType == WPAD_EXP_NONE){ + controller_Wiimote.available[Control] = 1; + } + return 0; + } +} + +static int _GetKeys(int Control, BUTTONS * Keys, controller_config_t* config) +{ + if(wpadNeedScan){ WPAD_ScanPads(); wpadNeedScan = 0; } + WPADData* wpad = WPAD_Data(Control); + BUTTONS* c = Keys; + memset(c, 0, sizeof(BUTTONS)); + //Reset buttons & sticks + c->btns.All = 0xFFFF; + c->leftStickX = c->leftStickY = c->rightStickX = c->rightStickY = 128; + + // Only use a connected classic controller + if(!available(Control)) + return 0; + + unsigned int b = getButtons(&wpad->exp.classic); + inline int isHeld(button_tp button){ + return (b & button->mask) == button->mask ? 0 : 1; + } + + c->btns.SQUARE_BUTTON = isHeld(config->SQU); + c->btns.CROSS_BUTTON = isHeld(config->CRO); + c->btns.CIRCLE_BUTTON = isHeld(config->CIR); + c->btns.TRIANGLE_BUTTON = isHeld(config->TRI); + + c->btns.R1_BUTTON = isHeld(config->R1); + c->btns.L1_BUTTON = isHeld(config->L1); + c->btns.R2_BUTTON = isHeld(config->R2); + c->btns.L2_BUTTON = isHeld(config->L2); + + c->btns.L_DPAD = isHeld(config->DL); + c->btns.R_DPAD = isHeld(config->DR); + c->btns.U_DPAD = isHeld(config->DU); + c->btns.D_DPAD = isHeld(config->DD); + + c->btns.START_BUTTON = isHeld(config->START); + c->btns.R3_BUTTON = isHeld(config->R3); + c->btns.L3_BUTTON = isHeld(config->L3); + c->btns.SELECT_BUTTON = isHeld(config->SELECT); + + //adjust values by 128 cause PSX sticks range 0-255 with a 128 center pos + s8 stickX = 0; + s8 stickY = 0; + if(config->analogL->mask == L_STICK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.classic.ljs, STICK_X, 127); + stickY = getStickValue(&wpad->exp.classic.ljs, STICK_Y, 127); + } else if(config->analogL->mask == R_STICK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.classic.rjs, STICK_X, 127); + stickY = getStickValue(&wpad->exp.classic.rjs, STICK_Y, 127); + } + c->leftStickX = (u8)(stickX+127) & 0xFF; + if(config->invertedYL) c->leftStickY = (u8)(stickY+127) & 0xFF; + else c->leftStickY = (u8)(-stickY+127) & 0xFF; + + if(config->analogR->mask == L_STICK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.classic.ljs, STICK_X, 127); + stickY = getStickValue(&wpad->exp.classic.ljs, STICK_Y, 127); + } else if(config->analogR->mask == R_STICK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.classic.rjs, STICK_X, 127); + stickY = getStickValue(&wpad->exp.classic.rjs, STICK_Y, 127); + } + c->rightStickX = (u8)(stickX+127) & 0xFF; + if(config->invertedYR) c->rightStickY = (u8)(stickY+127) & 0xFF; + else c->rightStickY = (u8)(-stickY+127) & 0xFF; + + // Return 1 if whether the exit button(s) are pressed + return isHeld(config->exit) ? 0 : 1; +} + +static void pause(int Control){ + WPAD_Rumble(Control, 0); +} + +static void resume(int Control){ } + +static void rumble(int Control, int rumble){ + WPAD_Rumble(Control, (rumble && rumbleEnabled) ? 1 : 0); +} + +static void configure(int Control, controller_config_t* config){ + // Don't know how this should be integrated +} + +static void assign(int p, int v){ + // TODO: Light up the LEDs appropriately +} + +static void refreshAvailable(void); + +controller_t controller_Classic = + { 'C', + _GetKeys, + configure, + assign, + pause, + resume, + rumble, + refreshAvailable, + {0, 0, 0, 0}, + sizeof(buttons)/sizeof(buttons[0]), + buttons, + sizeof(analog_sources)/sizeof(analog_sources[0]), + analog_sources, + sizeof(menu_combos)/sizeof(menu_combos[0]), + menu_combos, + { .SQU = &buttons[12], // Y + .CRO = &buttons[10], // B + .CIR = &buttons[9], // A + .TRI = &buttons[11], // X + .R1 = &buttons[6], // Full R + .L1 = &buttons[5], // Full L + .R2 = &buttons[8], // Right Z + .L2 = &buttons[7], // Left Z + .R3 = &buttons[0], // None + .L3 = &buttons[0], // None + .DL = &buttons[2], // D-Pad Left + .DR = &buttons[3], // D-Pad Right + .DU = &buttons[1], // D-Pad Up + .DD = &buttons[4], // D-Pad Down + .START = &buttons[13], // + + .SELECT = &buttons[14], // - + .analogL = &analog_sources[0], // Left Stick + .analogR = &analog_sources[1], // Right stick + .exit = &menu_combos[2], // Home + .invertedYL = 0, + .invertedYR = 0, + } + }; + +static void refreshAvailable(void){ + + int i; + u32 expType; + WPAD_ScanPads(); + for(i=0; i<4; ++i){ + int err = WPAD_Probe(i, &expType); + if(err == WPAD_ERR_NONE && + expType == WPAD_EXP_CLASSIC){ + controller_Classic.available[i] = 1; + WPAD_SetDataFormat(i, WPAD_DATA_EXPANSION); + } else + controller_Classic.available[i] = 0; + } +} +#endif diff --git a/Gamecube/gc_input/controller-GC.c b/Gamecube/gc_input/controller-GC.c new file mode 100644 index 0000000..a9de3c8 --- /dev/null +++ b/Gamecube/gc_input/controller-GC.c @@ -0,0 +1,238 @@ +/** + * WiiSX - controller-GC.c + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * Copyright (C) 2007, 2008, 2009 emu_kidid + * + * Gamecube controller input module + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * sepp256@gmail.com + * emukidid@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#include +#include +#include "controller.h" +#include "../wiiSXconfig.h" + +enum { + ANALOG_AS_ANALOG = 1, C_STICK_AS_ANALOG = 2, +}; + +enum { + ANALOG_L = 0x01 << 16, + ANALOG_R = 0x02 << 16, + ANALOG_U = 0x04 << 16, + ANALOG_D = 0x08 << 16, + C_STICK_L = 0x10 << 16, + C_STICK_R = 0x20 << 16, + C_STICK_U = 0x40 << 16, + C_STICK_D = 0x80 << 16, + PAD_TRIGGER_Z_UP = 0x0100 << 16, +}; + +static button_t buttons[] = { + { 0, ~0, "None" }, + { 1, PAD_BUTTON_UP, "D-Up" }, + { 2, PAD_BUTTON_LEFT, "D-Left" }, + { 3, PAD_BUTTON_RIGHT, "D-Right" }, + { 4, PAD_BUTTON_DOWN, "D-Down" }, + { 5, PAD_TRIGGER_L|PAD_TRIGGER_Z_UP, "L-Z" }, + { 6, PAD_TRIGGER_R|PAD_TRIGGER_Z_UP, "R-Z" }, + { 7, PAD_TRIGGER_L|PAD_TRIGGER_Z, "L+Z" }, + { 8, PAD_TRIGGER_R|PAD_TRIGGER_Z, "R+Z" }, + { 9, PAD_BUTTON_A, "A" }, + { 10, PAD_BUTTON_B, "B" }, + { 11, PAD_BUTTON_X, "X" }, + { 12, PAD_BUTTON_Y, "Y" }, + { 13, PAD_BUTTON_START|PAD_TRIGGER_Z_UP, "Start-Z" }, + { 14, PAD_BUTTON_START|PAD_TRIGGER_Z, "Start+Z" }, + { 15, C_STICK_U, "C-Up" }, + { 16, C_STICK_L, "C-Left" }, + { 17, C_STICK_R, "C-Right" }, + { 18, C_STICK_D, "C-Down" }, + { 19, ANALOG_U, "A-Up" }, + { 20, ANALOG_L, "A-Left" }, + { 21, ANALOG_R, "A-Right" }, + { 22, ANALOG_D, "A-Down" }, +}; + +static button_t analog_sources[] = { + { 0, ANALOG_AS_ANALOG, "Analog Stick" }, + { 1, C_STICK_AS_ANALOG, "C-Stick" }, +}; + +static button_t menu_combos[] = { + { 0, PAD_BUTTON_X|PAD_BUTTON_Y, "X+Y" }, + { 1, PAD_BUTTON_START|PAD_BUTTON_X, "Start+X" }, +}; + +u32 gc_connected; + +static unsigned int getButtons(int Control) +{ + unsigned int b = PAD_ButtonsHeld(Control); + s8 stickX = PAD_StickX(Control); + s8 stickY = PAD_StickY(Control); + s8 substickX = PAD_SubStickX(Control); + s8 substickY = PAD_SubStickY(Control); + + if(stickX < -48) b |= ANALOG_L; + if(stickX > 48) b |= ANALOG_R; + if(stickY > 48) b |= ANALOG_U; + if(stickY < -48) b |= ANALOG_D; + + if(substickX < -48) b |= C_STICK_L; + if(substickX > 48) b |= C_STICK_R; + if(substickY > 48) b |= C_STICK_U; + if(substickY < -48) b |= C_STICK_D; + + if(!(b & PAD_TRIGGER_Z)) b |= PAD_TRIGGER_Z_UP; + + return b; +} + +static int _GetKeys(int Control, BUTTONS * Keys, controller_config_t* config) +{ + if(padNeedScan){ gc_connected = PAD_ScanPads(); padNeedScan = 0; } + BUTTONS* c = Keys; + memset(c, 0, sizeof(BUTTONS)); + //Reset buttons & sticks + c->btns.All = 0xFFFF; + c->leftStickX = c->leftStickY = c->rightStickX = c->rightStickY = 128; + + controller_GC.available[Control] = (gc_connected & (1<mask) == button->mask ? 0 : 1; + } + + c->btns.SQUARE_BUTTON = isHeld(config->SQU); + c->btns.CROSS_BUTTON = isHeld(config->CRO); + c->btns.CIRCLE_BUTTON = isHeld(config->CIR); + c->btns.TRIANGLE_BUTTON = isHeld(config->TRI); + + c->btns.R1_BUTTON = isHeld(config->R1); + c->btns.L1_BUTTON = isHeld(config->L1); + c->btns.R2_BUTTON = isHeld(config->R2); + c->btns.L2_BUTTON = isHeld(config->L2); + + c->btns.L_DPAD = isHeld(config->DL); + c->btns.R_DPAD = isHeld(config->DR); + c->btns.U_DPAD = isHeld(config->DU); + c->btns.D_DPAD = isHeld(config->DD); + + c->btns.START_BUTTON = isHeld(config->START); + c->btns.R3_BUTTON = isHeld(config->R3); + c->btns.L3_BUTTON = isHeld(config->L3); + c->btns.SELECT_BUTTON = isHeld(config->SELECT); + + //adjust values by 128 cause PSX sticks range 0-255 with a 128 center pos + if(config->analogL->mask == ANALOG_AS_ANALOG){ + c->leftStickX = (u8)(PAD_StickX(Control)+127) & 0xFF; + c->leftStickY = (u8)(-PAD_StickY(Control)+127) & 0xFF; + } else if(config->analogL->mask == C_STICK_AS_ANALOG){ + c->leftStickX = (u8)(PAD_SubStickX(Control)+127) & 0xFF; + c->leftStickY = (u8)(-PAD_SubStickY(Control)+127) & 0xFF; + } + if(config->invertedYL) c->leftStickY = (u8)(127-((int)c->leftStickY-127)); + + if(config->analogR->mask == ANALOG_AS_ANALOG){ + c->rightStickX = (u8)(PAD_StickX(Control)+127) & 0xFF; + c->rightStickY = (u8)(-PAD_StickY(Control)+127) & 0xFF; + } else if(config->analogR->mask == C_STICK_AS_ANALOG){ + c->rightStickX = (u8)(PAD_SubStickX(Control)+127) & 0xFF; + c->rightStickY = (u8)(-PAD_SubStickY(Control)+127) & 0xFF; + } + if(config->invertedYR) c->rightStickY = (u8)(127-((int)c->rightStickY-127)); + + // Return 1 if whether the exit button(s) are pressed + return isHeld(config->exit) ? 0 : 1; +} + +static void pause(int Control){ + PAD_ControlMotor(Control, PAD_MOTOR_STOP); +} + +static void resume(int Control){ } + +static void rumble(int Control, int rumble){ + PAD_ControlMotor(Control, (rumble && rumbleEnabled) ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP); +} + +static void configure(int Control, controller_config_t* config){ + // Don't know how this should be integrated +} + +static void assign(int p, int v){ + // Nothing to do here +} + +static void refreshAvailable(void); + +controller_t controller_GC = + { 'G', + _GetKeys, + configure, + assign, + pause, + resume, + rumble, + refreshAvailable, + {0, 0, 0, 0}, + sizeof(buttons)/sizeof(buttons[0]), + buttons, + sizeof(analog_sources)/sizeof(analog_sources[0]), + analog_sources, + sizeof(menu_combos)/sizeof(menu_combos[0]), + menu_combos, + { .SQU = &buttons[10], // B + .CRO = &buttons[9], // A + .CIR = &buttons[11], // X + .TRI = &buttons[12], // Y + .R1 = &buttons[6], // Right Trigger - Z + .L1 = &buttons[5], // Left Trigger - Z + .R2 = &buttons[8], // Right Trigger + Z + .L2 = &buttons[7], // Left Trigger + Z + .R3 = &buttons[0], // None + .L3 = &buttons[0], // None + .DL = &buttons[2], // D-Pad Left + .DR = &buttons[3], // D-Pad Right + .DU = &buttons[1], // D-Pad Up + .DD = &buttons[4], // D-Pad Down + .START = &buttons[13], // Start - Z + .SELECT = &buttons[14], // Start + Z + .analogL = &analog_sources[0], // Analog Stick + .analogR = &analog_sources[1], // C stick + .exit = &menu_combos[1], // Start+X + .invertedYL = 0, + .invertedYR = 0, + } + }; + + +static void refreshAvailable(void){ + + if(padNeedScan){ gc_connected = PAD_ScanPads(); padNeedScan = 0; } + + int i; + for(i=0; i<4; ++i) + controller_GC.available[i] = (gc_connected & (1< +#include +#include +#include "controller.h" +#include "../wiiSXconfig.h" + +unsigned int convertToPSRange(const int raw) +{ + // Convert raw from a value between [-1, 1]. + // It's easier to convert to another analog range this way. + float converted = (float)(raw / 1024.0f); + + if (converted < -1.0f) + converted = -1.0f; + else if (converted > 1.0f) + converted = 1.0f; + + float result = 0.0f; + if (converted < 0.0f) + result = (converted * 128.0f) - 128.0f; + else + result = (converted * 127.0f) + 127.0f; + + return result; +} + +enum { + L_STICK_AS_ANALOG = 1, R_STICK_AS_ANALOG = 2, +}; + +enum { + L_STICK_L = 0x01 << 16, + L_STICK_R = 0x02 << 16, + L_STICK_U = 0x04 << 16, + L_STICK_D = 0x08 << 16, + R_STICK_L = 0x10 << 16, + R_STICK_R = 0x20 << 16, + R_STICK_U = 0x40 << 16, + R_STICK_D = 0x80 << 16, +}; + +static button_t buttons[] = { + { 0, ~0, "None" }, + { 1, WPAD_CLASSIC_BUTTON_UP, "D-Up" }, + { 2, WPAD_CLASSIC_BUTTON_LEFT, "D-Left" }, + { 3, WPAD_CLASSIC_BUTTON_RIGHT, "D-Right" }, + { 4, WPAD_CLASSIC_BUTTON_DOWN, "D-Down" }, + { 5, WPAD_CLASSIC_BUTTON_FULL_L, "L" }, + { 6, WPAD_CLASSIC_BUTTON_FULL_R, "R" }, + { 7, WPAD_CLASSIC_BUTTON_ZL, "Left Z" }, + { 8, WPAD_CLASSIC_BUTTON_ZR, "Right Z" }, + { 9, WPAD_CLASSIC_BUTTON_A, "A" }, + { 10, WPAD_CLASSIC_BUTTON_B, "B" }, + { 11, WPAD_CLASSIC_BUTTON_X, "X" }, + { 12, WPAD_CLASSIC_BUTTON_Y, "Y" }, + { 13, WPAD_CLASSIC_BUTTON_PLUS, "+" }, + { 14, WPAD_CLASSIC_BUTTON_MINUS, "-" }, + { 15, WPAD_CLASSIC_BUTTON_HOME, "Home" }, + { 16, WUPC_EXTRA_BUTTON_RSTICK, "RS-Button" }, + { 17, WUPC_EXTRA_BUTTON_LSTICK, "LS-Button" }, + { 18, R_STICK_U, "RS-Up" }, + { 19, R_STICK_L, "RS-Left" }, + { 20, R_STICK_R, "RS-Right" }, + { 21, R_STICK_D, "RS-Down" }, + { 22, L_STICK_U, "LS-Up" }, + { 23, L_STICK_L, "LS-Left" }, + { 24, L_STICK_R, "LS-Right" }, + { 25, L_STICK_D, "LS-Down" }, +}; + +static button_t analog_sources[] = { + { 0, L_STICK_AS_ANALOG, "Left Stick" }, + { 1, R_STICK_AS_ANALOG, "Right Stick" }, +}; + +static button_t menu_combos[] = { + { 0, WPAD_CLASSIC_BUTTON_X | WPAD_CLASSIC_BUTTON_Y, "X+Y" }, + { 1, WPAD_CLASSIC_BUTTON_ZL | WPAD_CLASSIC_BUTTON_ZR, "ZL+ZR" }, + { 2, WPAD_CLASSIC_BUTTON_HOME, "Home" }, +}; + +static void pause(int Control){ + WUPC_Rumble(Control, 0); +} + +static void resume(int Control){ } + +static void rumble(int Control, int rumble){ + WUPC_Rumble(Control, (rumble && rumbleEnabled) ? 1 : 0); +} + +static void configure(int Control, controller_config_t* config){ + // Don't know how this should be integrated +} + +static void assign(int p, int v){ + // TODO: Light up the LEDs appropriately +} + +static int available(int Control){ + struct WUPCData* data = WUPC_Data(Control); + + controller_WiiUPro.available[Control] = data != NULL ? 1 : 0; + + return controller_WiiUPro.available[Control]; +} + +static unsigned int getButtons(int Control){ + struct WUPCData* data = WUPC_Data(Control); + if (data != NULL){ + unsigned int btns = (unsigned int)data->button; + + // Slight hack: Add the extra buttons (L3/R3 basically) to the data. + // They do not interfere with the other Wii U controller buttons. + btns |= data->extra; + + return btns; + } + + return 0; +} + +static int _GetKeys(int Control, BUTTONS * Keys, controller_config_t* config) +{ + if (wpadNeedScan){ WUPC_UpdateButtonStats(); wpadNeedScan = 0; } + BUTTONS* c = Keys; + memset(c, 0, sizeof(BUTTONS)); + //Reset buttons & sticks + c->btns.All = 0xFFFF; + c->leftStickX = c->leftStickY = c->rightStickX = c->rightStickY = 128; + + if (available(Control) == 0) + return 0; + + unsigned int b = getButtons(Control); + inline int isHeld(button_tp button){ + return (b & button->mask) == button->mask ? 0 : 1; + } + + c->btns.SQUARE_BUTTON = isHeld(config->SQU); + c->btns.CROSS_BUTTON = isHeld(config->CRO); + c->btns.CIRCLE_BUTTON = isHeld(config->CIR); + c->btns.TRIANGLE_BUTTON = isHeld(config->TRI); + + c->btns.R1_BUTTON = isHeld(config->R1); + c->btns.L1_BUTTON = isHeld(config->L1); + c->btns.R2_BUTTON = isHeld(config->R2); + c->btns.L2_BUTTON = isHeld(config->L2); + + c->btns.L_DPAD = isHeld(config->DL); + c->btns.R_DPAD = isHeld(config->DR); + c->btns.U_DPAD = isHeld(config->DU); + c->btns.D_DPAD = isHeld(config->DD); + + c->btns.START_BUTTON = isHeld(config->START); + c->btns.R3_BUTTON = isHeld(config->R3); + c->btns.L3_BUTTON = isHeld(config->L3); + c->btns.SELECT_BUTTON = isHeld(config->SELECT); + + // When converting the stick coordinates to the PS1's range, + // we need to invert the Y axes of both sticks, since it tends to + // cause funny side-effects if we don't, like making Snake run down + // instead of up in Metal Gear Solid, for example. + c->leftStickX = convertToPSRange(WUPC_lStickX(Control)); + c->leftStickY = convertToPSRange(-WUPC_lStickY(Control)); + + c->rightStickX = convertToPSRange(WUPC_rStickX(Control)); + c->rightStickY = convertToPSRange(-WUPC_rStickY(Control)); + + // Return 1 if whether the exit button(s) are pressed + return isHeld(config->exit) ? 0 : 1; +} + +static void refreshAvailable(void); + +controller_t controller_WiiUPro = +{ + 'P', + _GetKeys, + configure, + assign, + pause, + resume, + rumble, + refreshAvailable, + { 0, 0, 0, 0 }, + sizeof(buttons) / sizeof(buttons[0]), + buttons, + sizeof(analog_sources) / sizeof(analog_sources[0]), + analog_sources, + sizeof(menu_combos) / sizeof(menu_combos[0]), + menu_combos, + { + .SQU = &buttons[12], // Y + .CRO = &buttons[10], // B + .CIR = &buttons[9], // A + .TRI = &buttons[11], // X + .R1 = &buttons[6], // Full R + .L1 = &buttons[5], // Full L + .R2 = &buttons[8], // Right Z + .L2 = &buttons[7], // Left Z + .R3 = &buttons[17], // Left Stick Button + .L3 = &buttons[16], // Right Stick Button + .DL = &buttons[2], // D-Pad Left + .DR = &buttons[3], // D-Pad Right + .DU = &buttons[1], // D-Pad Up + .DD = &buttons[4], // D-Pad Down + .START = &buttons[13], // + + .SELECT = &buttons[14], // - + .analogL = &analog_sources[0], // Left Stick + .analogR = &analog_sources[1], // Right stick + .exit = &menu_combos[2], // Home + .invertedYL = 0, + .invertedYR = 0, + } +}; + +static void refreshAvailable(void){ + int i = 0; + + struct WUPCData* data = NULL; + + for (i = 0; i < 4; ++i) + { + data = WUPC_Data(i); + + controller_WiiUPro.available[i] = data != NULL ? 1 : 0; + } +} + +#endif // HW_RVL diff --git a/Gamecube/gc_input/controller-WiimoteNunchuk.c b/Gamecube/gc_input/controller-WiimoteNunchuk.c new file mode 100644 index 0000000..102347a --- /dev/null +++ b/Gamecube/gc_input/controller-WiimoteNunchuk.c @@ -0,0 +1,385 @@ +/** + * WiiSX - controller-WiimoteNunchuk.c + * Copyright (C) 2007, 2008, 2009, 2010 Mike Slegeir + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * + * Wiimote + Nunchuk input module + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifdef HW_RVL + +#include +#include +#include +#include "controller.h" +#include "../wiiSXconfig.h" + +#ifndef PI +#define PI 3.14159f +#endif + +enum { STICK_X, STICK_Y }; +static int getStickValue(joystick_t* j, int axis, int maxAbsValue){ + float angle = PI * j->ang/180.0f; + float magnitude = (j->mag > 1.0f) ? 1.0f : + (j->mag < -1.0f) ? -1.0f : j->mag; + float value; + if(axis == STICK_X) + value = magnitude * sin( angle ); + else + value = magnitude * cos( angle ); + return (int)(value * maxAbsValue); +} + +enum { + NUNCHUK_AS_ANALOG, IR_AS_ANALOG, + TILT_AS_ANALOG, WHEEL_AS_ANALOG, + NO_ANALOG, +}; + +enum { + NUNCHUK_L = 0x10 << 16, + NUNCHUK_R = 0x20 << 16, + NUNCHUK_U = 0x40 << 16, + NUNCHUK_D = 0x80 << 16, +}; + +#define NUM_WIIMOTE_BUTTONS 12 +static button_t buttons[] = { + { 0, ~0, "None" }, + { 1, WPAD_BUTTON_UP, "D-Up" }, + { 2, WPAD_BUTTON_LEFT, "D-Left" }, + { 3, WPAD_BUTTON_RIGHT, "D-Right" }, + { 4, WPAD_BUTTON_DOWN, "D-Down" }, + { 5, WPAD_BUTTON_A, "A" }, + { 6, WPAD_BUTTON_B, "B" }, + { 7, WPAD_BUTTON_PLUS, "+" }, + { 8, WPAD_BUTTON_MINUS, "-" }, + { 9, WPAD_BUTTON_HOME, "Home" }, + { 10, WPAD_BUTTON_1, "1" }, + { 11, WPAD_BUTTON_2, "2" }, + { 12, WPAD_NUNCHUK_BUTTON_C, "C" }, + { 13, WPAD_NUNCHUK_BUTTON_Z, "Z" }, + { 14, NUNCHUK_U, "NC-Up" }, + { 15, NUNCHUK_L, "NC-Left" }, + { 16, NUNCHUK_R, "NC-Right" }, + { 17, NUNCHUK_D, "NC-Down" }, +}; + +static button_t analog_sources_wmn[] = { + { 0, NUNCHUK_AS_ANALOG, "Nunchuk" }, + { 1, IR_AS_ANALOG, "IR" }, +}; + +static button_t analog_sources_wm[] = { + { 0, TILT_AS_ANALOG, "Tilt" }, + { 1, WHEEL_AS_ANALOG, "Wheel" }, + { 2, IR_AS_ANALOG, "IR" }, + { 3, NO_ANALOG, "None" }, +}; + +static button_t menu_combos[] = { + { 0, WPAD_BUTTON_1|WPAD_BUTTON_2, "1+2" }, + { 1, WPAD_BUTTON_PLUS|WPAD_BUTTON_MINUS, "+&-" }, +}; + +static int _GetKeys(int Control, BUTTONS * Keys, controller_config_t* config, + int (*available)(int), + unsigned int (*getButtons)(WPADData*)) +{ + if(wpadNeedScan){ WPAD_ScanPads(); wpadNeedScan = 0; } + WPADData* wpad = WPAD_Data(Control); + BUTTONS* c = Keys; + memset(c, 0, sizeof(BUTTONS)); + //Reset buttons & sticks + c->btns.All = 0xFFFF; + c->leftStickX = c->leftStickY = c->rightStickX = c->rightStickY = 128; + + // Only use a connected nunchuck controller + if(!available(Control)) + return 0; + + unsigned int b = getButtons(wpad); + inline int isHeld(button_tp button){ + return (b & button->mask) == button->mask ? 0 : 1; + } + + c->btns.SQUARE_BUTTON = isHeld(config->SQU); + c->btns.CROSS_BUTTON = isHeld(config->CRO); + c->btns.CIRCLE_BUTTON = isHeld(config->CIR); + c->btns.TRIANGLE_BUTTON = isHeld(config->TRI); + + c->btns.R1_BUTTON = isHeld(config->R1); + c->btns.L1_BUTTON = isHeld(config->L1); + c->btns.R2_BUTTON = isHeld(config->R2); + c->btns.L2_BUTTON = isHeld(config->L2); + + c->btns.L_DPAD = isHeld(config->DL); + c->btns.R_DPAD = isHeld(config->DR); + c->btns.U_DPAD = isHeld(config->DU); + c->btns.D_DPAD = isHeld(config->DD); + + c->btns.START_BUTTON = isHeld(config->START); + c->btns.R3_BUTTON = isHeld(config->R3); + c->btns.L3_BUTTON = isHeld(config->L3); + c->btns.SELECT_BUTTON = isHeld(config->SELECT); + + //adjust values by 128 cause PSX sticks range 0-255 with a 128 center pos + s8 stickX = 0; + s8 stickY = 0; + if(config->analogL->mask == NUNCHUK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.nunchuk.js, STICK_X, 127); + stickY = getStickValue(&wpad->exp.nunchuk.js, STICK_Y, 127); + } else if(config->analogL->mask == IR_AS_ANALOG){ + if(wpad->ir.smooth_valid){ + stickX = ((short)(wpad->ir.sx - 512)) >> 2; + stickY = -(signed char)((wpad->ir.sy - 384) / 3); + } else { + stickX = 0; + stickY = 0; + } + } else if(config->analogL->mask == TILT_AS_ANALOG){ + stickX = -wpad->orient.pitch; + stickY = wpad->orient.roll; + } else if(config->analogL->mask == WHEEL_AS_ANALOG){ + stickX = 512 - wpad->accel.y; + stickY = wpad->accel.z - 512; + } + c->leftStickX = (u8)(stickX+127) & 0xFF; + if(config->invertedYL) c->leftStickY = (u8)(stickY+127) & 0xFF; + else c->leftStickY = (u8)(-stickY+127) & 0xFF; + + stickX = 0; + stickY = 0; + if(config->analogR->mask == NUNCHUK_AS_ANALOG){ + stickX = getStickValue(&wpad->exp.nunchuk.js, STICK_X, 127); + stickY = getStickValue(&wpad->exp.nunchuk.js, STICK_Y, 127); + } else if(config->analogR->mask == IR_AS_ANALOG){ + if(wpad->ir.smooth_valid){ + stickX = ((short)(wpad->ir.sx - 512)) >> 2; + stickY = -(signed char)((wpad->ir.sy - 384) / 3); + } else { + stickX = 0; + stickY = 0; + } + } else if(config->analogR->mask == TILT_AS_ANALOG){ + stickX = -wpad->orient.pitch; + stickY = wpad->orient.roll; + } else if(config->analogR->mask == WHEEL_AS_ANALOG){ + stickX = 512 - wpad->accel.y; + stickY = wpad->accel.z - 512; + } + c->rightStickX = (u8)(stickX+127) & 0xFF; + if(config->invertedYR) c->rightStickY = (u8)(stickY+127) & 0xFF; + else c->rightStickY = (u8)(-stickY+127) & 0xFF; + + // Return 1 if whether the exit button(s) are pressed + return isHeld(config->exit) ? 0 : 1; +} + +static int checkType(int Control, int type){ + int err; + u32 expType; + err = WPAD_Probe(Control, &expType); + + if(err != WPAD_ERR_NONE) + return -1; + + switch(expType){ + case WPAD_EXP_NONE: + controller_Wiimote.available[Control] = 1; + break; + case WPAD_EXP_NUNCHUK: + controller_WiimoteNunchuk.available[Control] = 1; + break; + case WPAD_EXP_CLASSIC: + controller_Classic.available[Control] = 1; + break; + } + + return expType; +} + +static int availableWM(int Control){ + if(checkType(Control, WPAD_EXP_NONE) != WPAD_EXP_NONE){ + controller_Wiimote.available[Control] = 0; + return 0; + } else { + return 1; + } +} + +static int availableWMN(int Control){ + if(checkType(Control, WPAD_EXP_NUNCHUK) != WPAD_EXP_NUNCHUK){ + controller_WiimoteNunchuk.available[Control] = 0; + return 0; + } else { + return 1; + } +} + +static unsigned int getButtonsWM(WPADData* controller){ + return controller->btns_h; +} + +static unsigned int getButtonsWMN(WPADData* controller){ + unsigned int b = controller->btns_h; + s8 stickX = getStickValue(&controller->exp.nunchuk.js, STICK_X, 7); + s8 stickY = getStickValue(&controller->exp.nunchuk.js, STICK_Y, 7); + + if(stickX < -3) b |= NUNCHUK_L; + if(stickX > 3) b |= NUNCHUK_R; + if(stickY > 3) b |= NUNCHUK_U; + if(stickY < -3) b |= NUNCHUK_D; + + return b; +} + +static int GetKeysWM(int con, BUTTONS * keys, controller_config_t* cfg){ + return _GetKeys(con, keys, cfg, availableWM, getButtonsWM); +} + +static int GetKeysWMN(int con, BUTTONS * keys, controller_config_t* cfg){ + return _GetKeys(con, keys, cfg, availableWMN, getButtonsWMN); +} + +static void pause(int Control){ + WPAD_Rumble(Control, 0); +} + +static void resume(int Control){ } + +static void rumble(int Control, int rumble){ + WPAD_Rumble(Control, (rumble && rumbleEnabled) ? 1 : 0); +} + +static void configure(int Control, controller_config_t* config){ + static s32 analog_fmts[] = { + WPAD_DATA_EXPANSION, // Nunchuk + WPAD_DATA_IR, // IR + WPAD_DATA_ACCEL, // Tilt + WPAD_DATA_ACCEL, // Wheel + WPAD_DATA_BUTTONS, // None + }; + WPAD_SetDataFormat(Control, analog_fmts[config->analogL->mask] | analog_fmts[config->analogR->mask]); +} + +static void assign(int p, int v){ + // TODO: Light up the LEDs appropriately +} + +static void refreshAvailableWM(void); +static void refreshAvailableWMN(void); + +controller_t controller_Wiimote = + { 'W', + GetKeysWM, + configure, + assign, + pause, + resume, + rumble, + refreshAvailableWM, + {0, 0, 0, 0}, + NUM_WIIMOTE_BUTTONS, + buttons, + sizeof(analog_sources_wm)/sizeof(analog_sources_wm[0]), + analog_sources_wm, + sizeof(menu_combos)/sizeof(menu_combos[0]), + menu_combos, + { .SQU = &buttons[0], // None + .CRO = &buttons[10], // 1 + .CIR = &buttons[11], // 2 + .TRI = &buttons[0], // None + .R1 = &buttons[7], // + + .L1 = &buttons[8], // - + .R2 = &buttons[0], // None + .L2 = &buttons[0], // None + .R3 = &buttons[0], // None + .L3 = &buttons[0], // None + .DL = &buttons[1], // D Up + .DR = &buttons[4], // D Down + .DU = &buttons[3], // D Right + .DD = &buttons[2], // D Left + .START = &buttons[9], // Home + .SELECT = &buttons[0], // None + .analogL = &analog_sources_wm[0], // Tilt + .analogR = &analog_sources_wm[3], // None + .exit = &menu_combos[1], // +&- + .invertedYL = 0, + .invertedYR = 0, + } + }; + +controller_t controller_WiimoteNunchuk = + { 'N', + GetKeysWMN, + configure, + assign, + pause, + resume, + rumble, + refreshAvailableWMN, + {0, 0, 0, 0}, + sizeof(buttons)/sizeof(buttons[0]), + buttons, + sizeof(analog_sources_wmn)/sizeof(analog_sources_wmn[0]), + analog_sources_wmn, + sizeof(menu_combos)/sizeof(menu_combos[0]), + menu_combos, + { .SQU = &buttons[2], // D Left + .CRO = &buttons[4], // D Down + .CIR = &buttons[3], // D Right + .TRI = &buttons[1], // D Up + .R1 = &buttons[5], // A + .L1 = &buttons[13], // Z + .R2 = &buttons[6], // B + .L2 = &buttons[12], // C + .R3 = &buttons[0], // None + .L3 = &buttons[0], // None + .DL = &buttons[0], // None + .DR = &buttons[0], // None + .DU = &buttons[0], // None + .DD = &buttons[0], // None + .START = &buttons[8], // - + .SELECT = &buttons[7], // + + .analogL = &analog_sources_wmn[0], // Nunchuck + .analogR = &analog_sources_wmn[1], // IR + .exit = &menu_combos[0], // 1+2 + .invertedYL = 0, + .invertedYR = 0, + } + }; + +static void refreshAvailableWM(void){ + int i; + WPAD_ScanPads(); + for(i=0; i<4; ++i){ + availableWM(i); + } +} + +static void refreshAvailableWMN(void){ + int i; + WPAD_ScanPads(); + for(i=0; i<4; ++i){ + availableWMN(i); + } +} +#endif diff --git a/Gamecube/gc_input/controller.h b/Gamecube/gc_input/controller.h new file mode 100644 index 0000000..cd565f5 --- /dev/null +++ b/Gamecube/gc_input/controller.h @@ -0,0 +1,165 @@ +/** + * WiiSX - controller.h + * Copyright (C) 2007, 2008, 2009 Mike Slegeir + * Copyright (C) 2007, 2008, 2009 emu_kidid + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * + * Standard prototypes for accessing different controllers + * + * WiiSX homepage: http://www.emulatemii.com + * email address: tehpola@gmail.com + * emukidid@gmail.com + * sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef CONTROLLER_H +#define CONTROLLER_H + +#include + +extern char padNeedScan, wpadNeedScan; +extern u32 gc_connected; + +void control_info_init(void); +void auto_assign_controllers(void); + +typedef union { + u16 All; + struct { + unsigned SQUARE_BUTTON : 1; + unsigned CROSS_BUTTON : 1; + unsigned CIRCLE_BUTTON : 1; + unsigned TRIANGLE_BUTTON : 1; + unsigned R1_BUTTON : 1; + unsigned L1_BUTTON : 1; + unsigned R2_BUTTON : 1; + unsigned L2_BUTTON : 1; + unsigned L_DPAD : 1; + unsigned D_DPAD : 1; + unsigned R_DPAD : 1; + unsigned U_DPAD : 1; + unsigned START_BUTTON : 1; + unsigned L3_BUTTON : 1; + unsigned R3_BUTTON : 1; + unsigned SELECT_BUTTON : 1; + }; +} _BUTTONS; + +typedef struct { + _BUTTONS btns; + u8 leftStickX; + u8 leftStickY; + u8 rightStickX; + u8 rightStickY; +} BUTTONS; + + +typedef struct { + int index; + unsigned int mask; + char* name; +} button_t; + +typedef button_t* button_tp; + +#define CONTROLLER_CONFIG_VERSION 1 +typedef struct { + button_tp SQU, CRO, CIR, TRI; + button_tp R1, L1, R2, L2, R3, L3; + button_tp DL, DR, DU, DD; + button_tp START, SELECT; + button_tp analogL, analogR, exit; + int invertedYL, invertedYR; +} controller_config_t; + +typedef struct { + // Identifier used in configuration file names + char identifier; + // Call GetKeys to read in BUTTONS for a controller of this type + // You should pass in controller num for this type + // Not for the player number assigned + // (eg use GC Controller 1, not player 1) + int (*GetKeys)(int, BUTTONS*, controller_config_t*); + // Set the configuration for a controller of this type + // You should pass in physical controller num as above + void (*configure)(int, controller_config_t*); + // Assign actual controller to virtual controller + void (*assign)(int,int); + // Pause/Resume a controller + void (*pause)(int); + void (*resume)(int); + // Rumble controller (0 stops rumble) + void (*rumble)(int, int); + // Fill in available[] for this type + void (*refreshAvailable)(void); + // Controllers plugged in/available of this type + char available[4]; + // Number of buttons available for this controller type + int num_buttons; + // Pointer to buttons for this controller type + button_t* buttons; + // Number of analog sources available for this controller type + int num_analog_sources; + // Pointer to analog sources for this controller type + button_t* analog_sources; + // Number of menu combos available for this controller type + int num_menu_combos; + // Pointer to analog sources for this controller type + button_t* menu_combos; + // Default controller mapping + controller_config_t config_default; + // Current controller mapping + controller_config_t config[4]; + // Saved controller mappings + controller_config_t config_slot[4]; +} controller_t; + +typedef struct _virtualControllers_t { + BOOL inUse; // This virtual controller is being controlled + controller_t* control; // The type of controller being used + int number; // The physical controller number + controller_config_t* config; // This is no longer needed... +} virtualControllers_t; + +extern virtualControllers_t virtualControllers[2]; + +// List of all the defined controller_t's +#if defined(WII) && !defined(NO_BT) + +#define num_controller_t 5 +extern controller_t controller_GC; +extern controller_t controller_Classic; +extern controller_t controller_WiiUPro; +extern controller_t controller_WiimoteNunchuk; +extern controller_t controller_Wiimote; +extern controller_t* controller_ts[num_controller_t]; + +#else // WII && !NO_BT + +#define num_controller_t 1 +extern controller_t controller_GC; +extern controller_t* controller_ts[num_controller_t]; + +#endif // WII && !NO_BT + +void init_controller_ts(void); +void assign_controller(int whichVirtual, controller_t*, int whichPhysical); +void unassign_controller(int whichVirtual); + +int load_configurations(FILE*, controller_t*); +void save_configurations(FILE*, controller_t*); + +#endif diff --git a/Gamecube/libgui/Button.cpp b/Gamecube/libgui/Button.cpp new file mode 100644 index 0000000..3735858 --- /dev/null +++ b/Gamecube/libgui/Button.cpp @@ -0,0 +1,371 @@ +/** + * WiiSX - Button.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Button.h" +#include "GuiResources.h" +#include "GraphicsGX.h" +#include "IPLFont.h" +#include "Image.h" +#include "FocusManager.h" +#include + +namespace menu { + +Button::Button(int style, char** label, float x, float y, float width, float height) + : active(false), + selected(false), + normalImage(0), + focusImage(0), + selectedImage(0), + selectedFocusImage(0), + buttonText(label), + buttonStyle(style), + labelMode(LABEL_CENTER), + labelScissor(0), + StartTime(0), + x(x), + y(y), + width(width), + height(height), + fontSize(1.0), + clickedFunc(0), + returnFunc(0) +{ + //Focus color Inactive color Active color Selected color Label color + GXColor colors[5] = {{255, 100, 100, 255}, {255, 255, 255, 70}, {255, 255, 255, 130}, {255, 255, 255, 255}, {255, 255, 255, 255}}; + + setType(TYPE_BUTTON); + switch(buttonStyle) + { + case BUTTON_DEFAULT: + setNormalImage(Resources::getInstance().getImage(Resources::IMAGE_DEFAULT_BUTTON)); + setFocusImage(Resources::getInstance().getImage(Resources::IMAGE_DEFAULT_BUTTONFOCUS)); + setSelectedImage(Resources::getInstance().getImage(Resources::IMAGE_DEFAULT_BUTTONFOCUS)); + break; + case BUTTON_STYLEA_NORMAL: + setNormalImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTON)); + setFocusImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTONFOCUS)); + this->height = 56; + break; + case BUTTON_STYLEA_SELECT: + setNormalImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTONSELECTOFF)); + setFocusImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTONSELECTOFFFOCUS)); + setSelectedImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTONSELECTON)); + setSelectedFocusImage(Resources::getInstance().getImage(Resources::IMAGE_STYLEA_BUTTONSELECTONFOCUS)); + this->height = 56; + break; + } + if (buttonStyle != BUTTON_DEFAULT) + { + colors[0] = (GXColor) {255, 255, 255, 255}; + colors[1] = (GXColor) {200, 200, 200, 255}; + colors[2] = (GXColor) {255, 255, 255, 255}; + } + + setButtonColors(colors); +} + +Button::~Button() +{ +} + +void Button::setActive(bool activeBool) +{ + active = activeBool; +} + +bool Button::getActive() +{ + return active; +} + +void Button::setSelected(bool selectedBool) +{ + selected = selectedBool; +} + +void Button::setReturn(ButtonFunc newReturnFunc) +{ + returnFunc = newReturnFunc; +} + +void Button::doReturn() +{ + if (returnFunc) returnFunc(); +} + +void Button::setClicked(ButtonFunc newClickedFunc) +{ + clickedFunc = newClickedFunc; +} + +void Button::doClicked() +{ + if (clickedFunc) clickedFunc(); +} + +void Button::setText(char** strPtr) +{ + buttonText = strPtr; +} + +void Button::setFontSize(float size) +{ + fontSize = size; +} + +#include "ogc/lwp_watchdog.h" + +void Button::setLabelMode(int mode) +{ + labelMode = mode; + if(labelMode >= LABEL_SCROLL) StartTime = ticks_to_microsecs(gettick()); +} + +void Button::setLabelScissor(int scissor) +{ + labelScissor = scissor; +} + +void Button::setNormalImage(Image *image) +{ + normalImage = image; +} + +void Button::setFocusImage(Image *image) +{ + focusImage = image; +} + +void Button::setSelectedImage(Image *image) +{ + selectedImage = image; +} + +void Button::setSelectedFocusImage(Image *image) +{ + selectedFocusImage = image; +} + +#define SCROLL_PERIOD 4.0f + +void Button::drawComponent(Graphics& gfx) +{ +// printf("Button drawComponent\n"); + + gfx.setColor(inactiveColor); + + //activate relevant texture + if(active) + { + //draw normalImage with/without gray mask and with alpha test on + //printf("Button Active\n"); + gfx.setColor(activeColor); + } + if(getFocus()) + { + //draw focus indicator (extra border for button?) + //printf("Button in Focus\n"); + gfx.setColor(focusColor); + } + //draw buttonLabel? + + gfx.enableBlending(true); +// gfx.setTEV(GX_PASSCLR); + gfx.setTEV(GX_MODULATE); + +// gfx.setColor(focusColor); + gfx.setDepth(-10.0f); + gfx.newModelView(); + gfx.loadModelView(); + gfx.loadOrthographic(); + + switch (buttonStyle) + { + case BUTTON_DEFAULT: +// gfx.fillRect(x, y, width, height); + normalImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); +// gfx.drawImage(0, x, y, width, height, 0.0, 1.0, 0.0, 1.0); + + if (selected) + { + gfx.setColor(selectedColor); + if(selectedImage) selectedImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + } + break; + case BUTTON_STYLEA_NORMAL: + if (getFocus()) focusImage->activateImage(GX_TEXMAP0); + else normalImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height, 0.0, width/8.0, 0.0, 1.0); + gfx.drawImage(0, x+width/2, y, width/2, height, width/8.0, 0.0, 0.0, 1.0); + break; + case BUTTON_STYLEA_SELECT: + if (selected) + { + if (getFocus()) selectedFocusImage->activateImage(GX_TEXMAP0); + else selectedImage->activateImage(GX_TEXMAP0); + } + else + { + if (getFocus()) focusImage->activateImage(GX_TEXMAP0); + else normalImage->activateImage(GX_TEXMAP0); + } + gfx.drawImage(0, x, y, width/2, height, 0.0, width/8.0, 0.0, 1.0); + gfx.drawImage(0, x+width/2, y, width/2, height, width/8.0, 0.0, 0.0, 1.0); + break; + } + + if (buttonText) + { + //int strWidth; + int strHeight; + unsigned long CurrentTime; + float scrollWidth, time_sec, scrollOffset; + gfx.enableScissor(x + labelScissor, y, width - 2*labelScissor, height); + if(active) IplFont::getInstance().drawInit(labelColor); + else IplFont::getInstance().drawInit(inactiveColor); + switch (labelMode) + { + case LABEL_CENTER: + IplFont::getInstance().drawString((int) (x+width/2), (int) (y+height/2), *buttonText, fontSize, true); + break; + case LABEL_LEFT: + //strWidth = IplFont::getInstance().getStringWidth(*buttonText, fontSize); + strHeight = IplFont::getInstance().getStringHeight(*buttonText, fontSize); + IplFont::getInstance().drawString((int) (x+labelScissor), (int) (y+(height-strHeight)/2), *buttonText, fontSize, false); + break; + case LABEL_SCROLL: + strHeight = IplFont::getInstance().getStringHeight(*buttonText, fontSize); + scrollWidth = IplFont::getInstance().getStringWidth(*buttonText, fontSize)-width+2*labelScissor; + scrollWidth = scrollWidth < 0.0f ? 0.0 : scrollWidth; + CurrentTime = ticks_to_microsecs(gettick()); + time_sec = (float)(CurrentTime - StartTime)/1000000.0f; + if (time_sec > SCROLL_PERIOD) StartTime = ticks_to_microsecs(gettick()); + scrollOffset = fabsf(fmodf(time_sec,SCROLL_PERIOD)-SCROLL_PERIOD/2)/(SCROLL_PERIOD/2); + IplFont::getInstance().drawString((int) (x+labelScissor-(int)(scrollOffset*scrollWidth)), (int) (y+(height-strHeight)/2), *buttonText, fontSize, false); + break; + case LABEL_SCROLLONFOCUS: + if(getFocus()) + { + strHeight = IplFont::getInstance().getStringHeight(*buttonText, fontSize); + scrollWidth = IplFont::getInstance().getStringWidth(*buttonText, fontSize)-width+2*labelScissor; + scrollWidth = scrollWidth < 0.0f ? 0.0 : scrollWidth; + CurrentTime = ticks_to_microsecs(gettick()); + time_sec = (float)(CurrentTime - StartTime)/1000000.0f; + if (time_sec > SCROLL_PERIOD) StartTime = ticks_to_microsecs(gettick()); + scrollOffset = fabsf(fmodf(time_sec,SCROLL_PERIOD)-SCROLL_PERIOD/2)/(SCROLL_PERIOD/2); + IplFont::getInstance().drawString((int) (x+labelScissor-(int)(scrollOffset*scrollWidth)), (int) (y+(height-strHeight)/2), *buttonText, fontSize, false); + } + else + { + //strWidth = IplFont::getInstance().getStringWidth(*buttonText, fontSize); + strHeight = IplFont::getInstance().getStringHeight(*buttonText, fontSize); + IplFont::getInstance().drawString((int) (x+labelScissor), (int) (y+(height-strHeight)/2), *buttonText, fontSize, false); + } + break; + } + gfx.disableScissor(); + } + +} + +void Button::updateTime(float deltaTime) +{ + //Overload in Component class + //Add interpolator class & update here? +} + +Component* Button::updateFocus(int direction, int buttonsPressed) +{ + Component* newFocus = NULL; + if(!getFocus() && active) + { + setFocus(true); + newFocus = this; + } + else if (!getFocus() && !active) + { + //try to move direction, and if new component found send to focus manager and remove focus for current component + if (getNextFocus(direction)) + newFocus = (getNextFocus(direction))->updateFocus(direction, buttonsPressed); + else + newFocus = getNextFocus(direction); + } + else + { + if (getNextFocus(direction)) + newFocus = (getNextFocus(direction))->updateFocus(direction, buttonsPressed); + if (newFocus) + setFocus(false); + else + newFocus = this; + } + if (newFocus == this) + { + //finally update button behavior based on buttons pressed + if(buttonsPressed & Focus::ACTION_BACK) + doReturn(); + else if (buttonsPressed & Focus::ACTION_SELECT) + doClicked(); + } + return newFocus; +} + +void Button::setButtonColors(GXColor *colors) +{ + focusColor.r = colors[0].r; + focusColor.g = colors[0].g; + focusColor.b = colors[0].b; + focusColor.a = colors[0].a; + inactiveColor.r = colors[1].r; + inactiveColor.g = colors[1].g; + inactiveColor.b = colors[1].b; + inactiveColor.a = colors[1].a; + activeColor.r = colors[2].r; + activeColor.g = colors[2].g; + activeColor.b = colors[2].b; + activeColor.a = colors[2].a; + selectedColor.r = colors[3].r; + selectedColor.g = colors[3].g; + selectedColor.b = colors[3].b; + selectedColor.a = colors[3].a; + labelColor.r = colors[4].r; + labelColor.g = colors[4].g; + labelColor.b = colors[4].b; + labelColor.a = colors[4].a; +} + +void Button::setLabelColor(GXColor color) +{ + labelColor.r = color.r; + labelColor.g = color.g; + labelColor.b = color.b; + labelColor.a = color.a; +} + +} //namespace menu diff --git a/Gamecube/libgui/Button.h b/Gamecube/libgui/Button.h new file mode 100644 index 0000000..4ed980d --- /dev/null +++ b/Gamecube/libgui/Button.h @@ -0,0 +1,92 @@ +/** + * WiiSX - Button.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef BUTTON_H +#define BUTTON_H + +//#include "GuiTypes.h" +#include "Component.h" + +#define BTN_DEFAULT menu::Button::BUTTON_DEFAULT +#define BTN_A_NRM menu::Button::BUTTON_STYLEA_NORMAL +#define BTN_A_SEL menu::Button::BUTTON_STYLEA_SELECT + +typedef void (*ButtonFunc)( void ); + +namespace menu { + +class Button : public Component +{ +public: + Button(int style, char** label, float x, float y, float width, float height); + ~Button(); + void setActive(bool active); + bool getActive(); + void setSelected(bool selected); + void setReturn(ButtonFunc returnFn); + void doReturn(); + void setClicked(ButtonFunc clickedFn); + void doClicked(); + void setText(char** strPtr); + void setFontSize(float size); + void setLabelMode(int mode); + void setLabelScissor(int scissor); + void setNormalImage(Image *image); + void setFocusImage(Image *image); + void setSelectedImage(Image *image); + void setSelectedFocusImage(Image *image); + void updateTime(float deltaTime); + void drawComponent(Graphics& gfx); + Component* updateFocus(int direction, int buttonsPressed); + void setButtonColors(GXColor *colors); + void setLabelColor(GXColor color); + enum LabelMode + { + LABEL_CENTER=0, + LABEL_LEFT, + LABEL_SCROLL, + LABEL_SCROLLONFOCUS + }; + + enum ButtonStyle + { + BUTTON_DEFAULT=0, + BUTTON_STYLEA_NORMAL, + BUTTON_STYLEA_SELECT + }; + +private: + bool active, selected; + Image *normalImage; + Image *focusImage; + Image *selectedImage; + Image *selectedFocusImage; + char** buttonText; + int buttonStyle, labelMode, labelScissor; + unsigned long StartTime; + float x, y, width, height, fontSize; + GXColor focusColor, inactiveColor, activeColor, selectedColor, labelColor; + ButtonFunc clickedFunc, returnFunc; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/Component.cpp b/Gamecube/libgui/Component.cpp new file mode 100644 index 0000000..ec278d5 --- /dev/null +++ b/Gamecube/libgui/Component.cpp @@ -0,0 +1,140 @@ +/** + * Wii64 - Component.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Component.h" + +namespace menu { + +Component::Component() + : componentList(0), + visible(true), + enabled(false), + focus(false), + parent(0), + type(TYPE_OTHER) +{ + nextFocus[0] = nextFocus[1] = nextFocus[2] = nextFocus[3] = nextFocus[4] = NULL; +} + +Component::~Component() +{ +} + +void Component::setEnabled(bool enable) +{ +// printf("Component setEnabled\n"); + enabled = enable; +} + +bool Component::isEnabled() const +{ + return enabled; +} + +void Component::setVisible(bool visibleBool) +{ + visible = visibleBool; +} + +bool Component::isVisible() const +{ + return visible; +} + +void Component::setFocus(bool focusBool) +{ + focus = focusBool; +} + +bool Component::getFocus() +{ + return focus; +} + +void Component::setType(int typeInt) +{ + type = typeInt; +} + +int Component::getType() +{ + return type; +} + +void Component::setParent(Component* parent) +{ + this->parent = parent; +} + +Component* Component::getParent() const +{ + return parent; +} + +void Component::draw(Graphics& gfx) +{ + //push Graphics Context to Component variables + //Draw object + //maybe call paintComponent() and then paintChildren() + //pop Graphics context +// printf("Component draw\n"); + if (isVisible()) + drawComponent(gfx); +} + +void Component::drawComponent(Graphics& gfx) +{ +// printf("virtual Component drawComponent\n"); + //Overload for custom draw routine +} + +void Component::drawChildren(Graphics& gfx) const +{ + //Overload when Component class contains children +} + +void Component::updateTime(float deltaTime) +{ + //Overload in Component class + //Add interpolator class & update here? +} + +void Component::setNextFocus(int direction, Component* component) +{ + nextFocus[direction] = component; +} + +Component* Component::getNextFocus(int direction) +{ + return nextFocus[direction]; +} + +Component* Component::updateFocus(int direction, int buttonsPressed) +{ + //Overload in Component class + return NULL; +} + +/*void Component::doFocusEvent(int type, bool buttonDown) +{ + //Overload in Component class +}*/ + +} //namespace menu diff --git a/Gamecube/libgui/Component.h b/Gamecube/libgui/Component.h new file mode 100644 index 0000000..f4b00c0 --- /dev/null +++ b/Gamecube/libgui/Component.h @@ -0,0 +1,72 @@ +/** + * Wii64 - Component.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef COMPONENT_H +#define COMPONENT_H + +#include "GuiTypes.h" + +namespace menu { + +class Component +{ +public: + Component(); + virtual ~Component(); + virtual void setEnabled(bool enable); + bool isEnabled() const; + void setVisible(bool visible); + bool isVisible() const; + void setFocus(bool focus); + bool getFocus(); + void setType(int type); + int getType(); + void setParent(Component* parent); + Component* getParent() const; + void draw(Graphics& gfx); + virtual void drawComponent(Graphics& gfx); + virtual void drawChildren(Graphics& gfx) const; + virtual void updateTime(float deltaTime); + void setNextFocus(int direction, Component* component); + Component* getNextFocus(int direction); + virtual Component* updateFocus(int direction, int buttonsPressed); +// virtual void doFocusEvent(int type, bool buttonDown); + enum ComponentType + { + TYPE_OTHER, + TYPE_FRAME, + TYPE_BUTTON, + TYPE_TEXTBOX + }; + +protected: + ComponentList componentList; + +private: + bool visible, enabled, focus; + Component* parent; + Component* nextFocus[5]; + int type; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/CursorManager.cpp b/Gamecube/libgui/CursorManager.cpp new file mode 100644 index 0000000..d0fb5ac --- /dev/null +++ b/Gamecube/libgui/CursorManager.cpp @@ -0,0 +1,240 @@ +/** + * Wii64 - CursorManager.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "CursorManager.h" +#include "InputManager.h" +#include "FocusManager.h" +#include "GraphicsGX.h" +#include "Image.h" +#include "resources.h" +#include "IPLFont.h" +#include "Frame.h" + +namespace menu { + +Cursor::Cursor() + : currentFrame(0), + cursorList(0), + cursorX(0.0f), + cursorY(0.0f), + cursorRot(0.0f), + imageCenterX(12.0f), + imageCenterY(4.0f), + foundComponent(0), + hoverOverComponent(0), + pressed(false), + frameSwitch(true), + clearInput(true), + freezeAction(false), + buttonsPressed(0), + activeChan(-1) +{ + pointerImage = new menu::Image(CursorPointTexture, 40, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + grabImage = new menu::Image(CursorGrabTexture, 40, 44, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); +} + +Cursor::~Cursor() +{ + delete pointerImage; + delete grabImage; +} + +void Cursor::updateCursor() +{ + if (hoverOverComponent) hoverOverComponent->setFocus(false); + if(frameSwitch) + { + setCursorFocus(NULL); + clearInput = true; + frameSwitch = false; + } + +#ifdef HW_RVL + WPADData* wiiPad = Input::getInstance().getWpad(); + for (int i = 0; i < 4; i++) + { + //cycle through all 4 wiimotes + //take first one pointing at screen + //if (aimed at screen): set cursorX, cursorY, cursorRot, clear focusActive + if(wiiPad[i].ir.valid && wiiPad[i].err == WPAD_ERR_NONE) + { + if(activeChan != i) + { + //clear previous cursor state here + previousButtonsPressed[i] = wiiPad[i].btns_h; + activeChan = i; +// clearInput = false; + } + else + { + if(clearInput) + { + previousButtonsPressed[i] = wiiPad[i].btns_h; + } + clearInput = false; + } + if(screenMode) cursorX = wiiPad[i].ir.x*848/640 - 104; + else cursorX = wiiPad[i].ir.x; + cursorY = wiiPad[i].ir.y; + cursorRot = wiiPad[i].ir.angle; + buttonsPressed = (wiiPad[i].btns_h ^ previousButtonsPressed[i]) & wiiPad[i].btns_h; + previousButtonsPressed[i] = wiiPad[i].btns_h; + pressed = (wiiPad[i].btns_h & (WPAD_BUTTON_A | WPAD_BUTTON_B)) ? true : false; + Focus::getInstance().setFocusActive(false); + if (hoverOverComponent) + { + hoverOverComponent->setFocus(false); + hoverOverComponent = NULL; + } + std::vector::iterator iteration; + for (iteration = cursorList.begin(); iteration != cursorList.end(); ++iteration) + { + if( currentFrame == (*iteration).frame && + (cursorX > (*iteration).xRange[0]) && (cursorX < (*iteration).xRange[1]) && + (cursorY > (*iteration).yRange[0]) && (cursorY < (*iteration).yRange[1])) + { + setCursorFocus((*iteration).comp); + if (frameSwitch) break; + } + } + if (!hoverOverComponent) setCursorFocus(currentFrame); + return; + } + } +#endif + //if not: clear cursorX, cursorY, cursorRot, set focusActive + cursorX = cursorY = cursorRot = 0.0f; + setCursorFocus(NULL); + Focus::getInstance().setFocusActive(true); + activeChan = -1; +} + +void Cursor::setCursorFocus(Component* component) +{ + int buttonsDown = 0; + //int focusDirection = 0; + Component* newHoverOverComponent = NULL; + +#ifdef HW_RVL + if (buttonsPressed & WPAD_BUTTON_A) buttonsDown |= Focus::ACTION_SELECT; + if (buttonsPressed & WPAD_BUTTON_B) buttonsDown |= Focus::ACTION_BACK; +#endif + if (freezeAction) buttonsDown = 0; + if (component) newHoverOverComponent = component->updateFocus(0/*focusDirection*/,buttonsDown); + if (newHoverOverComponent) + { + if (hoverOverComponent) hoverOverComponent->setFocus(false); + hoverOverComponent = newHoverOverComponent; + } + +} + +void Cursor::drawCursor(Graphics& gfx) +{ + if(cursorX > 0.0f || cursorY > 0.0f) + { + int width, height; + gfx.enableBlending(true); + gfx.setTEV(GX_REPLACE); + + gfx.setDepth(-10.0f); + gfx.newModelView(); + gfx.rotate(cursorRot); + gfx.translate(-imageCenterX, -imageCenterY, 0.0f); + gfx.translateApply(cursorX, cursorY, 0.0f); + gfx.loadModelView(); + gfx.loadOrthographic(); + + if(pressed) + { + grabImage->activateImage(GX_TEXMAP0); + width = 40; + height = 44; + } + else + { + pointerImage->activateImage(GX_TEXMAP0); + width = 40; + height = 56; + } + gfx.drawImage(0, 0, 0, width, height, 0.0, 1.0, 0.0, 1.0); + } + +/* GXColor debugColor = (GXColor) {255, 100, 100, 255}; + IplFont::getInstance().drawInit(debugColor); + char buffer[50]; + sprintf(buffer, "IR: %.2f, %.2f, %.2f",cursorX,cursorY,cursorRot); + IplFont::getInstance().drawString((int) 320, (int) 240, buffer, 1.0, true);*/ +} + +void Cursor::addComponent(Frame* parentFrame, Component* component, float x1, float x2, float y1, float y2) +{ + CursorEntry entry; + entry.frame = parentFrame; + entry.comp = component; + entry.xRange[0] = x1; + entry.xRange[1] = x2; + entry.yRange[0] = y1; + entry.yRange[1] = y2; + cursorList.push_back(entry); +} + +void Cursor::removeComponent(Frame* parentFrame, Component* component) +{ + std::vector::iterator iter; + + for(iter = cursorList.begin(); iter != cursorList.end(); ++iter) + { + if((*iter).frame == parentFrame && (*iter).comp == component) + { + cursorList.erase(iter); + break; + } + } +} + +void Cursor::setCurrentFrame(Frame* frame) +{ + currentFrame = frame; + frameSwitch = true; +} + +Frame* Cursor::getCurrentFrame() +{ + return currentFrame; +} + +void Cursor::clearInputData() +{ + clearInput = true; +} + +void Cursor::clearCursorFocus() +{ + if (hoverOverComponent) hoverOverComponent->setFocus(false); + cursorX = cursorY = 0.0f; +} + +void Cursor::setFreezeAction(bool freeze) +{ + freezeAction = freeze; +} + +} //namespace menu diff --git a/Gamecube/libgui/CursorManager.h b/Gamecube/libgui/CursorManager.h new file mode 100644 index 0000000..b50f74d --- /dev/null +++ b/Gamecube/libgui/CursorManager.h @@ -0,0 +1,70 @@ +/** + * Wii64 - CursorManager.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef CURSORMANAGER_H +#define CURSORMANAGER_H + +#include "GuiTypes.h" + +namespace menu { + +class Cursor +{ +public: + void updateCursor(); + void drawCursor(Graphics& gfx); + void setCursorFocus(Component* component); + void addComponent(Frame* frame, Component* component, float x1, float x2, float y1, float y2); + void removeComponent(Frame* frame, Component* component); + void setCurrentFrame(Frame* frame); + Frame* getCurrentFrame(); + void clearInputData(); + void clearCursorFocus(); + void setFreezeAction(bool freezeAction); + static Cursor& getInstance() + { + static Cursor obj; + return obj; + } + +private: + Cursor(); + ~Cursor(); + + class CursorEntry + { + public: + Frame *frame; + Component *comp; + float xRange[2], yRange[2]; + }; + + Frame *currentFrame; + std::vector cursorList; + Image *pointerImage, *grabImage; + float cursorX, cursorY, cursorRot, imageCenterX, imageCenterY; + Component *foundComponent, *hoverOverComponent; + bool pressed, frameSwitch, clearInput, freezeAction; + int buttonsPressed, previousButtonsPressed[4], activeChan; +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/FocusManager.cpp b/Gamecube/libgui/FocusManager.cpp new file mode 100644 index 0000000..3f4edcb --- /dev/null +++ b/Gamecube/libgui/FocusManager.cpp @@ -0,0 +1,255 @@ +/** + * Wii64 - FocusManager.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "FocusManager.h" +#include "InputManager.h" +#include "Frame.h" +#include "IPLFont.h" + +namespace menu { + +Focus::Focus() + : focusActive(false), + pressed(false), + frameSwitch(true), + clearInput(true), + freezeAction(false), + buttonsPressed(0), + focusList(0), + primaryFocusOwner(0), + secondaryFocusOwner(0) +{ + for (int i=0; i<4; i++) { + previousButtonsWii[i] = 0; + previousButtonsGC[i] = 0; + } +} + +Focus::~Focus() +{ +} + +void Focus::updateFocus() +{ + int focusDirection = 0; + int buttonsDown = 0; +#ifdef HW_RVL + WPADData* wiiPad = Input::getInstance().getWpad(); +#endif +// PADStatus* gcPad = Input::getInstance().getPad(); + + if (!focusActive) return; + + if (frameSwitch) + { + if(primaryFocusOwner) primaryFocusOwner->setFocus(false); + if (currentFrame) primaryFocusOwner = currentFrame->getDefaultFocus(); + else primaryFocusOwner = NULL; + frameSwitch = false; + } + + if(clearInput) + { + for (int i=0; i<4; i++) + { + previousButtonsGC[i] = PAD_ButtonsHeld(i); +#ifdef HW_RVL + previousButtonsWii[i] = wiiPad[i].btns_h; + previousButtonsWiiUPro[i] = WUPC_ButtonsHeld(i); +#endif + } + clearInput = false; + } + + for (int i=0; i<4; i++) + { +#ifdef HW_RVL + u32 currentButtonsWiiUPro = WUPC_ButtonsHeld(i); +#endif + u16 currentButtonsGC = PAD_ButtonsHeld(i); + if (currentButtonsGC ^ previousButtonsGC[i]) + { + u16 currentButtonsDownGC = (currentButtonsGC ^ previousButtonsGC[i]) & currentButtonsGC; + switch (currentButtonsDownGC & 0xf) { + case PAD_BUTTON_LEFT: + focusDirection = DIRECTION_LEFT; + break; + case PAD_BUTTON_RIGHT: + focusDirection = DIRECTION_RIGHT; + break; + case PAD_BUTTON_DOWN: + focusDirection = DIRECTION_DOWN; + break; + case PAD_BUTTON_UP: + focusDirection = DIRECTION_UP; + break; + default: + focusDirection = DIRECTION_NONE; + } + if (currentButtonsDownGC & PAD_BUTTON_A) buttonsDown |= ACTION_SELECT; + if (currentButtonsDownGC & PAD_BUTTON_B) buttonsDown |= ACTION_BACK; + if (freezeAction) + { + focusDirection = DIRECTION_NONE; + buttonsDown = 0; + } + if (primaryFocusOwner) primaryFocusOwner = primaryFocusOwner->updateFocus(focusDirection,buttonsDown); + else primaryFocusOwner = currentFrame->updateFocus(focusDirection,buttonsDown); + previousButtonsGC[i] = currentButtonsGC; + break; + } +#ifdef HW_RVL + else if (wiiPad[i].btns_h ^ previousButtonsWii[i]) + { + u32 currentButtonsDownWii = (wiiPad[i].btns_h ^ previousButtonsWii[i]) & wiiPad[i].btns_h; + if (wiiPad[i].exp.type == WPAD_EXP_CLASSIC) + { + switch (currentButtonsDownWii & 0xc0030000) { + case WPAD_CLASSIC_BUTTON_LEFT: + focusDirection = DIRECTION_LEFT; + break; + case WPAD_CLASSIC_BUTTON_RIGHT: + focusDirection = DIRECTION_RIGHT; + break; + case WPAD_CLASSIC_BUTTON_DOWN: + focusDirection = DIRECTION_DOWN; + break; + case WPAD_CLASSIC_BUTTON_UP: + focusDirection = DIRECTION_UP; + break; + default: + focusDirection = DIRECTION_NONE; + } + } + else + { + switch (currentButtonsDownWii & 0xf00) { + case WPAD_BUTTON_LEFT: + focusDirection = DIRECTION_LEFT; + break; + case WPAD_BUTTON_RIGHT: + focusDirection = DIRECTION_RIGHT; + break; + case WPAD_BUTTON_DOWN: + focusDirection = DIRECTION_DOWN; + break; + case WPAD_BUTTON_UP: + focusDirection = DIRECTION_UP; + break; + default: + focusDirection = DIRECTION_NONE; + } + } + if (currentButtonsDownWii & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) buttonsDown |= ACTION_SELECT; + if (currentButtonsDownWii & (WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)) buttonsDown |= ACTION_BACK; + if (freezeAction) + { + focusDirection = DIRECTION_NONE; + buttonsDown = 0; + } + if (primaryFocusOwner) primaryFocusOwner = primaryFocusOwner->updateFocus(focusDirection,buttonsDown); + else primaryFocusOwner = currentFrame->updateFocus(focusDirection,buttonsDown); + previousButtonsWii[i] = wiiPad[i].btns_h; + break; + } + else if (currentButtonsWiiUPro ^ previousButtonsWiiUPro[i]) + { + switch (currentButtonsWiiUPro & 0xc0030000) { + case WPAD_CLASSIC_BUTTON_LEFT: + focusDirection = DIRECTION_LEFT; + break; + case WPAD_CLASSIC_BUTTON_RIGHT: + focusDirection = DIRECTION_RIGHT; + break; + case WPAD_CLASSIC_BUTTON_DOWN: + focusDirection = DIRECTION_DOWN; + break; + case WPAD_CLASSIC_BUTTON_UP: + focusDirection = DIRECTION_UP; + break; + default: + focusDirection = DIRECTION_NONE; + } + if (currentButtonsWiiUPro & WPAD_CLASSIC_BUTTON_A) buttonsDown |= ACTION_SELECT; + if (currentButtonsWiiUPro & WPAD_CLASSIC_BUTTON_B) buttonsDown |= ACTION_BACK; + if (freezeAction) + { + focusDirection = DIRECTION_NONE; + buttonsDown = 0; + } + if (primaryFocusOwner) primaryFocusOwner = primaryFocusOwner->updateFocus(focusDirection, buttonsDown); + else primaryFocusOwner = currentFrame->updateFocus(focusDirection, buttonsDown); + previousButtonsWiiUPro[i] = currentButtonsWiiUPro; + break; + } +#endif + } +} + +void Focus::addComponent(Component* component) +{ + focusList.push_back(component); +} + +void Focus::removeComponent(Component* component) +{ + ComponentList::iterator iter = std::find(focusList.begin(), focusList.end(),component); + if(iter != focusList.end()) + { + focusList.erase(iter); + } +} + +Frame* Focus::getCurrentFrame() +{ + return currentFrame; +} + +void Focus::setCurrentFrame(Frame* frame) +{ + currentFrame = frame; + frameSwitch = true; + Input::getInstance().clearInputData(); +} + +void Focus::setFocusActive(bool focusActiveBool) +{ + focusActive = focusActiveBool; + if (primaryFocusOwner) primaryFocusOwner->setFocus(focusActive); +} + +void Focus::clearInputData() +{ + clearInput = true; +} + +void Focus::clearPrimaryFocus() +{ + if(primaryFocusOwner) primaryFocusOwner->setFocus(false); + primaryFocusOwner = NULL; + frameSwitch = true; +} + +void Focus::setFreezeAction(bool freeze) +{ + freezeAction = freeze; +} + +} //namespace menu diff --git a/Gamecube/libgui/FocusManager.h b/Gamecube/libgui/FocusManager.h new file mode 100644 index 0000000..5049af0 --- /dev/null +++ b/Gamecube/libgui/FocusManager.h @@ -0,0 +1,76 @@ +/** + * Wii64 - FocusManager.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef FOCUSMANAGER_H +#define FOCUSMANAGER_H + +#include "GuiTypes.h" + +namespace menu { + +class Focus +{ +public: + void updateFocus(); + void addComponent(Component* component); + void removeComponent(Component* component); + Frame* getCurrentFrame(); + void setCurrentFrame(Frame* frame); + void setFocusActive(bool active); + void clearInputData(); + void clearPrimaryFocus(); + void setFreezeAction(bool freezeAction); + enum FocusDirection + { + DIRECTION_NONE=0, + DIRECTION_LEFT, + DIRECTION_RIGHT, + DIRECTION_DOWN, + DIRECTION_UP + }; + enum FocusAction + { + ACTION_SELECT=1, + ACTION_BACK=2 + }; + + static Focus& getInstance() + { + static Focus obj; + return obj; + } + +private: + Focus(); + ~Focus(); + bool focusActive, pressed, frameSwitch, clearInput, freezeAction; + int buttonsPressed, previousButtonsPressed; + u32 previousButtonsWii[4]; + u16 previousButtonsGC[4]; + u32 previousButtonsWiiUPro[4]; + ComponentList focusList; + Component *primaryFocusOwner, *secondaryFocusOwner; + Frame *currentFrame; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/Frame.cpp b/Gamecube/libgui/Frame.cpp new file mode 100644 index 0000000..b258253 --- /dev/null +++ b/Gamecube/libgui/Frame.cpp @@ -0,0 +1,140 @@ +/** + * WiiSX - Frame.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Frame.h" +#include "FocusManager.h" + +namespace menu { + +Frame::Frame() + : defaultFocus(0), + backFunc(0), + selectFunc(0) +{ + setVisible(false); +} + +Frame::~Frame() +{ + removeAll(); +} + +void Frame::showFrame() +{ + setVisible(true); +} + +void Frame::hideFrame() +{ + setVisible(false); +} + +void Frame::updateTime(float deltaTime) +{ + if(isVisible()) + { + updateFrame(deltaTime); + + ComponentList::const_iterator iteration; + for (iteration = componentList.begin(); iteration != componentList.end(); ++iteration) + { + (*iteration)->updateTime(deltaTime); + } + } +} + +void Frame::drawChildren(Graphics &gfx) +{ + if(isVisible()) + { +// printf("Frame drawChildren\n"); + ComponentList::const_iterator iteration; + for (iteration = componentList.begin(); iteration != componentList.end(); ++iteration) + { +// printf("Frame calling component::draw\n"); + (*iteration)->draw(gfx); + } + } +} + +void Frame::setEnabled(bool enable) +{ +// printf("Frame setEnabled\n"); + ComponentList::const_iterator iterator; + for(iterator = componentList.begin(); iterator != componentList.end(); ++iterator) + { + (*iterator)->setEnabled(enable); + } + Component::setEnabled(enable); +} + +void Frame::remove(Component* component) +{ + ComponentList::iterator iter = std::find(componentList.begin(), componentList.end(),component); + if(iter != componentList.end()) + { + (*iter)->setParent(0); + componentList.erase(iter); + } +} + +void Frame::removeAll() +{ + componentList.clear(); +} + +void Frame::add(Component* component) +{ + component->setParent(this); + componentList.push_back(component); +} + +void Frame::setDefaultFocus(Component* component) +{ + defaultFocus = component; +} + +Component* Frame::getDefaultFocus() +{ + return defaultFocus; +} + +void Frame::setBackFunc(FrameFunc backFn) +{ + backFunc = backFn; +} + +void Frame::setSelectFunc(FrameFunc selectFn) +{ + selectFunc = selectFn; +} + +Component* Frame::updateFocus(int direction, int buttonsPressed) +{ + //This function only called from CursorManager when wii-mote is not pointing to a button. + Component* newFocus = NULL; + + if(buttonsPressed & Focus::ACTION_BACK && backFunc) backFunc(); + else if (buttonsPressed & Focus::ACTION_SELECT && selectFunc) selectFunc(); + + return newFocus; +} + +} //namespace menu diff --git a/Gamecube/libgui/Frame.h b/Gamecube/libgui/Frame.h new file mode 100644 index 0000000..800b422 --- /dev/null +++ b/Gamecube/libgui/Frame.h @@ -0,0 +1,60 @@ +/** + * WiiSX - Frame.h + * Copyright (C) 2009, 2010 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef FRAME_H +#define FRAME_H + +#include "GuiTypes.h" +#include "Component.h" + +typedef void (*FrameFunc)( void ); + +namespace menu { + +class Frame : public Component +{ +public: + Frame(); + ~Frame(); + void showFrame(); + void hideFrame(); + void setEnabled(bool enable); + virtual void drawChildren(Graphics& gfx); + void remove(Component* component); + void removeAll(); + void add(Component* comp); + void updateTime(float deltaTime); + void setDefaultFocus(Component* comp); + Component* getDefaultFocus(); + void setBackFunc(FrameFunc backFn); + void setSelectFunc(FrameFunc selectFn); + Component* updateFocus(int direction, int buttonsPressed); + virtual void activateSubmenu(int submenu) {}; + virtual void updateFrame(float deltaTime) {}; + +private: + Component* defaultFocus; + FrameFunc backFunc, selectFunc; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/GraphicsGX.cpp b/Gamecube/libgui/GraphicsGX.cpp new file mode 100644 index 0000000..6f2420d --- /dev/null +++ b/Gamecube/libgui/GraphicsGX.cpp @@ -0,0 +1,505 @@ +/** + * WiiSX - GraphicsGX.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include "GraphicsGX.h" + +#define DEFAULT_FIFO_SIZE (256 * 1024) + + +extern "C" unsigned int usleep(unsigned int us); +void video_mode_init(GXRModeObj *rmode, unsigned int *fb1, unsigned int *fb2); + +namespace menu { + +Graphics::Graphics(GXRModeObj *rmode) + : vmode(rmode), + which_fb(0), + first_frame(true), + depth(1.0f), + transparency(1.0f), + viewportWidth(640.0f), + viewportHeight(480.0f) +{ +// printf("Graphics constructor\n"); + + setColor((GXColor) {0,0,0,0}); + +#ifdef HW_RVL + CONF_Init(); +#endif + VIDEO_Init(); + switch (videoMode) + { + case VIDEOMODE_AUTO: + //vmode = VIDEO_GetPreferredMode(NULL); + vmode = VIDEO_GetPreferredMode(&vmode_phys); +#if 0 + if(CONF_GetAspectRatio()) { + vmode->viWidth = 678; + vmode->viXOrigin = (VI_MAX_WIDTH_PAL - 678) / 2; + } +#endif + if (memcmp( &vmode_phys, &TVPal528IntDf, sizeof(GXRModeObj)) == 0) + memcpy( &vmode_phys, &TVPal576IntDfScale, sizeof(GXRModeObj)); + break; + case VIDEOMODE_NTSC: + vmode = &TVNtsc480IntDf; + memcpy( &vmode_phys, vmode, sizeof(GXRModeObj)); + break; + case VIDEOMODE_PAL: + vmode = &TVPal576IntDfScale; + memcpy( &vmode_phys, vmode, sizeof(GXRModeObj)); + break; + case VIDEOMODE_PROGRESSIVE: + vmode = &TVNtsc480Prog; + memcpy( &vmode_phys, vmode, sizeof(GXRModeObj)); + break; + } + + //vmode->efbHeight = viewportHeight; // Note: all possible modes have efbHeight of 480 + + VIDEO_Configure(vmode); + + xfb[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode)); + xfb[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(vmode)); + + console_init (xfb[0], 20, 64, vmode->fbWidth, vmode->xfbHeight, vmode->fbWidth * 2); + + VIDEO_SetNextFramebuffer(xfb[which_fb]); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if(vmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync(); + which_fb ^= 1; + + //Pass vmode, xfb[0] and xfb[1] back to main program + video_mode_init(vmode, (unsigned int*)xfb[0], (unsigned int*)xfb[1]); + + //Perform GX init stuff here? + //GX_init here or in main? + //GX_SetViewport( 0.0f, 0.0f, viewportWidth, viewportHeight ); + init(); +} + +Graphics::~Graphics() +{ +} + +void Graphics::init() +{ + + f32 yscale; + u32 xfbHeight; + void *gpfifo = NULL; + GXColor background = {0, 0, 0, 0xff}; + + gpfifo = memalign(32,DEFAULT_FIFO_SIZE); + memset(gpfifo,0,DEFAULT_FIFO_SIZE); + GX_Init(gpfifo,DEFAULT_FIFO_SIZE); + GX_SetCopyClear(background, GX_MAX_Z24); + + GX_SetViewport(0,0,vmode->fbWidth,vmode->efbHeight,0,1); + yscale = GX_GetYScaleFactor(vmode->efbHeight,vmode->xfbHeight); + xfbHeight = GX_SetDispCopyYScale(yscale); + GX_SetScissor(0,0,vmode->fbWidth,vmode->efbHeight); + GX_SetDispCopySrc(0,0,vmode->fbWidth,vmode->efbHeight); + GX_SetDispCopyDst(vmode->fbWidth,xfbHeight); + GX_SetCopyFilter(vmode->aa,vmode->sample_pattern,GX_TRUE,vmode->vfilter); + GX_SetFieldMode(vmode->field_rendering,((vmode->viHeight==2*vmode->xfbHeight)?GX_ENABLE:GX_DISABLE)); + + if (vmode->aa) + GX_SetPixelFmt(GX_PF_RGB565_Z16, GX_ZC_LINEAR); + else + GX_SetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); + + GX_SetCullMode(GX_CULL_NONE); + GX_SetDispCopyGamma(GX_GM_1_0); + + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_TEXMTX0); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + setTEV(GX_PASSCLR); + newModelView(); + loadModelView(); + loadOrthographic(); +} + +void Graphics::drawInit() +{ + // Reset various parameters from gfx plugin + GX_SetZTexture(GX_ZT_DISABLE,GX_TF_Z16,0); //GX_ZT_DISABLE or GX_ZT_REPLACE; set in gDP.cpp + GX_SetZCompLoc(GX_TRUE); // Do Z-compare before texturing. + GX_SetFog(GX_FOG_NONE,0,1,0,1,(GXColor){0,0,0,255}); + GX_SetViewport(0,0,vmode->fbWidth,vmode->efbHeight,0,1); + GX_SetCoPlanar(GX_DISABLE); + GX_SetClipMode(GX_CLIP_ENABLE); + GX_SetScissor(0,0,vmode->fbWidth,vmode->efbHeight); + GX_SetAlphaCompare(GX_ALWAYS,0,GX_AOP_AND,GX_ALWAYS,0); + + GX_SetZMode(GX_ENABLE,GX_ALWAYS,GX_TRUE); + + //set blend mode + GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); //Fix src alpha + GX_SetColorUpdate(GX_ENABLE); + GX_SetAlphaUpdate(GX_ENABLE); + GX_SetDstAlpha(GX_DISABLE, 0xFF); + //set cull mode + GX_SetCullMode (GX_CULL_NONE); + + GX_InvVtxCache(); + GX_InvalidateTexAll(); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_TEXMTX0); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + setTEV(GX_PASSCLR); + newModelView(); + loadModelView(); + loadOrthographic(); +} + +void Graphics::swapBuffers() +{ +// printf("Graphics swapBuffers\n"); +// if(which_fb==1) usleep(1000000); + GX_SetCopyClear((GXColor){0, 0, 0, 0xFF}, GX_MAX_Z24); + GX_CopyDisp(xfb[which_fb],GX_TRUE); + GX_Flush(); + + VIDEO_SetNextFramebuffer(xfb[which_fb]); + if(first_frame) { + first_frame = false; + VIDEO_SetBlack(GX_FALSE); + } + VIDEO_Flush(); + VIDEO_WaitVSync(); + which_fb ^= 1; +// printf("Graphics endSwapBuffers\n"); +} + +void Graphics::clearEFB(GXColor color, u32 zvalue) +{ + GX_SetColorUpdate(GX_ENABLE); + GX_SetAlphaUpdate(GX_ENABLE); + GX_SetZMode(GX_ENABLE,GX_ALWAYS,GX_TRUE); + GX_SetCopyClear(color, zvalue); + GX_CopyDisp(xfb[which_fb],GX_TRUE); + GX_Flush(); +} + +void Graphics::newModelView() +{ + guMtxIdentity(currentModelViewMtx); +} + +void Graphics::translate(float x, float y, float z) +{ + Mtx tmp; + guMtxTrans (tmp, x, y, z); + guMtxConcat (currentModelViewMtx, tmp, currentModelViewMtx); +} + +void Graphics::translateApply(float x, float y, float z) +{ + guMtxTransApply(currentModelViewMtx,currentModelViewMtx,x,y,z); +} + +void Graphics::rotate(float degrees) +{ + guMtxRotDeg(currentModelViewMtx,'Z',degrees); +} + +void Graphics::loadModelView() +{ + GX_LoadPosMtxImm(currentModelViewMtx,GX_PNMTX0); +} + +void Graphics::loadOrthographic() +{ + if(screenMode) guOrtho(currentProjectionMtx, 0, 479, -104, 743, 0, 700); + else guOrtho(currentProjectionMtx, 0, 479, 0, 639, 0, 700); + GX_LoadProjectionMtx(currentProjectionMtx, GX_ORTHOGRAPHIC); +} + +void Graphics::setDepth(float newDepth) +{ + depth = newDepth; +} + +float Graphics::getDepth() +{ + return depth; +} + +void Graphics::setColor(GXColor color) +{ + for (int i = 0; i < 4; i++){ + currentColor[i].r = color.r; + currentColor[i].g = color.g; + currentColor[i].b = color.b; + currentColor[i].a = color.a; + } + applyCurrentColor(); +} + +void Graphics::setColor(GXColor* color) +{ + for (int i = 0; i < 4; i++){ + currentColor[i].r = color[i].r; + currentColor[i].g = color[i].g; + currentColor[i].b = color[i].b; + currentColor[i].a = color[i].a; + } + applyCurrentColor(); +} + +void Graphics::drawRect(int x, int y, int width, int height) +{ + GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 4); + GX_Position3f32((float) x,(float) y, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) (x+width),(float) y, depth ); + GX_Color4u8(appliedColor[1].r, appliedColor[1].g, appliedColor[1].b, appliedColor[1].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) (x+width),(float) (y+height), depth ); + GX_Color4u8(appliedColor[2].r, appliedColor[2].g, appliedColor[2].b, appliedColor[2].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) x,(float) (y+height), depth ); + GX_Color4u8(appliedColor[3].r, appliedColor[3].g, appliedColor[3].b, appliedColor[3].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_End(); +} + +void Graphics::fillRect(int x, int y, int width, int height) +{ + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32((float) x,(float) y, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) (x+width),(float) y, depth ); + GX_Color4u8(appliedColor[1].r, appliedColor[1].g, appliedColor[1].b, appliedColor[1].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) (x+width),(float) (y+height), depth ); + GX_Color4u8(appliedColor[2].r, appliedColor[2].g, appliedColor[2].b, appliedColor[2].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) x,(float) (y+height), depth ); + GX_Color4u8(appliedColor[3].r, appliedColor[3].g, appliedColor[3].b, appliedColor[3].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_End(); +} + +void Graphics::drawImage(int textureId, int x, int y, int width, int height, float s1, float s2, float t1, float t2) +{ + //Init texture here or in calling code? + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position3f32((float) x,(float) y, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(s1,t1); + GX_Position3f32((float) (x+width),(float) y, depth ); + GX_Color4u8(appliedColor[1].r, appliedColor[1].g, appliedColor[1].b, appliedColor[1].a); + GX_TexCoord2f32(s2,t1); + GX_Position3f32((float) (x+width),(float) (y+height), depth ); + GX_Color4u8(appliedColor[2].r, appliedColor[2].g, appliedColor[2].b, appliedColor[2].a); + GX_TexCoord2f32(s2,t2); + GX_Position3f32((float) x,(float) (y+height), depth ); + GX_Color4u8(appliedColor[3].r, appliedColor[3].g, appliedColor[3].b, appliedColor[3].a); + GX_TexCoord2f32(s1,t2); + GX_End(); +} + +void Graphics::drawLine(int x1, int y1, int x2, int y2) +{ + GX_Begin(GX_LINES, GX_VTXFMT0, 2); + GX_Position3f32((float) x1,(float) y1, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_Position3f32((float) x2,(float) y2, depth ); + GX_Color4u8(appliedColor[1].r, appliedColor[1].g, appliedColor[1].b, appliedColor[1].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_End(); +} + +#ifndef PI +#define PI 3.14159f +#endif + +void Graphics::drawCircle(int x, int y, int radius, int numSegments) +{ + + GX_Begin(GX_LINESTRIP, GX_VTXFMT0, numSegments+1); + + for (int i = 0; i<=numSegments; i++) + { + float angle, point_x, point_y; + angle = 2*PI * i/numSegments; + point_x = (float)x + (float)radius * cos( angle ); + point_y = (float)y + (float)radius * sin( angle ); + + GX_Position3f32((float) point_x,(float) point_y, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(0.0f,0.0f); + } + + GX_End(); +} + +void Graphics::drawString(int x, int y, const std::string &str) +{ + //todo +} + +void Graphics::drawPoint(int x, int y, int radius) +{ + GX_SetPointSize(u8 (radius *3 ),GX_TO_ZERO); + GX_Begin(GX_POINTS, GX_VTXFMT0, 1); + GX_Position3f32((float) x,(float) y, depth ); + GX_Color4u8(appliedColor[0].r, appliedColor[0].g, appliedColor[0].b, appliedColor[0].a); + GX_TexCoord2f32(0.0f,0.0f); + GX_End(); +} + +void Graphics::setLineWidth(int width) +{ + GX_SetLineWidth((u8) (width * 6), GX_TO_ZERO ); +} + +void Graphics::pushDepth(float d) +{ + depthStack.push(getDepth()); + setDepth(d); +} + +void Graphics::popDepth() +{ + depthStack.pop(); + if(depthStack.size() != 0) + { + setDepth(depthStack.top()); + } + else + { + setDepth(1.0f); + } +} + +void Graphics::enableScissor(int x, int y, int width, int height) +{ + if(screenMode) + { + int x1 = (x+104)*640/848; + int x2 = (x+width+104)*640/848; + GX_SetScissor((u32) x1,(u32) y,(u32) x2-x1,(u32) height); + } + else + GX_SetScissor((u32) x,(u32) y,(u32) width,(u32) height); +} + +void Graphics::disableScissor() +{ + GX_SetScissor((u32) 0,(u32) 0,(u32) viewportWidth,(u32) viewportHeight); //Set to the same size as the viewport. +} + +void Graphics::enableBlending(bool blend) +{ + if (blend) + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); + else + GX_SetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR); +} + +void Graphics::setTEV(int tev_op) +{ + GX_SetNumTevStages(1); + GX_SetNumChans (1); + GX_SetNumTexGens (1); + GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GX_SetTevOp (GX_TEVSTAGE0, tev_op); +} + +void Graphics::pushTransparency(float f) +{ + transparencyStack.push(getTransparency()); + setTransparency(f); +} + +void Graphics::popTransparency() +{ + transparencyStack.pop(); + if(transparencyStack.size() != 0) + { + setTransparency(transparencyStack.top()); + } + else + { + setTransparency(1.0f); + } +} + +void Graphics::setTransparency(float f) +{ + transparency = f; + applyCurrentColor(); +} + +float Graphics::getTransparency() +{ + return transparency; +} + +void Graphics::applyCurrentColor() +{ + for (int i = 0; i < 4; i++){ + appliedColor[i].r = currentColor[i].r; + appliedColor[i].g = currentColor[i].g; + appliedColor[i].b = currentColor[i].b; + appliedColor[i].a = (u8) (getCurrentTransparency(i) * 255.0f); + } +} + +float Graphics::getCurrentTransparency(int index) +{ + float alpha = (float)currentColor[index].a/255.0f; + float val = alpha * transparency; + return val; +} + +} //namespace menu diff --git a/Gamecube/libgui/GraphicsGX.h b/Gamecube/libgui/GraphicsGX.h new file mode 100644 index 0000000..6c26110 --- /dev/null +++ b/Gamecube/libgui/GraphicsGX.h @@ -0,0 +1,86 @@ +/** + * WiiSX - GraphicsGX.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef GRAPHICSGX_H +#define GRAPHICSGX_H + +#include "GuiTypes.h" +#include + +namespace menu { + +class Graphics +{ +public: + explicit Graphics(GXRModeObj *vmode); + ~Graphics(); + void init(); + void drawInit(); + void swapBuffers(); + void clearEFB(GXColor color, u32 zvalue); + void newModelView(); + void translate(float x, float y, float z); + void translateApply(float x, float y, float z); + void rotate(float degrees); + void loadModelView(); + void loadOrthographic(); + void setDepth(float newDepth); + float getDepth(); + void setColor(GXColor color); + void setColor(GXColor* color); + void drawRect(int x, int y, int width, int height); + void fillRect(int x, int y, int width, int height); + void drawImage(int textureId, int x, int y, int width, int height, float s1, float s2, float t1, float t2); + void drawLine(int x1, int y1, int x2, int y2); + void drawCircle(int x, int y, int radius, int numSegments); + void drawString(int x, int y, const std::string &str); + void drawPoint(int x, int y, int radius); + void setLineWidth(int width); + void pushDepth(float d); + void popDepth(); + void enableScissor(int x, int y, int width, int height); + void disableScissor(); + void enableBlending(bool blend); + void setTEV(int tev_op); + void pushTransparency(float f); + void popTransparency(); + void setTransparency(float f); + float getTransparency(); + +private: + void applyCurrentColor(); + float getCurrentTransparency(int index); + GXRModeObj *vmode; + GXRModeObj vmode_phys; + int which_fb; + bool first_frame; + void *xfb[2]; + float depth, transparency; + float viewportWidth, viewportHeight; + FloatStack depthStack, transparencyStack; + GXColor currentColor[4], appliedColor[4]; + Mtx currentModelViewMtx; + Mtx44 currentProjectionMtx; +// MatrixStack modelViewMtxStack; +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/Gui.cpp b/Gamecube/libgui/Gui.cpp new file mode 100644 index 0000000..7abc66e --- /dev/null +++ b/Gamecube/libgui/Gui.cpp @@ -0,0 +1,158 @@ +/** + * WiiSX - Gui.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Gui.h" +#include "IPLFont.h" +#include "InputManager.h" +#include "CursorManager.h" +#include "FocusManager.h" +#include "MessageBox.h" +#include "LoadingBar.h" +#include "GuiResources.h" + +extern "C" { +#include "../gc_input/controller.h" +#ifdef WII +#include +#endif +} + +extern char shutdown; + +namespace menu { + +Gui::Gui() + : fade(9) +{ + menuLogo = new Logo(); + menuLogo->setLocation(570.0, 70.0, -150.0); + menuLogo->setVisible(true); +} + +Gui::~Gui() +{ + delete menuLogo; + delete gfx; +} + +void Gui::setVmode(GXRModeObj *vmode) +{ + gfx = new Graphics(vmode); + IplFont::getInstance().setVmode(vmode); +} + +void Gui::addFrame(Frame *frame) +{ + frameList.push_back(frame); +} + +void Gui::removeFrame(Frame *frame) +{ + frameList.erase(std::remove(frameList.begin(),frameList.end(),frame),frameList.end()); +} + +void Gui::draw() +{ +// printf("Gui draw\n"); + Input::getInstance().refreshInput(); + Cursor::getInstance().updateCursor(); + Focus::getInstance().updateFocus(); + if(padAutoAssign) auto_assign_controllers(); + //Update time?? + //Get graphics framework and pass to Frame draw fns? + gfx->drawInit(); + drawBackground(); + FrameList::const_iterator iteration; + for (iteration = frameList.begin(); iteration != frameList.end(); ++iteration) + { + (*iteration)->drawChildren(*gfx); + } +// menuLogo->drawComponent(*gfx); + menuLogo->draw(*gfx); + if (MessageBox::getInstance().getActive()) MessageBox::getInstance().drawMessageBox(*gfx); + if (LoadingBar::getInstance().getActive()) LoadingBar::getInstance().drawLoadingBar(*gfx); + Cursor::getInstance().drawCursor(*gfx); + + if(shutdown) + { + Cursor::getInstance().setFreezeAction(true); + Focus::getInstance().setFreezeAction(true); + gfx->enableBlending(true); + gfx->setTEV(GX_PASSCLR); + gfx->setDepth(-10.0f); + gfx->newModelView(); + gfx->loadModelView(); + gfx->loadOrthographic(); + + gfx->setColor((GXColor){0, 0, 0, fade}); + if(screenMode) gfx->fillRect(-104, 0, 848, 480); + else gfx->fillRect(0, 0, 640, 480); + + if(fade == 255) + { + VIDEO_SetBlack(true); + VIDEO_Flush(); + VIDEO_WaitVSync(); + if(shutdown==1) //Power off System + SYS_ResetSystem(SYS_POWEROFF, 0, 0); + else //Return to Loader + { +#ifdef WII + DI_Close(); +#endif + void (*rld)() = (void (*)()) 0x80001800; +#ifdef HW_DOL + #define PSOSDLOADID 0x7c6000a6 + // try to reload + if(*(volatile unsigned int*)0x80001800 == PSOSDLOADID) { + rld(); + } + else { + *(volatile unsigned int*)0xCC003024 = 0; //reboot + } +#else + rld(); +#endif + } + } + + char increment = 3; + fade = fade +increment > 255 ? 255 : fade + increment; + } + + gfx->swapBuffers(); +} + +void Gui::drawBackground() +{ + //Draw Menu Backdrop + Resources::getInstance().getImage(Resources::IMAGE_MENU_BACKGROUND)->activateImage(GX_TEXMAP0); +// gfx->setTEV(GX_REPLACE); + GXColor muxCol = (GXColor){0,35,70,255}; + GX_SetTevColor(GX_TEVREG0,muxCol); + GX_SetTevColorIn(GX_TEVSTAGE0,GX_CC_C0,GX_CC_ZERO,GX_CC_TEXC,GX_CC_TEXC); + GX_SetTevColorOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + gfx->enableBlending(false); + if(screenMode) gfx->drawImage(0, -104, 0, 848, 480, 0, 1, 0, 1); + else gfx->drawImage(0, 0, 0, 640, 480, (848.0-640.0)/2/848.0, 1.0 - (848.0-640.0)/2/848.0, 0, 1); + gfx->setTEV(GX_PASSCLR); +} + +} //namespace menu diff --git a/Gamecube/libgui/Gui.h b/Gamecube/libgui/Gui.h new file mode 100644 index 0000000..68353ca --- /dev/null +++ b/Gamecube/libgui/Gui.h @@ -0,0 +1,56 @@ +/** + * Wii64 - Gui.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef GUI_H +#define GUI_H + +#include "GuiTypes.h" +#include "Frame.h" +#include "Logo.h" +#include "GraphicsGX.h" + +namespace menu { + +class Gui +{ +public: + void setVmode(GXRModeObj *rmode); + void addFrame(Frame* frame); + void removeFrame(Frame* frame); + void draw(); + void drawBackground(); + static Gui& getInstance() + { + static Gui obj; + return obj; + } + Graphics *gfx; + Logo* menuLogo; + +private: + Gui(); + ~Gui(); + FrameList frameList; + char fade; +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/GuiResources.cpp b/Gamecube/libgui/GuiResources.cpp new file mode 100644 index 0000000..8cd8d18 --- /dev/null +++ b/Gamecube/libgui/GuiResources.cpp @@ -0,0 +1,137 @@ +/** + * WiiSX - GuiResources.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "GuiResources.h" +#include "Image.h" +#include "resources.h" +#include "../menu/MenuResources.h" + +namespace menu { + +Resources::Resources() +{ + defaultButtonImage = new Image(ButtonTexture, 16, 16, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE); + defaultButtonFocusImage = new Image(ButtonFocusTexture, 16, 16, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE); +// styleAButtonImage = new Image(StyleAButtonTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); +// styleAButtonFocusImage = new Image(StyleAButtonFocusTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); +// styleAButtonSelectOffImage = new Image(StyleAButtonSelectOffTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); +// styleAButtonSelectOffFocusImage = new Image(StyleAButtonSelectOffFocusTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); +// styleAButtonSelectOnImage = new Image(StyleAButtonSelectOnTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); +// styleAButtonSelectOnFocusImage = new Image(StyleAButtonSelectOnFocusTexture, 8, 56, GX_TF_CI8, GX_CLAMP, GX_CLAMP, GX_FALSE, StyleAButtonTlut, GX_TL_RGB5A3, GX_TLUT0, GX_TLUT_256); + styleAButtonImage = new Image(StyleAButtonTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + styleAButtonFocusImage = new Image(StyleAButtonFocusTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + styleAButtonSelectOffImage = new Image(StyleAButtonSelectOffTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + styleAButtonSelectOffFocusImage = new Image(StyleAButtonSelectOffFocusTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + styleAButtonSelectOnImage = new Image(StyleAButtonSelectOnTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); + styleAButtonSelectOnFocusImage = new Image(StyleAButtonSelectOnFocusTexture, 8, 56, GX_TF_RGBA8, GX_CLAMP, GX_CLAMP, GX_FALSE); +// menuBackgroundImage = new Image(BackgroundTexture, 848, 480, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE); + menuBackgroundImage = new Image(BackgroundTexture, 424, 240, GX_TF_I8, GX_CLAMP, GX_CLAMP, GX_FALSE); +#ifdef HW_RVL + logoImage = new Image(LogoTexture, 136, 52, GX_TF_RGB5A3, GX_CLAMP, GX_CLAMP, GX_FALSE); +#else + logoImage = new Image(LogoTexture, 176, 52, GX_TF_RGB5A3, GX_CLAMP, GX_CLAMP, GX_FALSE); +#endif + controllerEmptyImage = new Image(ControlEmptyTexture, 48, 64, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + controllerGamecubeImage = new Image(ControlGamecubeTexture, 48, 64, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + controllerClassicImage = new Image(ControlClassicTexture, 48, 64, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + controllerWiimoteNunchuckImage = new Image(ControlWiimoteNunchuckTexture, 48, 64, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + controllerWiimoteImage = new Image(ControlWiimoteTexture, 48, 64, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + psxControllerImage = new Image(PsxControllerTexture, 232, 152, GX_TF_IA4, GX_CLAMP, GX_CLAMP, GX_FALSE); + +} + +Resources::~Resources() +{ + delete defaultButtonImage; + delete defaultButtonFocusImage; + delete styleAButtonImage; + delete styleAButtonFocusImage; + delete styleAButtonSelectOffImage; + delete styleAButtonSelectOffFocusImage; + delete styleAButtonSelectOnImage; + delete styleAButtonSelectOnFocusImage; + delete menuBackgroundImage; + delete logoImage; + delete controllerEmptyImage; + delete controllerGamecubeImage; + delete controllerClassicImage; + delete controllerWiimoteNunchuckImage; + delete controllerWiimoteImage; + delete psxControllerImage; +} + +Image* Resources::getImage(int image) +{ + Image* returnImage = NULL; + switch (image) + { + case IMAGE_DEFAULT_BUTTON: + returnImage = defaultButtonImage; + break; + case IMAGE_DEFAULT_BUTTONFOCUS: + returnImage = defaultButtonFocusImage; + break; + case IMAGE_STYLEA_BUTTON: + returnImage = styleAButtonImage; + break; + case IMAGE_STYLEA_BUTTONFOCUS: + returnImage = styleAButtonFocusImage; + break; + case IMAGE_STYLEA_BUTTONSELECTOFF: + returnImage = styleAButtonSelectOffImage; + break; + case IMAGE_STYLEA_BUTTONSELECTOFFFOCUS: + returnImage = styleAButtonSelectOffFocusImage; + break; + case IMAGE_STYLEA_BUTTONSELECTON: + returnImage = styleAButtonSelectOnImage; + break; + case IMAGE_STYLEA_BUTTONSELECTONFOCUS: + returnImage = styleAButtonSelectOnFocusImage; + break; + case IMAGE_MENU_BACKGROUND: + returnImage = menuBackgroundImage; + break; + case IMAGE_LOGO: + returnImage = logoImage; + break; + case IMAGE_CONTROLLER_EMPTY: + returnImage = controllerEmptyImage; + break; + case IMAGE_CONTROLLER_GAMECUBE: + returnImage = controllerGamecubeImage; + break; + case IMAGE_CONTROLLER_CLASSIC: + returnImage = controllerClassicImage; + break; + case IMAGE_CONTROLLER_WIIMOTENUNCHUCK: + returnImage = controllerWiimoteNunchuckImage; + break; + case IMAGE_CONTROLLER_WIIMOTE: + returnImage = controllerWiimoteImage; + break; + case IMAGE_PSX_CONTROLLER: + returnImage = psxControllerImage; + break; + } + return returnImage; +} + +} //namespace menu diff --git a/Gamecube/libgui/GuiResources.h b/Gamecube/libgui/GuiResources.h new file mode 100644 index 0000000..5c1b64e --- /dev/null +++ b/Gamecube/libgui/GuiResources.h @@ -0,0 +1,76 @@ +/** + * WiiSX - GuiResources.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef GUIRESOURCES_H +#define GUIRESOURCES_H + +#include "GuiTypes.h" + +namespace menu { + +class Resources +{ +public: + Image* getImage(int image); + static Resources& getInstance() + { + static Resources obj; + return obj; + } + + enum Images + { + IMAGE_DEFAULT_BUTTON=1, + IMAGE_DEFAULT_BUTTONFOCUS, + IMAGE_STYLEA_BUTTON, + IMAGE_STYLEA_BUTTONFOCUS, + IMAGE_STYLEA_BUTTONSELECTOFF, + IMAGE_STYLEA_BUTTONSELECTOFFFOCUS, + IMAGE_STYLEA_BUTTONSELECTON, + IMAGE_STYLEA_BUTTONSELECTONFOCUS, + IMAGE_MENU_BACKGROUND, + IMAGE_LOGO, + IMAGE_CONTROLLER_EMPTY, + IMAGE_CONTROLLER_GAMECUBE, + IMAGE_CONTROLLER_CLASSIC, + IMAGE_CONTROLLER_WIIMOTENUNCHUCK, + IMAGE_CONTROLLER_WIIMOTE, + IMAGE_PSX_CONTROLLER + }; + +private: + Resources(); + ~Resources(); + Image *defaultButtonImage, *defaultButtonFocusImage; + Image *styleAButtonImage, *styleAButtonFocusImage; + Image *styleAButtonSelectOffImage, *styleAButtonSelectOffFocusImage; + Image *styleAButtonSelectOnImage, *styleAButtonSelectOnFocusImage; + Image *menuBackgroundImage; + Image *logoImage; + Image *controllerEmptyImage, *controllerGamecubeImage; + Image *controllerClassicImage, *controllerWiimoteNunchuckImage; + Image *controllerWiimoteImage; + Image *psxControllerImage; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/GuiTypes.h b/Gamecube/libgui/GuiTypes.h new file mode 100644 index 0000000..2cfb756 --- /dev/null +++ b/Gamecube/libgui/GuiTypes.h @@ -0,0 +1,60 @@ +/** + * Wii64 - GuiTypes.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef GUIDEFS_H +#define GUIDEFS_H + +#include +#include "../wiiSXconfig.h" +#ifdef HW_RVL +#include +#include +#endif +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +} + +namespace menu { + +class Graphics; +class Component; +class Frame; +class Button; +class Input; +class Cursor; +class Focus; +class Image; +class IplFont; + +typedef std::vector FrameList; +typedef std::vector ComponentList; +typedef std::stack FloatStack; +//typedef std::stack MatrixStack; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/IPLFont.cpp b/Gamecube/libgui/IPLFont.cpp new file mode 100644 index 0000000..77f28c2 --- /dev/null +++ b/Gamecube/libgui/IPLFont.cpp @@ -0,0 +1,474 @@ +/** + * Wii64 - IPLFont.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "IPLFont.h" + +#ifdef HW_RVL +#include "../MEM2.h" +#endif + +namespace menu { + +#define FONT_TEX_SIZE_I4 ((512*512)>>1) +#define FONT_SIZE_ANSI (288 + 131072) + +#define STRHEIGHT_OFFSET 6 + +extern "C" void __SYS_ReadROM(void *buf,u32 len,u32 offset); + +IplFont::IplFont() + : frameWidth(640) +{ +#ifdef HW_RVL + fontFont = (unsigned char*)(FONT_LO); +#endif + memset(fontFont,0,FONT_TEX_SIZE_I4); + initFont(); +} + +IplFont::~IplFont() +{ +} + +void IplFont::initFont() +{ + #ifndef WII + //lowlevel Qoob Modchip disable for cube + setIplConfig(6); + #endif + + void* fontArea = memalign(32,FONT_SIZE_ANSI); + memset(fontArea,0,FONT_SIZE_ANSI); + void* packed_data = (void*)(((u32)fontArea+119072)&~31); + void* unpacked_data = (void*)((u32)fontArea+288); + __SYS_ReadROM(packed_data,0x3000,0x1FCF00); + decodeYay0(packed_data,unpacked_data); + + sys_fontheader *fontData = (sys_fontheader*)unpacked_data; + + convertI2toI4((void*)fontFont, (void*)((u32)unpacked_data+fontData->sheet_image), fontData->sheet_width, fontData->sheet_height); + DCFlushRange(fontFont, FONT_TEX_SIZE_I4); + + for (int i=0; i<256; ++i) + { + int c = i; + + if ((c < fontData->first_char) || (c > fontData->last_char)) c = fontData->inval_char; + else c -= fontData->first_char; + + fontChars.font_size[i] = ((unsigned char*)fontData)[fontData->width_table + c]; + + int r = c / fontData->sheet_column; + c %= fontData->sheet_column; + + fontChars.s[i] = c * fontData->cell_width; + fontChars.t[i] = r * fontData->cell_height; + } + + fontChars.fheight = fontData->cell_height; + + free(fontArea); +} + +#ifndef WII +//used to disable lowlevel Qoob Modchip for cube + +void IplFont::setIplConfig(unsigned char c) +{ + //lowlevel Qoob Modchip disable + volatile unsigned long* exi = (volatile unsigned long*)0xCC006800; + unsigned long val,addr; + addr=0xc0000000; + val = c << 24; + exi[0] = ((((exi[0]) & 0x405) | 256) | 48); //select IPL + //write addr of IPL + exi[0 * 5 + 4] = addr; + exi[0 * 5 + 3] = ((4 - 1) << 4) | (1 << 2) | 1; + while (exi[0 * 5 + 3] & 1); + //write the ipl we want to send + exi[0 * 5 + 4] = val; + exi[0 * 5 + 3] = ((4 - 1) << 4) | (1 << 2) | 1; + while (exi[0 * 5 + 3] & 1); + + exi[0] &= 0x405; //deselect IPL +} +#endif + +typedef struct _yay0header { + unsigned int id ATTRIBUTE_PACKED; + unsigned int dec_size ATTRIBUTE_PACKED; + unsigned int links_offset ATTRIBUTE_PACKED; + unsigned int chunks_offset ATTRIBUTE_PACKED; +} yay0header; + +void IplFont::decodeYay0(void *src, void *dest) +{ + /* Yay0 decompression */ + u32 i,k,link; + u8 *dest8,*tmp; + u32 loff,coff,roff; + u32 size,cnt,cmask,bcnt; + yay0header *header; + + dest8 = (u8*)dest; + header = (yay0header*)src; + size = header->dec_size; + loff = header->links_offset; + coff = header->chunks_offset; + + roff = sizeof(yay0header); + cmask = 0; + cnt = 0; + bcnt = 0; + + do { + if(!bcnt) { + cmask = *(u32*)((u32)src+roff); + roff += 4; + bcnt = 32; + } + + if(cmask&0x80000000) { + dest8[cnt++] = *(u8*)((u32)src+coff); + coff++; + } else { + link = *(u16*)((u32)src+loff); + loff += 2; + + tmp = dest8+(cnt-(link&0x0fff)-1); + k = link>>12; + if(k==0) { + k = (*(u8*)((u32)src+coff))+18; + coff++; + } else k += 2; + + for(i=0;i>6)&3)<<6) | (((v>>6)&3)<<4) | (((v>>4)&3)<<2) | ((v>>4)&3); + *d++ = (((v>>2)&3)<<6) | (((v>>2)&3)<<4) | (((v)&3)<<2) | ((v)&3); + } + } + } +} + +void IplFont::setVmode(GXRModeObj *rmode) +{ + vmode = rmode; +} + +extern "C" char menuActive; + +void IplFont::drawInit(GXColor fontColor) +{ + //FixMe: vmode access + Mtx44 GXprojection2D; + Mtx GXmodelView2D; + + // Reset various parameters from gfx plugin + GX_SetCoPlanar(GX_DISABLE); + GX_SetClipMode(GX_CLIP_ENABLE); +// GX_SetScissor(0,0,vmode->fbWidth,vmode->efbHeight); + GX_SetAlphaCompare(GX_ALWAYS,0,GX_AOP_AND,GX_ALWAYS,0); + + guMtxIdentity(GXmodelView2D); + GX_LoadTexMtxImm(GXmodelView2D,GX_TEXMTX0,GX_MTX2x4); +// guMtxTransApply (GXmodelView2D, GXmodelView2D, 0.0F, 0.0F, -5.0F); + GX_LoadPosMtxImm(GXmodelView2D,GX_PNMTX0); + if(screenMode && menuActive) + guOrtho(GXprojection2D, 0, 479, -104, 743, 0, 700); + else if(screenMode == SCREENMODE_16x9_PILLARBOX) + guOrtho(GXprojection2D, 0, 479, -104, 743, 0, 700); + else + guOrtho(GXprojection2D, 0, 479, 0, 639, 0, 700); + GX_LoadProjectionMtx(GXprojection2D, GX_ORTHOGRAPHIC); +// GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1); + + GX_SetZMode(GX_DISABLE,GX_ALWAYS,GX_TRUE); + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_TEXMTX0); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + //set vertex attribute formats here + GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_POS, GX_POS_XYZ, GX_S16, 0); + GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); +// GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_U16, 7); + GX_SetVtxAttrFmt(GX_VTXFMT1, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + //enable textures + GX_SetNumChans (1); +// GX_SetChanCtrl(GX_COLOR0A0,GX_DISABLE,GX_SRC_REG,GX_SRC_VTX,GX_LIGHTNULL,GX_DF_NONE,GX_AF_NONE); + GX_SetNumTexGens (1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GX_InvalidateTexAll(); + GX_InitTexObj(&fontTexObj, &fontFont[0], 512, 512, GX_TF_I4, GX_CLAMP, GX_CLAMP, GX_FALSE); + GX_LoadTexObj(&fontTexObj, GX_TEXMAP0); + + GX_SetTevColor(GX_TEVREG1,fontColor); +// GX_SetTevKColor(GX_KCOLOR0, fontColor); +// GX_SetTevKColorSel(GX_TEVSTAGE0,GX_TEV_KCSEL_K0); +// GX_SetTevKAlphaSel(GX_TEVSTAGE0,GX_TEV_KCSEL_K0_A); + + GX_SetNumTevStages (1); + GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); // change to (u8) tile later + GX_SetTevColorIn (GX_TEVSTAGE0, GX_CC_C1, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); +// GX_SetTevColorIn (GX_TEVSTAGE0, GX_CC_KONST, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); + GX_SetTevColorOp (GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV); + GX_SetTevAlphaIn (GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_A1, GX_CA_TEXA, GX_CA_ZERO); + GX_SetTevAlphaOp (GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_ENABLE, GX_TEVPREV); +// GX_SetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_RED); +// GX_SetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); +// GX_SetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP1); + + //set blend mode + GX_SetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR); //Fix src alpha + GX_SetColorUpdate(GX_ENABLE); +// GX_SetAlphaUpdate(GX_ENABLE); +// GX_SetDstAlpha(GX_DISABLE, 0xFF); + //set cull mode + GX_SetCullMode (GX_CULL_NONE); + +} + +void IplFont::setColor(GXColor fontColour) +{ + GX_SetTevColor(GX_TEVREG1, fontColour); +// GX_SetTevKColor(GX_KCOLOR0, fontColour); + fontColor.r = fontColour.r; + fontColor.g = fontColour.g; + fontColor.b = fontColour.b; + fontColor.a = fontColour.a; +} + +void IplFont::setColor(GXColor* fontColorPtr) +{ + GX_SetTevColor(GX_TEVREG1, *fontColorPtr); +// GX_SetTevKColor(GX_KCOLOR0, *fontColorPtr); + fontColor.r = fontColorPtr->r; + fontColor.g = fontColorPtr->g; + fontColor.b = fontColorPtr->b; + fontColor.a = fontColorPtr->a; +} + +void IplFont::drawString(int x, int y, char *string, float scale, bool centered) +{ + if(centered) + { + int strWidth = 0; + int strHeight = (fontChars.fheight+STRHEIGHT_OFFSET) * scale; + char* string_work = string; +// while(*string_work && (x < back_framewidth)) + while(*string_work) + { + unsigned char c = *string_work; + strWidth += (int) fontChars.font_size[c] * scale; + string_work++; + } +// x0 = (int) MAX(0, (back_framewidth - x)/2); +// x = (int) (frameWidth - x)/2; + x = (int) x - strWidth/2; + y = (int) y - strHeight/2; +// write_font(x0,y,string,scale); + } + +// int ox = x; + +// while (*string && (x < (ox + back_framewidth))) + while (*string) + { + //blit_char(axfb,whichfb,x, y, *string, norm_blit ? blit_lookup_norm : blit_lookup); + unsigned char c = *string; + int i; + GX_Begin(GX_QUADS, GX_VTXFMT1, 4); + for (i=0; i<4; i++) { + int s = ((i & 1) ^ ((i & 2) >> 1)) ? fontChars.font_size[c] : 1; + int t = (i & 2) ? fontChars.fheight : 1; + float s0 = ((float) (fontChars.s[c] + s))/512; + float t0 = ((float) (fontChars.t[c] + t))/512; + s = (int) s * scale; + t = (int) t * scale; + GX_Position3s16(x + s, y + t, 0); + GX_Color4u8(fontColor.r, fontColor.g, fontColor.b, fontColor.a); +// GX_Color4u8(fontState->colour.r, fontState->colour.g, fontState->colour.b, fontState->colour.a); +// GX_TexCoord2f32(((float) (fontChars.s[c] + s))/512, ((float) (fontChars.t[c] + t))/512); +// GX_TexCoord2u16(fontChars.s[c] + s, fontChars.t[c] + t); + GX_TexCoord2f32(s0, t0); + } + GX_End(); + + x += (int) fontChars.font_size[c] * scale; + string++; + } + +} + +int IplFont::drawStringWrap(int x, int y, char *string, float scale, bool centered, int maxWidth, int lineSpacing) +{ + int numLines = 0; + int stringWidth = 0; + int tokenWidth = 0; + int numTokens = 0; + char* lineStart = string; + char* lineStop = string; + char* stringWork = string; + char* stringDraw = NULL; + + while(1) + { + if(*stringWork == 0) //end of string + { + if((stringWidth + tokenWidth <= maxWidth) || (numTokens = 0)) + { + if (stringWidth + tokenWidth > 0) + { + drawString( x, y+numLines*lineSpacing, lineStart, scale, centered); + numLines++; + } + break; + } + else + { + stringDraw = (char*)malloc(lineStop - lineStart + 1); + for (int i = 0; i < lineStop-lineStart; i++) + stringDraw[i] = lineStart[i]; + stringDraw[lineStop-lineStart] = 0; + drawString( x, y+numLines*lineSpacing, stringDraw, scale, centered); + free(stringDraw); + numLines++; + lineStart = lineStop+1; + drawString( x, y+numLines*lineSpacing, lineStart, scale, centered); + numLines++; + break; + } + } + + if((*stringWork == ' ')) //end of token + { + if(stringWidth + tokenWidth <= maxWidth) + { + stringWidth += tokenWidth; + numTokens++; + tokenWidth = 0; + lineStop = stringWork; + } + else + { + if (numTokens == 0) //if the word is wider than maxWidth, just print it + lineStop = stringWork; + + stringDraw = (char*)malloc(lineStop - lineStart + 1); + for (int i = 0; i < lineStop-lineStart; i++) + stringDraw[i] = lineStart[i]; + stringDraw[lineStop-lineStart] = 0; + drawString( x, y+numLines*lineSpacing, stringDraw, scale, centered); + free(stringDraw); + numLines++; + + lineStart = lineStop+1; + lineStop = lineStart; + stringWork = lineStart; + stringWidth = 0; + tokenWidth = 0; + numTokens = 0; + continue; + } + } + tokenWidth += (int) fontChars.font_size[(int)(*stringWork)] * scale; + + stringWork++; + } + + return numLines; +} + +void IplFont::drawStringAtOrigin(char *string, float scale) +{ + int x0, y0, x = 0; + char* string_work = string; + while(*string_work) + { + unsigned char c = *string_work; + x += (int) fontChars.font_size[c] * scale; + string_work++; + } + x0 = (int) -x/2; + y0 = (int) -(fontChars.fheight+STRHEIGHT_OFFSET)*scale/2; + drawString(x0, y0, string, scale, false); +} + +int IplFont::getStringWidth(char *string, float scale) +{ + int strWidth = 0; + char* string_work = string; + while(*string_work) + { + unsigned char c = *string_work; + strWidth += (int) fontChars.font_size[c] * scale; + string_work++; + } + return strWidth; +} + +int IplFont::getStringHeight(char *string, float scale) +{ + int strHeight = (fontChars.fheight+STRHEIGHT_OFFSET) * scale; + + return strHeight; +} + +} //namespace menu + +extern "C" { +void IplFont_drawInit(GXColor fontColor) +{ + menu::IplFont::getInstance().drawInit(fontColor); +} + +void IplFont_drawString(int x, int y, char *string, float scale, bool centered) +{ + menu::IplFont::getInstance().drawString(x, y, string, scale, centered); +} +} diff --git a/Gamecube/libgui/IPLFont.h b/Gamecube/libgui/IPLFont.h new file mode 100644 index 0000000..ca42c3d --- /dev/null +++ b/Gamecube/libgui/IPLFont.h @@ -0,0 +1,76 @@ +/** + * Wii64 - IPLFont.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef IPLFONT_H +#define IPLFONT_H + +#include "GuiTypes.h" + +namespace menu { + +class IplFont +{ +public: + void setVmode(GXRModeObj *rmode); + void drawInit(GXColor fontColor); + void setColor(GXColor fontColor); + void setColor(GXColor* fontColorPtr); + void drawString(int x, int y, char *string, float scale, bool centered); + int drawStringWrap(int x, int y, char *string, float scale, bool centered, int maxWidth, int lineSpacing); + void drawStringAtOrigin(char *string, float scale); + int getStringWidth(char *string, float scale); + int getStringHeight(char *string, float scale); + static IplFont& getInstance() + { + static IplFont obj; + return obj; + } + +private: + IplFont(); + ~IplFont(); + void initFont(); + #ifndef WII + void setIplConfig(unsigned char c); + #endif + void decodeYay0(void *src, void *dst); + void convertI2toI4(void *dst, void *src, int xres, int yres); + + typedef struct { + u16 s[256], t[256], font_size[256], fheight; + } CHAR_INFO; + +#ifdef HW_RVL + unsigned char *fontFont; +#else //GC + unsigned char fontFont[ 0x40000 ] __attribute__((aligned(32))); +#endif + + u16 frameWidth; + CHAR_INFO fontChars; + GXTexObj fontTexObj; + GXRModeObj *vmode; + GXColor fontColor; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/IPLFontC.h b/Gamecube/libgui/IPLFontC.h new file mode 100644 index 0000000..084c6f4 --- /dev/null +++ b/Gamecube/libgui/IPLFontC.h @@ -0,0 +1,13 @@ +/***************************************************************************** + * font.h - C functions to call IPLFont singleton class + *****************************************************************************/ +#ifdef __cplusplus +extern "C" { +#endif + +void IplFont_drawInit(GXColor fontColor); +void IplFont_drawString(int x, int y, char *string, float scale, bool centered); + +#ifdef __cplusplus +} +#endif diff --git a/Gamecube/libgui/Image.cpp b/Gamecube/libgui/Image.cpp new file mode 100644 index 0000000..da6bcb4 --- /dev/null +++ b/Gamecube/libgui/Image.cpp @@ -0,0 +1,60 @@ +/** + * Wii64 - Image.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Image.h" + +namespace menu { + +Image::Image(void* texture, u16 wd, u16 ht, u8 fmt, u8 wrap_s, u8 wrap_t, u8 mipmap) + : img_ptr(texture), + tlut_ptr(0), + width(wd), + height(ht), + format(fmt), + tlut_format(0) +{ + GX_InitTexObj(&obj, img_ptr, width, height, format, wrap_s, wrap_t, mipmap); +} + +Image::Image(void* texture, u16 wd, u16 ht, u8 fmt, u8 wrap_s, u8 wrap_t, u8 mipmap, void* lut, u8 lut_fmt, u8 lut_name, u16 lut_size) + : img_ptr(texture), + tlut_ptr(lut), + width(wd), + height(ht), + format(fmt), + tlut_format(lut_fmt), + tlut_name(lut_name), + tlut_size(lut_size) +{ + GX_InitTlutObj(&tlut_obj, tlut_ptr, tlut_format, tlut_size); + GX_InitTexObjCI(&obj, img_ptr, width, height, format, wrap_s, wrap_t, mipmap, tlut_name); +} + +Image::~Image() +{ +} + +void Image::activateImage(u8 mapid) +{ + if (tlut_ptr) GX_LoadTlut(&tlut_obj, tlut_name); + GX_LoadTexObj(&obj, mapid); +} + +} //namespace menu diff --git a/Gamecube/libgui/Image.h b/Gamecube/libgui/Image.h new file mode 100644 index 0000000..6767214 --- /dev/null +++ b/Gamecube/libgui/Image.h @@ -0,0 +1,49 @@ +/** + * Wii64 - Image.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef IMAGE_H +#define IMAGE_H + +#include "GuiTypes.h" + +namespace menu { + +class Image +{ +public: + Image(void* texture, u16 wd, u16 ht, u8 fmt, u8 wrap_s, u8 wrap_t, u8 mipmap); + Image(void* texture, u16 wd, u16 ht, u8 fmt, u8 wrap_s, u8 wrap_t, u8 mipmap, void* lut, u8 lut_fmt, u8 lut_name, u16 lut_size); + ~Image(); + void activateImage(u8 mapid); + +private: + GXTexObj obj; + GXTlutObj tlut_obj; + void *img_ptr; + void *tlut_ptr; + u16 width, height; + u8 format, tlut_format, tlut_name; + u16 tlut_size; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/InputManager.cpp b/Gamecube/libgui/InputManager.cpp new file mode 100644 index 0000000..3e7dc21 --- /dev/null +++ b/Gamecube/libgui/InputManager.cpp @@ -0,0 +1,93 @@ +/** + * Wii64 - InputManager.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "InputManager.h" +#include "FocusManager.h" +#include "CursorManager.h" +#include "../gc_input/controller.h" + +void ShutdownWii(); + + + +namespace menu { + +Input::Input() +{ + PAD_Init(); +#ifdef HW_RVL + CONF_Init(); + WUPC_Init(); + WPAD_Init(); + WPAD_SetIdleTimeout(120); + WPAD_SetVRes(WPAD_CHAN_ALL, 640, 480); + WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR); + WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownWii); + SYS_SetPowerCallback(ShutdownWii); + +#endif +// VIDEO_SetPostRetraceCallback (PAD_ScanPads); +} + +Input::~Input() +{ +#ifdef HW_RVL + WUPC_Shutdown(); + WPAD_Shutdown(); +#endif +} + +void Input::refreshInput() +{ + if(padNeedScan){ gc_connected = PAD_ScanPads(); padNeedScan = 0; } + PAD_Read(gcPad); + PAD_Clamp(gcPad); +#ifdef HW_RVL + if (wpadNeedScan){ WUPC_UpdateButtonStats(); WPAD_ScanPads(); wpadNeedScan = 0; } +// WPAD_ScanPads(); + wiiPad = WPAD_Data(0); + wupcData = WUPC_Data(0); +#endif +} + +#ifdef HW_RVL +WPADData* Input::getWpad() +{ + return wiiPad; +} + +WUPCData* Input::getWupc() +{ + return wupcData; +} +#endif + +PADStatus* Input::getPad() +{ + return &gcPad[0]; +} + +void Input::clearInputData() +{ + Focus::getInstance().clearInputData(); + Cursor::getInstance().clearInputData(); +} + +} //namespace menu diff --git a/Gamecube/libgui/InputManager.h b/Gamecube/libgui/InputManager.h new file mode 100644 index 0000000..5c205c2 --- /dev/null +++ b/Gamecube/libgui/InputManager.h @@ -0,0 +1,57 @@ +/** + * Wii64 - InputManager.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef INPUTMANAGER_H +#define INPUTMANAGER_H + +#include "GuiTypes.h" + +namespace menu { + +class Input +{ +public: + void refreshInput(); +#ifdef HW_RVL + WPADData* getWpad(); + WUPCData* getWupc(); +#endif + PADStatus* getPad(); + void clearInputData(); + static Input& getInstance() + { + static Input obj; + return obj; + } + +private: + Input(); + ~Input(); + PADStatus gcPad[4]; +#ifdef HW_RVL + WPADData *wiiPad; + WUPCData *wupcData; +#endif + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/InputStatusBar.cpp b/Gamecube/libgui/InputStatusBar.cpp new file mode 100644 index 0000000..66fd0e8 --- /dev/null +++ b/Gamecube/libgui/InputStatusBar.cpp @@ -0,0 +1,380 @@ +/** + * WiiSX - InputStatusBar.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "InputStatusBar.h" +#include "GuiResources.h" +#include "GraphicsGX.h" +#include "IPLFont.h" +#include "Image.h" +#include "FocusManager.h" +#include +#include + +extern "C" { +#include "../gc_input/controller.h" +//#include "../main/rom.h" +} +#include "../../psxcommon.h" + +namespace menu { + +InputStatusBar::InputStatusBar(float x, float y) + : x(x), + y(y) +/* : active(false), + selected(false), + normalImage(0), + focusImage(0), + selectedImage(0), + selectedFocusImage(0), + buttonText(label), + buttonStyle(style), + labelMode(LABEL_CENTER), + labelScissor(0), + StartTime(0), + x(x), + y(y), + width(width), + height(height), + clickedFunc(0), + returnFunc(0)*/ +{ + //Focus color Inactive color Active color Selected color Label color +// GXColor colors[5] = {{255, 100, 100, 255}, {255, 255, 255, 70}, {255, 255, 255, 130}, {255, 255, 255, 255}, {255, 255, 255, 255}}; + +} + +InputStatusBar::~InputStatusBar() +{ +} + +extern "C" BOOL hasLoadedISO; +extern "C" char autoSave; +extern "C" char CdromLabel[33]; +extern "C" char mcd1Written; +extern "C" char mcd2Written; + +void InputStatusBar::drawComponent(Graphics& gfx) +{ + int box_x = 50; + int box_y = 0; + int width = 235; + int height = 340; + int labelScissor = 5; + GXColor activeColor = (GXColor) {255, 255, 255, 255}; + GXColor inactiveColor = (GXColor) {192, 192, 192, 192}; +// GXColor controllerColors[5] = { { 1, 29, 169, 255}, //blue +// {229, 29, 19, 255}, //orange/red +// { 8, 147, 48, 255}, //green +// {255, 192, 1, 255}, //yellow/gold +// {150, 150, 255, 255}}; +// char statusText[50]; + Image* statusIcon = NULL; + //Draw Status Info Box + GXColor boxColor = (GXColor) {87, 90, 100,128}; + gfx.setTEV(GX_PASSCLR); + gfx.enableBlending(true); + gfx.setColor(boxColor); + gfx.fillRect(box_x, box_y, width, height); + //Write ROM Status Info + gfx.enableScissor(box_x + labelScissor, box_y, width - 2*labelScissor, height); + char buffer [51]; + int text_y = 100; + if(!hasLoadedISO) + { + IplFont::getInstance().drawInit(activeColor); + sprintf(buffer,"No ISO Loaded"); + IplFont::getInstance().drawString((int) box_x + 15, (int) text_y, buffer, 0.8, false); + } + else + { + IplFont::getInstance().drawInit(activeColor); + sprintf(buffer,"%s",CdromLabel); + IplFont::getInstance().drawString((int) box_x + 15, (int) text_y, buffer, 0.8, false); + text_y += 20*IplFont::getInstance().drawStringWrap((int) box_x + 15, (int) text_y, buffer, 0.8, false, width - 2*15, 20); + sprintf(buffer,"%s",(!Config.PsxType) ? "NTSC":"PAL"); + text_y += 13; + IplFont::getInstance().drawString((int) box_x + 15, (int) text_y, buffer, 0.7, false); + if (autoSave) + sprintf(buffer,"AutoSave Enabled"); + else if (!mcd1Written && !mcd2Written) + sprintf(buffer,"Nothing to Save"); + else + sprintf(buffer,"Game Needs Saving"); + text_y += 25; + IplFont::getInstance().drawString((int) box_x + 15, (int) text_y, buffer, 0.7, false); + } + gfx.disableScissor(); + //Update controller availability + for (int i = 0; i < 2; i++) + { + switch (padType[i]) + { + case PADTYPE_GAMECUBE: + controller_GC.available[(int)padAssign[i]] = (gc_connected & (1<activateImage(GX_TEXMAP0); + GX_SetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_RASC); + GX_SetTevColorOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + GX_SetTevAlphaIn(GX_TEVSTAGE0,GX_CA_ZERO,GX_CA_RASA,GX_CA_TEXA,GX_CA_ZERO); + GX_SetTevAlphaOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + gfx.enableBlending(true); + gfx.drawImage(0, base_x, base_y, 48, 64, 0, 1, 0, 1); + } + + //draw logo + Resources::getInstance().getImage(Resources::IMAGE_LOGO)->activateImage(GX_TEXMAP0); + gfx.setTEV(GX_REPLACE); + gfx.enableBlending(true); +#ifdef HW_RVL + gfx.drawImage(0, 75, 380, 136, 52, 0, 1, 0, 1); +#else + gfx.drawImage(0, 75, 380, 176, 52, 0, 1, 0, 1); +#endif + gfx.setTEV(GX_PASSCLR); + +/* +// printf("Button drawComponent\n"); + + gfx.setColor(inactiveColor); + + //activate relevant texture + if(active) + { + //draw normalImage with/without gray mask and with alpha test on + //printf("Button Active\n"); + gfx.setColor(activeColor); + } + if(getFocus()) + { + //draw focus indicator (extra border for button?) + //printf("Button in Focus\n"); + gfx.setColor(focusColor); + } + //draw buttonLabel? + + gfx.enableBlending(true); +// gfx.setTEV(GX_PASSCLR); + gfx.setTEV(GX_MODULATE); + +// gfx.setColor(focusColor); + gfx.setDepth(-10.0f); + gfx.newModelView(); + gfx.loadModelView(); + gfx.loadOrthographic(); + + switch (buttonStyle) + { + case BUTTON_DEFAULT: +// gfx.fillRect(x, y, width, height); + normalImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); +// gfx.drawImage(0, x, y, width, height, 0.0, 1.0, 0.0, 1.0); + + if (selected) + { + gfx.setColor(selectedColor); + if(selectedImage) selectedImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + } + break; + case BUTTON_STYLEA_NORMAL: + if (getFocus()) focusImage->activateImage(GX_TEXMAP0); + else normalImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height, 0.0, width/8.0, 0.0, 1.0); + gfx.drawImage(0, x+width/2, y, width/2, height, width/8.0, 0.0, 0.0, 1.0); + break; + case BUTTON_STYLEA_SELECT: + if (selected) + { + if (getFocus()) selectedFocusImage->activateImage(GX_TEXMAP0); + else selectedImage->activateImage(GX_TEXMAP0); + } + else + { + if (getFocus()) focusImage->activateImage(GX_TEXMAP0); + else normalImage->activateImage(GX_TEXMAP0); + } + gfx.drawImage(0, x, y, width/2, height, 0.0, width/8.0, 0.0, 1.0); + gfx.drawImage(0, x+width/2, y, width/2, height, width/8.0, 0.0, 0.0, 1.0); + break; + } + + if (buttonText) + { + int strWidth, strHeight; + unsigned long CurrentTime; + float scrollWidth, time_sec, scrollOffset; + gfx.enableScissor(x + labelScissor, y, width - 2*labelScissor, height); + if(active) IplFont::getInstance().drawInit(labelColor); + else IplFont::getInstance().drawInit(inactiveColor); + switch (labelMode) + { + case LABEL_CENTER: + IplFont::getInstance().drawString((int) (x+width/2), (int) (y+height/2), *buttonText, 1.0, true); + break; + case LABEL_LEFT: + strWidth = IplFont::getInstance().getStringWidth(*buttonText, 1.0); + strHeight = IplFont::getInstance().getStringHeight(*buttonText, 1.0); + IplFont::getInstance().drawString((int) (x+labelScissor), (int) (y+(height-strHeight)/2), *buttonText, 1.0, false); + break; + case LABEL_SCROLL: + strHeight = IplFont::getInstance().getStringHeight(*buttonText, 1.0); + scrollWidth = IplFont::getInstance().getStringWidth(*buttonText, 1.0)-width+2*labelScissor; + scrollWidth = scrollWidth < 0.0f ? 0.0 : scrollWidth; + CurrentTime = ticks_to_microsecs(gettick()); + time_sec = (float)(CurrentTime - StartTime)/1000000.0f; + if (time_sec > SCROLL_PERIOD) StartTime = ticks_to_microsecs(gettick()); + scrollOffset = fabsf(fmodf(time_sec,SCROLL_PERIOD)-SCROLL_PERIOD/2)/(SCROLL_PERIOD/2); + IplFont::getInstance().drawString((int) (x+labelScissor-(int)(scrollOffset*scrollWidth)), (int) (y+(height-strHeight)/2), *buttonText, 1.0, false); + break; + case LABEL_SCROLLONFOCUS: + if(getFocus()) + { + strHeight = IplFont::getInstance().getStringHeight(*buttonText, 1.0); + scrollWidth = IplFont::getInstance().getStringWidth(*buttonText, 1.0)-width+2*labelScissor; + scrollWidth = scrollWidth < 0.0f ? 0.0 : scrollWidth; + CurrentTime = ticks_to_microsecs(gettick()); + time_sec = (float)(CurrentTime - StartTime)/1000000.0f; + if (time_sec > SCROLL_PERIOD) StartTime = ticks_to_microsecs(gettick()); + scrollOffset = fabsf(fmodf(time_sec,SCROLL_PERIOD)-SCROLL_PERIOD/2)/(SCROLL_PERIOD/2); + IplFont::getInstance().drawString((int) (x+labelScissor-(int)(scrollOffset*scrollWidth)), (int) (y+(height-strHeight)/2), *buttonText, 1.0, false); + } + else + { + strWidth = IplFont::getInstance().getStringWidth(*buttonText, 1.0); + strHeight = IplFont::getInstance().getStringHeight(*buttonText, 1.0); + IplFont::getInstance().drawString((int) (x+labelScissor), (int) (y+(height-strHeight)/2), *buttonText, 1.0, false); + } + break; + } + gfx.disableScissor(); + } +*/ +} + +void InputStatusBar::updateTime(float deltaTime) +{ + //Overload in Component class + //Add interpolator class & update here? +} + +Component* InputStatusBar::updateFocus(int direction, int buttonsPressed) +{ + return NULL; +} + +} //namespace menu diff --git a/Gamecube/libgui/InputStatusBar.h b/Gamecube/libgui/InputStatusBar.h new file mode 100644 index 0000000..23b5358 --- /dev/null +++ b/Gamecube/libgui/InputStatusBar.h @@ -0,0 +1,53 @@ +/** + * Wii64 - InputStatusBar.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef INPUTSTATUSBAR_H +#define INPUTSTATUSBAR_H + +//#include "GuiTypes.h" +#include "Component.h" + +namespace menu { + +class InputStatusBar : public Component +{ +public: + InputStatusBar(float x, float y); + ~InputStatusBar(); + void updateTime(float deltaTime); + void drawComponent(Graphics& gfx); + Component* updateFocus(int direction, int buttonsPressed); + +private: +/* Image *normalImage; + Image *focusImage; + Image *selectedImage; + Image *selectedFocusImage; + char** buttonText; + int buttonStyle, labelMode, labelScissor; + unsigned long StartTime;*/ + float x, y;/*, width, height; + GXColor focusColor, inactiveColor, activeColor, selectedColor, labelColor;*/ + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/LoadingBar.cpp b/Gamecube/libgui/LoadingBar.cpp new file mode 100644 index 0000000..570daae --- /dev/null +++ b/Gamecube/libgui/LoadingBar.cpp @@ -0,0 +1,140 @@ +/** + * Wii64 - LoadingBar.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "LoadingBar.h" +#include "GraphicsGX.h" +#include "GuiResources.h" +#include "resources.h" +#include "CursorManager.h" +#include "FocusManager.h" +#include "IPLFont.h" +#include +#include + +namespace menu { + +#define LOADINGBAR_TEXT_WIDTH 100 +char loadingBarText[LOADINGBAR_TEXT_WIDTH]; + +LoadingBar::LoadingBar() + : buttonImage(0), + buttonFocusImage(0), + loadingBarActive(false), + currentCursorFrame(0), + currentFocusFrame(0), + percentComplete(0.0f) +{ + buttonImage = Resources::getInstance().getImage(Resources::IMAGE_DEFAULT_BUTTON); + buttonFocusImage = Resources::getInstance().getImage(Resources::IMAGE_DEFAULT_BUTTONFOCUS); + + showFrame(); + + boxColor = (GXColor) {100, 100, 100, 210}; + backColor = (GXColor) {0, 0, 0, 210}; +// barColor = (GXColor) {255, 100, 100, 255}; + barColor = (GXColor) {104, 125, 205, 210}; + textColor = (GXColor) {255, 255, 255, 255}; + +} + +LoadingBar::~LoadingBar() +{ +} + +void LoadingBar::showBar(float percent, const char* string) +{ + loadingBarActive = true; + currentCursorFrame = Cursor::getInstance().getCurrentFrame(); + Cursor::getInstance().setCurrentFrame(NULL); + currentFocusFrame = Focus::getInstance().getCurrentFrame(); + Focus::getInstance().setCurrentFrame(NULL); + percentComplete = percent; + //memset(loadingBarText, 0, LOADINGBAR_TEXT_WIDTH); + strncpy(loadingBarText, string, LOADINGBAR_TEXT_WIDTH); + loadingBarText[LOADINGBAR_TEXT_WIDTH - 1] = '\0'; + + menu::Gui::getInstance().draw(); + + loadingBarActive = false; + if (currentCursorFrame) Cursor::getInstance().setCurrentFrame(currentCursorFrame); + currentCursorFrame = NULL; + if (currentFocusFrame) Focus::getInstance().setCurrentFrame(currentFocusFrame); + currentFocusFrame = NULL; +} + +bool LoadingBar::getActive() +{ + return loadingBarActive; +} + +void LoadingBar::drawLoadingBar(Graphics& gfx) +{ + gfx.setColor(boxColor); + + gfx.enableBlending(true); + gfx.setTEV(GX_MODULATE); + + gfx.setDepth(-10.0f); + gfx.newModelView(); + gfx.loadModelView(); + gfx.loadOrthographic(); + + //draw box + float x = 120; float y = 160; float width = 400; float height = 150; + buttonImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + + //draw bar background + gfx.setColor(backColor); + x = 140; y = 245; width = 360; height = 30; + buttonImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + + //draw bar + gfx.setColor(barColor); + x = 140; y = 245; width = 360*percentComplete; height = 30; + buttonImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + + //draw text 'box' + x = 120; y = 200; width = 400; height = 40; + IplFont::getInstance().drawInit(textColor); + IplFont::getInstance().drawString((int) (x+width/2), (int) (y+height/2), loadingBarText, 0.9, true); +} + +extern "C" { + void LoadingBar_showBar(float percent, const char* string); +} + +void LoadingBar_showBar(float percent, const char* string) +{ + LoadingBar::getInstance().showBar(percent, string); +} + +} //namespace menu diff --git a/Gamecube/libgui/LoadingBar.h b/Gamecube/libgui/LoadingBar.h new file mode 100644 index 0000000..6cbbae5 --- /dev/null +++ b/Gamecube/libgui/LoadingBar.h @@ -0,0 +1,60 @@ +/** + * Wii64 - LoadingBar.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef LOADINGBAR_H +#define LOADINGBAR_H + +#include "Frame.h" +#include "Button.h" +#include "Image.h" +#include "Gui.h" +#include "GuiTypes.h" + +namespace menu { + +class LoadingBar : public Frame +{ +public: + void showBar(float percent, const char* text); + bool getActive(); + void drawLoadingBar(Graphics& gfx); + + static LoadingBar& getInstance() + { + static LoadingBar obj; + return obj; + } + +private: + LoadingBar(); + ~LoadingBar(); + Image *buttonImage; + Image *buttonFocusImage; + bool loadingBarActive; + Frame *currentCursorFrame; + Frame *currentFocusFrame; + float percentComplete; + GXColor boxColor, backColor, barColor, textColor; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/Logo.cpp b/Gamecube/libgui/Logo.cpp new file mode 100644 index 0000000..f6720c2 --- /dev/null +++ b/Gamecube/libgui/Logo.cpp @@ -0,0 +1,316 @@ +/** + * WiiSX - Logo.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "Logo.h" +#include "GraphicsGX.h" +#include +#include "ogc/lwp_watchdog.h" + +namespace menu { + +#define LOGO_P_X0 0 +#define LOGO_P_X1 1 +#define LOGO_P_X2 9 +#define LOGO_P_X25 10 +#define LOGO_P_X3 11 +#define LOGO_P_X4 19 +#define LOGO_P_Y1 10 +#define LOGO_P_Y2 19 +#define LOGO_P_Z1 5 +#define LOGO_P_Z2 15 + +// 'P' logo vertex data +s8 P_verts[] ATTRIBUTE_ALIGN (32) = +{ // x y z + LOGO_P_X1, -LOGO_P_Y2, -LOGO_P_Z2, // 0 (P, XZ plane, Y=-LOGO_P_Y2) + LOGO_P_X2, -LOGO_P_Y2, -LOGO_P_Z2, // 1 5 6 + LOGO_P_X3, -LOGO_P_Y2, -LOGO_P_Z1, // 2 3 4 + LOGO_P_X2, -LOGO_P_Y2, LOGO_P_Z1, // 3 2 + LOGO_P_X3, -LOGO_P_Y2, LOGO_P_Z1, // 4 0 1 + LOGO_P_X1, -LOGO_P_Y2, LOGO_P_Z2, // 5 + LOGO_P_X3, -LOGO_P_Y2, LOGO_P_Z2, // 6 + + LOGO_P_X1, -LOGO_P_Y2, -LOGO_P_Z2, // 7 (S, XY plane, Z=-LOGO_P_Z2) + LOGO_P_X2, -LOGO_P_Y2, -LOGO_P_Z2, // 8 21 22 + -LOGO_P_X4, -LOGO_P_Y1, -LOGO_P_Z2, // 9 15 16 17 18 19 20 + -LOGO_P_X3, -LOGO_P_Y1, -LOGO_P_Z2, // 10 + -LOGO_P_X2, -LOGO_P_Y1, -LOGO_P_Z2, // 11 9 10 11 12 13 14 + -LOGO_P_X1, -LOGO_P_Y1, -LOGO_P_Z2, // 12 7 8 + LOGO_P_X1, -LOGO_P_Y1, -LOGO_P_Z2, // 13 + LOGO_P_X2, -LOGO_P_Y1, -LOGO_P_Z2, // 14 + -LOGO_P_X4, LOGO_P_Y1, -LOGO_P_Z2, // 15 + -LOGO_P_X3, LOGO_P_Y1, -LOGO_P_Z2, // 16 + -LOGO_P_X2, LOGO_P_Y1, -LOGO_P_Z2, // 17 + -LOGO_P_X1, LOGO_P_Y1, -LOGO_P_Z2, // 18 + LOGO_P_X1, LOGO_P_Y1, -LOGO_P_Z2, // 19 + LOGO_P_X2, LOGO_P_Y1, -LOGO_P_Z2, // 20 + -LOGO_P_X4, LOGO_P_Y2, -LOGO_P_Z2, // 21 + -LOGO_P_X3, LOGO_P_Y2, -LOGO_P_Z2, // 22 + + -LOGO_P_X25,-LOGO_P_Y1, -LOGO_P_Z2, // 23 Yellow band center + -LOGO_P_X0, LOGO_P_Y1, -LOGO_P_Z2, // 24 Blue band center +}; + +// N64 logo color data +u8 logo_colors[] ATTRIBUTE_ALIGN (32) = +{ // r, g, b, a + //'P' logo colors + 8, 147, 48, 255, // 0 green + 1, 29, 169, 255, // 1 blue + 254, 32, 21, 255, // 2 orange/red + 255, 192, 1, 255, // 3 yellow/gold +}; + +#define LOGO_MODE_MAX 1 + +Logo::Logo() + : x(0), + y(0), + z(0), + size(1), + rotateAuto(0), + rotateX(0), + rotateY(0) +{ + setVisible(false); + srand ( gettick() ); + logoMode = rand() % LOGO_MODE_MAX; +} + +Logo::~Logo() +{ +} + +void Logo::setLocation(float newX, float newY, float newZ) +{ + x = newX; + y = newY; + z = newZ; +} + +void Logo::setSize(float newSize) +{ + size = newSize; +} + +void Logo::setMode(int mode) +{ + logoMode = mode; +} + +void Logo::updateTime(float deltaTime) +{ + //Overload in Component class + //Add interpolator class & update here? +} + +void Logo::drawComponent(Graphics& gfx) +{ + Mtx v, m, mv, tmp; // view, model, modelview, and perspective matrices + guVector cam = { 0.0F, 0.0F, 0.0F }, + up = { 0.0F, 1.0F, 0.0F}, + look = { 0.0F, 0.0F,-1.0F}, + axisX = { 1.0F, 0.0F, 0.0F}, + axisXm= {-1.0F, 0.0F, 0.0F}, + axisY = { 0.0F, 1.0F, 0.0F}, + axisYm= { 0.0F,-1.0F, 0.0F}, + axisZ = { 0.0F, 0.0F, 1.0F}, + axisZm= { 0.0F, 0.0F,-1.0F}; + s8 stickX,stickY; + guVector center; + + guLookAt (v, &cam, &up, &look); + rotateAuto++; + + u16 pad0 = PAD_ButtonsDown(0); + if (pad0 & PAD_TRIGGER_Z) logoMode = (logoMode+1) % LOGO_MODE_MAX; + + //libOGC was changed such that sticks are now clamped and don't have to be by us + stickX = PAD_SubStickX(0); + stickY = PAD_SubStickY(0); +// if(stickX > 18 || stickX < -18) rotateX += stickX/32; +// if(stickY > 18 || stickY < -18) rotateY += stickY/32; + rotateX += stickX/32; + rotateY += stickY/32; + + // move the logo out in front of us and rotate it + guMtxIdentity (m); + + guMtxRotAxisDeg (tmp, &axisX, 115); //change to isometric view + guMtxConcat (m, tmp, m); + guMtxRotAxisDeg (tmp, &axisX, -rotateY); + guMtxConcat (m, tmp, m); + guMtxRotAxisDeg (tmp, &axisZ, -29); //change to isometric view + guMtxConcat (m, tmp, m); + guMtxRotAxisDeg (tmp, &axisZ, rotateX); + guMtxConcat (m, tmp, m); + guMtxRotAxisDeg (tmp, &axisZ, -rotateAuto); //slowly rotate logo + guMtxConcat (m, tmp, m); + guMtxScale (tmp, 1.5f, 1.0f, 2.0f); + guMtxConcat (m, tmp, m); + + guMtxTransApply (m, m, x, y, z); + guMtxConcat (v, m, mv); + // load the modelview matrix into matrix memory + GX_LoadPosMtxImm (mv, GX_PNMTX0); + + GX_SetCullMode (GX_CULL_NONE); // show both sides of quads + GX_SetZMode(GX_ENABLE,GX_GEQUAL,GX_TRUE); + + GX_SetLineWidth(8,GX_TO_ZERO); + + // setup the vertex descriptor + GX_ClearVtxDesc (); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc (GX_VA_POS, GX_INDEX8); + GX_SetVtxDesc (GX_VA_CLR0, GX_INDEX8); + + // setup the vertex attribute table + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S8, 0); + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + // set the array stride + if(logoMode == LOGO_P) GX_SetArray (GX_VA_POS, P_verts, 3 * sizeof (s8)); + GX_SetArray (GX_VA_CLR0, logo_colors, 4 * sizeof (u8)); + + GX_SetNumChans (1); + GX_SetNumTexGens (0); + GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GX_SetTevOp (GX_TEVSTAGE0, GX_PASSCLR); + + if (logoMode == LOGO_P) + { + // 'P' + GX_Begin (GX_QUADS, GX_VTXFMT0, 28); //7 quads, so 28 verts + drawQuad ( 0, 5, 3, 1, 2); //Side P, red + drawQuad ( 5, 6, 4, 3, 2); + drawQuad ( 7, 13, 14, 8, 3); //Side S, yellow + drawQuad ( 9, 15, 16, 10, 0); //Side S, green + drawQuad (11, 17, 18, 12, 0); + drawQuad (13, 19, 20, 14, 0); + drawQuad (15, 21, 22, 16, 1); //Side S, blue + GX_End (); + + // setup the vertex descriptor + GX_ClearVtxDesc (); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc (GX_VA_CLR0, GX_INDEX8); + // setup the vertex attribute table + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); + GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + + center = (guVector){(float)P_verts[4*3+0], (float)P_verts[4*3+1], (float)P_verts[4*3+2]}; + drawBand(center, axisZm, axisX, 0.0f, 10.0f, 180.0f, 7, 2); + center = (guVector){(float)P_verts[23*3+0], (float)P_verts[23*3+1], (float)P_verts[23*3+2]}; + drawBand(center, axisXm, axisYm, 1.0f, 9.0f, 180.0f, 7, 3); + center = (guVector){(float)P_verts[24*3+0], (float)P_verts[24*3+1], (float)P_verts[24*3+2]}; + drawBand(center, axisX, axisY, 1.0f, 9.0f, 180.0f, 7, 1); + } + + //Reset GX state: + GX_SetLineWidth(6,GX_TO_ZERO); + gfx.drawInit(); +} + +void Logo::drawQuad(u8 v0, u8 v1, u8 v2, u8 v3, u8 c) +{ + // draws a quad from 4 vertex idx and one color idx + // one 8bit position idx + GX_Position1x8 (v0); + // one 8bit color idx + GX_Color1x8 (c); + GX_Position1x8 (v1); + GX_Color1x8 (c); + GX_Position1x8 (v2); + GX_Color1x8 (c); + GX_Position1x8 (v3); + GX_Color1x8 (c); +} + +/* +void Logo::drawLine(u8 v0, u8 v1, u8 c) +{ + // draws a line from 2 vertex idx and one color idx + // one 8bit position idx + GX_Position1x8 (v0); + // one 8bit color idx + GX_Color1x8 (c); + GX_Position1x8 (v1); + GX_Color1x8 (c); +} +*/ + +#ifndef PI +#define PI 3.14159f +#endif + +void Logo::drawBand(guVector center, guVector axis1, guVector axis2, float radius1, float radius2, float thetaMax, int numSegments, u8 c) +{ + guVector vec0, vec1, vec2, vec3, tmp; + + GX_Begin (GX_QUADS, GX_VTXFMT0, numSegments*4); //numSegs quads + for (int i=0; isetNextFocus(Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_MessageBoxCancel); + setEnabled(true); + + showFrame(); + boxColor = (GXColor) {100, 100, 100, 210}; + textColor = (GXColor) {255, 255, 255, 255}; + +} + +MessageBox::~MessageBox() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } +} + +void MessageBox::setMessage(const char* string) +{ + if (messageFade > 0.0f) messageFade = 0.0f; + messageBoxActive = true; + FRAME_BUTTONS[0].button->setVisible(true); + FRAME_BUTTONS[0].button->setActive(true); + FRAME_BUTTONS[1].button->setVisible(false); + FRAME_BUTTONS[1].button->setActive(false); + FRAME_BUTTONS[2].button->setVisible(false); + FRAME_BUTTONS[2].button->setActive(false); + setDefaultFocus(FRAME_BUTTONS[0].button); + + currentCursorFrame = Cursor::getInstance().getCurrentFrame(); + Cursor::getInstance().setCurrentFrame(this); + currentFocusFrame = Focus::getInstance().getCurrentFrame(); + Focus::getInstance().setCurrentFrame(this); + //memset(messageBoxText, 0, MESSAGEBOX_TEXT_WIDTH); + strncpy(messageBoxText, string, MESSAGEBOX_TEXT_WIDTH); + messageBoxText[MESSAGEBOX_TEXT_WIDTH - 1] = '\0'; + + while (messageBoxActive) + menu::Gui::getInstance().draw(); +// Input::getInstance().clearInputData(); +} + +int MessageBox::askMessage(const char* string) +{ + if (messageFade > 0.0f) messageFade = 0.0f; + messageBoxActive = true; + FRAME_BUTTONS[0].button->setVisible(false); + FRAME_BUTTONS[0].button->setActive(false); + FRAME_BUTTONS[1].button->setVisible(true); + FRAME_BUTTONS[1].button->setActive(true); + FRAME_BUTTONS[2].button->setVisible(true); + FRAME_BUTTONS[2].button->setActive(true); + setDefaultFocus(FRAME_BUTTONS[2].button); + + currentCursorFrame = Cursor::getInstance().getCurrentFrame(); + Cursor::getInstance().setCurrentFrame(this); + currentFocusFrame = Focus::getInstance().getCurrentFrame(); + Focus::getInstance().setCurrentFrame(this); + //memset(messageBoxText, 0, MESSAGEBOX_TEXT_WIDTH); + strncpy(messageBoxText, string, MESSAGEBOX_TEXT_WIDTH); + messageBoxText[MESSAGEBOX_TEXT_WIDTH - 1] = '\0'; + + setReturnValue(0); + while (messageBoxActive) + menu::Gui::getInstance().draw(); +// Input::getInstance().clearInputData(); + return getReturnValue(); +} + +void MessageBox::fadeMessage(const char* string) +{ + messageBoxActive = true; + FRAME_BUTTONS[0].button->setVisible(false); + FRAME_BUTTONS[0].button->setActive(false); + FRAME_BUTTONS[1].button->setVisible(false); + FRAME_BUTTONS[1].button->setActive(false); + FRAME_BUTTONS[2].button->setVisible(false); + FRAME_BUTTONS[2].button->setActive(false); + setDefaultFocus(this); + +// currentCursorFrame = Cursor::getInstance().getCurrentFrame(); +// Cursor::getInstance().setCurrentFrame(this); +// currentFocusFrame = Focus::getInstance().getCurrentFrame(); +// Focus::getInstance().setCurrentFrame(this); + //memset(messageBoxText, 0, MESSAGEBOX_TEXT_WIDTH); + strncpy(messageBoxText, string, MESSAGEBOX_TEXT_WIDTH); + messageBoxText[MESSAGEBOX_TEXT_WIDTH - 1] = '\0'; + + messageFade = 1.0f; + +// while (messageBoxActive) +// menu::Gui::getInstance().draw(); +// Input::getInstance().clearInputData(); +} + +void MessageBox::setReturnValue(int returnVal) +{ + returnValue = returnVal; +} + +int MessageBox::getReturnValue() +{ + return returnValue; +} + +void MessageBox::deactivate() +{ + messageBoxActive = false; + if (currentCursorFrame) Cursor::getInstance().setCurrentFrame(currentCursorFrame); + currentCursorFrame = NULL; + Focus::getInstance().clearPrimaryFocus(); + if (currentFocusFrame) Focus::getInstance().setCurrentFrame(currentFocusFrame); + currentFocusFrame = NULL; +} + +bool MessageBox::getActive() +{ + return messageBoxActive; +} + +void MessageBox::drawMessageBox(Graphics& gfx) +{ + GXColor tmpBoxColor = boxColor; + GXColor tmpTextColor = textColor; + float x = 40; float y = 60; float width = 560; float height = 360; + if (messageFade > 0.0f) + { + tmpBoxColor.a = tmpBoxColor.a*messageFade; + tmpTextColor.a = tmpTextColor.a*messageFade; + y = 140; + height = 200; + messageFade -= 0.01f; + if (!(messageFade > 0.0f)) messageBoxActive = false; + } + + gfx.setColor(tmpBoxColor); + + gfx.enableBlending(true); + gfx.setTEV(GX_MODULATE); + + gfx.setDepth(-10.0f); + gfx.newModelView(); + gfx.loadModelView(); + gfx.loadOrthographic(); + + buttonImage->activateImage(GX_TEXMAP0); + gfx.drawImage(0, x, y, width/2, height/2, 0.0, width/16.0, 0.0, height/16.0); + gfx.drawImage(0, x+width/2, y, width/2, height/2, width/16.0, 0.0, 0.0, height/16.0); + gfx.drawImage(0, x, y+height/2, width/2, height/2, 0.0, width/16.0, height/16.0, 0.0); + gfx.drawImage(0, x+width/2, y+height/2, width/2, height/2, width/16.0, 0.0, height/16.0, 0.0); + + //detect number of lines +#define MAX_LINES 12 + int ind = 0; + int numLines = 0; + int lineStart[MAX_LINES]; + int lineEnd[MAX_LINES]; + lineStart[numLines] = ind; + while (1) + { + if ((messageBoxText[ind]=='\n') || (messageBoxText[ind]=='\0')) + { + lineEnd[numLines++] = ind; + if (numLines==MAX_LINES) break; + if (messageBoxText[ind]=='\0') break; + lineStart[numLines] = ind+1; + } + ind++; + } + + int lineSpacing = 20 + 2*MIN((MAX_LINES - numLines),6); + char tempStr[256]; + IplFont::getInstance().drawInit(tmpTextColor); + for (int i = 0; i < numLines; i++) + { + int heightOffset = -lineSpacing*numLines/2+lineSpacing*i; + int numChar = lineEnd[i]-lineStart[i]; + numChar = numChar <= 255 ? numChar : 255; + strncpy(tempStr,&messageBoxText[lineStart[i]],numChar); + tempStr[numChar] = '\0'; + IplFont::getInstance().drawString((int) (x+width/2), (int) (y+height/2)-20+heightOffset, tempStr, 1.0, true); + } +// IplFont::getInstance().drawString((int) (x+width/2), (int) (y+height/2)-20+heightOffset, messageBoxText, 1.0, true); + + drawChildren(gfx); + +} + +void Func_MessageBoxOK() +{ + MessageBox::getInstance().setReturnValue(1); + MessageBox::getInstance().deactivate(); +} + +void Func_MessageBoxCancel() +{ + MessageBox::getInstance().deactivate(); +} + +} //namespace menu diff --git a/Gamecube/libgui/MessageBox.h b/Gamecube/libgui/MessageBox.h new file mode 100644 index 0000000..ff36fd1 --- /dev/null +++ b/Gamecube/libgui/MessageBox.h @@ -0,0 +1,65 @@ +/** + * Wii64 - MessageBox.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef MESSAGEBOX_H +#define MESSAGEBOX_H + +#include "Frame.h" +#include "Image.h" +#include "Gui.h" +#include "GuiTypes.h" + +namespace menu { + +class MessageBox : public Frame +{ +public: + void setMessage(const char* text); + int askMessage(const char* text); + void fadeMessage(const char* text); + void setReturnValue(int returnValue); + int getReturnValue(); + void deactivate(); + bool getActive(); + void drawMessageBox(Graphics& gfx); + + static MessageBox& getInstance() + { + static MessageBox obj; + return obj; + } + +private: + MessageBox(); + ~MessageBox(); + Image *buttonImage; + Image *buttonFocusImage; + bool messageBoxActive; + Frame *currentCursorFrame; + Frame *currentFocusFrame; + GXColor boxColor, textColor; + int returnValue; + float messageFade; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/TextBox.cpp b/Gamecube/libgui/TextBox.cpp new file mode 100644 index 0000000..b1d6b51 --- /dev/null +++ b/Gamecube/libgui/TextBox.cpp @@ -0,0 +1,64 @@ +/** + * Wii64 - TextBox.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "TextBox.h" +#include "GraphicsGX.h" +#include "IPLFont.h" + +namespace menu { + +TextBox::TextBox(char** label, float x, float y, float scale, bool centered) + : centered(centered), + textBoxText(label), + x(x), + y(y), + scale(scale) +{ + setType(TYPE_TEXTBOX); + //Label color +// GXColor color = {255, 255, 255, 255}; + GXColor color = {56, 56, 56, 255}; + setColor(&color); +} + +TextBox::~TextBox() +{ +} + +void TextBox::setColor(GXColor *colors) +{ + labelColor.r = colors[0].r; + labelColor.g = colors[0].g; + labelColor.b = colors[0].b; + labelColor.a = colors[0].a; +} + +void TextBox::setText(char** strPtr) +{ + textBoxText = strPtr; +} + +void TextBox::drawComponent(Graphics& gfx) +{ + IplFont::getInstance().drawInit(labelColor); + IplFont::getInstance().drawString((int) x, (int) y, *textBoxText, scale, centered); +} + +} //namespace menu diff --git a/Gamecube/libgui/TextBox.h b/Gamecube/libgui/TextBox.h new file mode 100644 index 0000000..d46a02d --- /dev/null +++ b/Gamecube/libgui/TextBox.h @@ -0,0 +1,48 @@ +/** + * Wii64 - TextBox.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef TEXTBOX_H +#define TEXTBOX_H + +//#include "GuiTypes.h" +#include "Component.h" + +namespace menu { + +class TextBox : public Component +{ +public: + TextBox(char** label, float x, float y, float scale, bool centered); + ~TextBox(); + void setColor(GXColor *labelColor); + void setText(char** strPtr); + void drawComponent(Graphics& gfx); + +private: + bool centered; + char** textBoxText; + float x, y, scale; + GXColor labelColor; + +}; + +} //namespace menu + +#endif diff --git a/Gamecube/libgui/resources.h b/Gamecube/libgui/resources.h new file mode 100644 index 0000000..9cc4c79 --- /dev/null +++ b/Gamecube/libgui/resources.h @@ -0,0 +1,36 @@ +/** + * Wii64 - resources.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef RESOURCES_H +#define RESOURCES_H + +extern u8 CursorPointTexture[]; +extern u8 CursorGrabTexture[]; +extern u8 ButtonTexture[]; +extern u8 ButtonFocusTexture[]; +extern u8 StyleAButtonTlut[]; +extern u8 StyleAButtonTexture[]; +extern u8 StyleAButtonFocusTexture[]; +extern u8 StyleAButtonSelectOffTexture[]; +extern u8 StyleAButtonSelectOffFocusTexture[]; +extern u8 StyleAButtonSelectOnTexture[]; +extern u8 StyleAButtonSelectOnFocusTexture[]; + +#endif diff --git a/Gamecube/libgui/resources.s b/Gamecube/libgui/resources.s new file mode 100644 index 0000000..18d419a --- /dev/null +++ b/Gamecube/libgui/resources.s @@ -0,0 +1,89 @@ + .rodata + .globl CursorPointTexture + .balign 32 + CursorPointTexture: + .incbin "../libgui/resources/CursorPoint.tx" + .globl CursorPointTexture_length + CursorPointTexture_length: + .long (CursorPointTexture_length - CursorPointTexture) + + .globl CursorGrabTexture + .balign 32 + CursorGrabTexture: + .incbin "../libgui/resources/CursorGrab.tx" + .globl CursorGrabTexture_length + CursorGrabTexture_length: + .long (CursorGrabTexture_length - CursorGrabTexture) + + .globl ButtonTexture + .balign 32 + ButtonTexture: + .incbin "../libgui/resources/Button.tx" + .globl ButtonTexture_length + ButtonTexture_length: + .long (ButtonTexture_length - ButtonTexture) + + .globl ButtonFocusTexture + .balign 32 + ButtonFocusTexture: + .incbin "../libgui/resources/ButtonFocus.tx" + .globl ButtonFocusTexture_length + ButtonFocusTexture_length: + .long (ButtonFocusTexture_length - ButtonFocusTexture) + + .globl StyleAButtonTlut + .balign 32 + StyleAButtonTlut: + .incbin "../libgui/resources/ButtonA.tlt" + .globl StyleAButtonTlut_length + StyleAButtonTlut_length: + .long (StyleAButtonTlut_length - StyleAButtonTlut) + + .globl StyleAButtonTexture + .balign 32 + StyleAButtonTexture: + .incbin "../libgui/resources/ButtonA.tx" + .globl StyleAButtonTexture_length + StyleAButtonTexture_length: + .long (StyleAButtonTexture_length - StyleAButtonTexture) + + .globl StyleAButtonFocusTexture + .balign 32 + StyleAButtonFocusTexture: + .incbin "../libgui/resources/ButtonAFoc.tx" + .globl StyleAButtonFocusTexture_length + StyleAButtonFocusTexture_length: + .long (StyleAButtonFocusTexture_length - StyleAButtonFocusTexture) + + .globl StyleAButtonSelectOffTexture + .balign 32 + StyleAButtonSelectOffTexture: + .incbin "../libgui/resources/ButtonASelOff.tx" + .globl StyleAButtonSelectOffTexture_length + StyleAButtonSelectOffTexture_length: + .long (StyleAButtonSelectOffTexture_length - StyleAButtonSelectOffTexture) + + .globl StyleAButtonSelectOffFocusTexture + .balign 32 + StyleAButtonSelectOffFocusTexture: + .incbin "../libgui/resources/ButtonASelOffFoc.tx" + .globl StyleAButtonSelectOffFocusTexture_length + StyleAButtonSelectOffFocusTexture_length: + .long (StyleAButtonSelectOffFocusTexture_length - StyleAButtonSelectOffFocusTexture) + + .globl StyleAButtonSelectOnTexture + .balign 32 + StyleAButtonSelectOnTexture: + .incbin "../libgui/resources/ButtonASelOn.tx" + .globl StyleAButtonSelectOnTexture_length + StyleAButtonSelectOnTexture_length: + .long (StyleAButtonSelectOnTexture_length - StyleAButtonSelectOnTexture) + + .globl StyleAButtonSelectOnFocusTexture + .balign 32 + StyleAButtonSelectOnFocusTexture: + .incbin "../libgui/resources/ButtonASelOnFoc.tx" + .globl StyleAButtonSelectOnFocusTexture_length + StyleAButtonSelectOnFocusTexture_length: + .long (StyleAButtonSelectOnFocusTexture_length - StyleAButtonSelectOnFocusTexture) + diff --git a/Gamecube/libgui/resources/Button.tx b/Gamecube/libgui/resources/Button.tx new file mode 100644 index 0000000..a797da9 Binary files /dev/null and b/Gamecube/libgui/resources/Button.tx differ diff --git a/Gamecube/libgui/resources/ButtonA.tlt b/Gamecube/libgui/resources/ButtonA.tlt new file mode 100644 index 0000000..d352ac7 Binary files /dev/null and b/Gamecube/libgui/resources/ButtonA.tlt differ diff --git a/Gamecube/libgui/resources/ButtonA.tx b/Gamecube/libgui/resources/ButtonA.tx new file mode 100644 index 0000000..308e54c Binary files /dev/null and b/Gamecube/libgui/resources/ButtonA.tx differ diff --git a/Gamecube/libgui/resources/ButtonAFoc.tx b/Gamecube/libgui/resources/ButtonAFoc.tx new file mode 100644 index 0000000..d3dd0d1 Binary files /dev/null and b/Gamecube/libgui/resources/ButtonAFoc.tx differ diff --git a/Gamecube/libgui/resources/ButtonASelOff.tx b/Gamecube/libgui/resources/ButtonASelOff.tx new file mode 100644 index 0000000..73e04b6 Binary files /dev/null and b/Gamecube/libgui/resources/ButtonASelOff.tx differ diff --git a/Gamecube/libgui/resources/ButtonASelOffFoc.tx b/Gamecube/libgui/resources/ButtonASelOffFoc.tx new file mode 100644 index 0000000..2f202db Binary files /dev/null and b/Gamecube/libgui/resources/ButtonASelOffFoc.tx differ diff --git a/Gamecube/libgui/resources/ButtonASelOn.tx b/Gamecube/libgui/resources/ButtonASelOn.tx new file mode 100644 index 0000000..312cfde Binary files /dev/null and b/Gamecube/libgui/resources/ButtonASelOn.tx differ diff --git a/Gamecube/libgui/resources/ButtonASelOnFoc.tx b/Gamecube/libgui/resources/ButtonASelOnFoc.tx new file mode 100644 index 0000000..aa2f5a2 Binary files /dev/null and b/Gamecube/libgui/resources/ButtonASelOnFoc.tx differ diff --git a/Gamecube/libgui/resources/ButtonFocus.tx b/Gamecube/libgui/resources/ButtonFocus.tx new file mode 100644 index 0000000..ea61d92 Binary files /dev/null and b/Gamecube/libgui/resources/ButtonFocus.tx differ diff --git a/Gamecube/libgui/resources/CursorGrab.tx b/Gamecube/libgui/resources/CursorGrab.tx new file mode 100644 index 0000000..f441663 Binary files /dev/null and b/Gamecube/libgui/resources/CursorGrab.tx differ diff --git a/Gamecube/libgui/resources/CursorPoint.tx b/Gamecube/libgui/resources/CursorPoint.tx new file mode 100644 index 0000000..a5ff551 Binary files /dev/null and b/Gamecube/libgui/resources/CursorPoint.tx differ diff --git a/Gamecube/menu/ConfigureButtonsFrame.cpp b/Gamecube/menu/ConfigureButtonsFrame.cpp new file mode 100644 index 0000000..b6460a7 --- /dev/null +++ b/Gamecube/menu/ConfigureButtonsFrame.cpp @@ -0,0 +1,659 @@ +/** + * WiiSX - ConfigureButtonsFrame.cpp + * Copyright (C) 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#include "MenuContext.h" +#include "ConfigureButtonsFrame.h" +#include "../libgui/GuiTypes.h" +#include "../libgui/GuiResources.h" +#include "../libgui/Button.h" +#include "../libgui/TextBox.h" +#include "../libgui/resources.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../libgui/MessageBox.h" +//#include "../main/timers.h" +//#include "../main/wii64config.h" + +extern "C" { +#include "../gc_input/controller.h" +} + +void Func_NextPad(); +void Func_DefaultConfig(); +void Func_ToggleConfigSlot(); +void Func_LoadConfig(); +void Func_SaveConfig(); + +void Func_ToggleButtonExit(); +void Func_ToggleButtonL1(); +void Func_ToggleButtonL2(); +void Func_ToggleButtonSelect(); +void Func_ToggleButtonStart(); +void Func_ToggleButtonR1(); +void Func_ToggleButtonR2(); +void Func_ToggleButtonDup(); +void Func_ToggleButtonDleft(); +void Func_ToggleButtonDright(); +void Func_ToggleButtonDdown(); +void Func_ToggleButtonTri(); +void Func_ToggleButtonSqu(); +void Func_ToggleButtonCir(); +void Func_ToggleButtonCro(); +void Func_ToggleAnalogL(); +void Func_ToggleAnalogR(); +void Func_ToggleInvertYL(); +void Func_ToggleInvertYR(); +void Func_ToggleButtonL3(); +void Func_ToggleButtonR3(); + +void Func_ReturnFromConfigureButtonsFrame(); + + +#define NUM_FRAME_BUTTONS 26 +#define FRAME_BUTTONS configureButtonsFrameButtons +#define FRAME_STRINGS configureButtonsFrameStrings +#define NUM_FRAME_TEXTBOXES 2 +#define FRAME_TEXTBOXES configureButtonsFrameTextBoxes +#define TITLE_STRING configureButtonsTitleString + +static char FRAME_STRINGS[27][20] = + { "Next Pad", + "Load Default", + "Slot 1", + "Load", + "Save", + "X+Y", + "Btn L1", + "Btn L2", + "Btn Select", + "Btn Start", + "Btn R1", + "Btn R2", + "Btn Dup", + "Btn Dleft", + "Btn Dright", + "Btn Ddown", + "Btn Tri", + "Btn Squ", + "Btn Cir", + "Btn Cro", + "Analog Stick L", + "Analog Stick R", + "Invert Y L", + "Invert Y R", + "Btn L3", + "Btn R3", + "Menu:"}; + +static char TITLE_STRING[50] = "Gamecube Pad 1 to PSX Pad 1 Mapping"; + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_NRM, FRAME_STRINGS[0], 40.0, 80.0, 115.0, 40.0, 22, 5, 4, 1, Func_NextPad, Func_ReturnFromConfigureButtonsFrame }, // Next Pad + { NULL, BTN_A_NRM, FRAME_STRINGS[1], 175.0, 80.0, 145.0, 40.0, 24, 8, 0, 2, Func_DefaultConfig, Func_ReturnFromConfigureButtonsFrame }, // Restore Default Config + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 340.0, 80.0, 80.0, 40.0, 25, 9, 1, 3, Func_ToggleConfigSlot, Func_ReturnFromConfigureButtonsFrame }, // Cycle Through Config Slots + { NULL, BTN_A_NRM, FRAME_STRINGS[3], 440.0, 80.0, 70.0, 40.0, 23, 10, 2, 4, Func_LoadConfig, Func_ReturnFromConfigureButtonsFrame }, // Load Config + { NULL, BTN_A_NRM, FRAME_STRINGS[4], 530.0, 80.0, 70.0, 40.0, 23, 10, 3, 0, Func_SaveConfig, Func_ReturnFromConfigureButtonsFrame }, // Save Config + + { NULL, BTN_A_NRM, FRAME_STRINGS[5], 30.0, 160.0, 100.0, 40.0, 0, 12, 10, 6, Func_ToggleButtonExit, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Exit + + { NULL, BTN_A_NRM, FRAME_STRINGS[6], 140.0, 130.0, 80.0, 40.0, 0, 7, 5, 8, Func_ToggleButtonL1, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button L1 + { NULL, BTN_A_NRM, FRAME_STRINGS[7], 140.0, 180.0, 80.0, 40.0, 6, 12, 5, 8, Func_ToggleButtonL2, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button L2 + { NULL, BTN_A_NRM, FRAME_STRINGS[8], 235.0, 140.0, 80.0, 40.0, 1, 20, 6, 9, Func_ToggleButtonSelect,Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Select + { NULL, BTN_A_NRM, FRAME_STRINGS[9], 325.0, 140.0, 80.0, 40.0, 2, 21, 8, 10, Func_ToggleButtonStart, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Start + { NULL, BTN_A_NRM, FRAME_STRINGS[10], 420.0, 130.0, 80.0, 40.0, 3, 11, 9, 5, Func_ToggleButtonR1, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button R1 + { NULL, BTN_A_NRM, FRAME_STRINGS[11], 420.0, 180.0, 80.0, 40.0, 10, 16, 9, 5, Func_ToggleButtonR2, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button R2 + + { NULL, BTN_A_NRM, FRAME_STRINGS[12], 75.0, 230.0, 80.0, 40.0, 5, 13, 16, 16, Func_ToggleButtonDup, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button D-up + { NULL, BTN_A_NRM, FRAME_STRINGS[13], 30.0, 280.0, 80.0, 40.0, 12, 15, 18, 14, Func_ToggleButtonDleft, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button D-left + { NULL, BTN_A_NRM, FRAME_STRINGS[14], 120.0, 280.0, 80.0, 40.0, 12, 15, 13, 17, Func_ToggleButtonDright,Func_ReturnFromConfigureButtonsFrame }, // Toggle Button D-right + { NULL, BTN_A_NRM, FRAME_STRINGS[15], 75.0, 330.0, 80.0, 40.0, 13, 22, 19, 20, Func_ToggleButtonDdown, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button D-down + + { NULL, BTN_A_NRM, FRAME_STRINGS[16], 485.0, 230.0, 80.0, 40.0, 11, 17, 12, 12, Func_ToggleButtonTri, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Triangle + { NULL, BTN_A_NRM, FRAME_STRINGS[17], 440.0, 280.0, 80.0, 40.0, 16, 19, 14, 18, Func_ToggleButtonSqu, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Square + { NULL, BTN_A_NRM, FRAME_STRINGS[18], 530.0, 280.0, 80.0, 40.0, 16, 19, 17, 13, Func_ToggleButtonCir, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Circle + { NULL, BTN_A_NRM, FRAME_STRINGS[19], 485.0, 330.0, 80.0, 40.0, 17, 23, 21, 15, Func_ToggleButtonCro, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button Cross + + { NULL, BTN_A_NRM, FRAME_STRINGS[20], 165.0, 345.0, 150.0, 40.0, 8, 24, 15, 21, Func_ToggleAnalogL, Func_ReturnFromConfigureButtonsFrame }, // Toggle Analog Stick L + { NULL, BTN_A_NRM, FRAME_STRINGS[21], 325.0, 345.0, 150.0, 40.0, 9, 25, 20, 19, Func_ToggleAnalogR, Func_ReturnFromConfigureButtonsFrame }, // Toggle Analog Stick R + { NULL, BTN_A_NRM, FRAME_STRINGS[22], 95.0, 395.0, 130.0, 40.0, 15, 0, 23, 24, Func_ToggleInvertYL, Func_ReturnFromConfigureButtonsFrame }, // Toggle Analog Invert Y L + { NULL, BTN_A_NRM, FRAME_STRINGS[23], 415.0, 395.0, 130.0, 40.0, 19, 3, 25, 22, Func_ToggleInvertYR, Func_ReturnFromConfigureButtonsFrame }, // Toggle Analog Invert Y R + { NULL, BTN_A_NRM, FRAME_STRINGS[24], 235.0, 395.0, 80.0, 40.0, 20, 1, 22, 25, Func_ToggleButtonL3, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button L3 + { NULL, BTN_A_NRM, FRAME_STRINGS[25], 325.0, 395.0, 80.0, 40.0, 21, 2, 24, 23, Func_ToggleButtonR3, Func_ReturnFromConfigureButtonsFrame }, // Toggle Button R3 +}; + +struct TextBoxInfo +{ + menu::TextBox *textBox; + char* textBoxString; + float x; + float y; + float scale; + bool centered; +} FRAME_TEXTBOXES[NUM_FRAME_TEXTBOXES] = +{ // textBox textBoxString x y scale centered + { NULL, TITLE_STRING, 320.0, 50.0, 1.0, true }, // ______ Pad X to N64 Pad Y Mapping + { NULL, FRAME_STRINGS[26], 80.0, 145.0, 0.9, true }, // Menu Combo +}; + +ConfigureButtonsFrame::ConfigureButtonsFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + for (int i = 0; i < 5; i++) + FRAME_BUTTONS[i].button->setFontSize(0.8); + for (int i = 5; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button->setFontSize(0.7); + + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + { + FRAME_TEXTBOXES[i].textBox = new menu::TextBox(&FRAME_TEXTBOXES[i].textBoxString, + FRAME_TEXTBOXES[i].x, FRAME_TEXTBOXES[i].y, + FRAME_TEXTBOXES[i].scale, FRAME_TEXTBOXES[i].centered); + add(FRAME_TEXTBOXES[i].textBox); + } + + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_ReturnFromConfigureButtonsFrame); + setEnabled(true); + activateSubmenu(SUBMENU_PSX_PADNONE); +} + +ConfigureButtonsFrame::~ConfigureButtonsFrame() +{ + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + delete FRAME_TEXTBOXES[i].textBox; + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + +} + +static char controllerTypeStrings[6][17] = + { "Gamecube", + "Classic", + "Wiimote+Nunchuck", + "Wiimote", + "Wii U Pro", + "NULL"}; + +enum ActivePadType +{ + ACTIVEPADTYPE_GAMECUBE=0, + ACTIVEPADTYPE_CLASSIC, + ACTIVEPADTYPE_WIIMOTENUNCHUCK, + ACTIVEPADTYPE_WIIMOTE, + ACTIVEPADTYPE_WIIUPRO, + ACTIVEPADTYPE_NONE, +}; + +enum ActivePadAssigned +{ + ACTIVEPADASSIGNED_FALSE=0, + ACTIVEPADASSIGNED_TRUE, +}; + +int activePad=ConfigureButtonsFrame::SUBMENU_PSX_PAD0; +int activePadType=ACTIVEPADTYPE_NONE; +int activePadAssigned=ACTIVEPADASSIGNED_TRUE; + +void ConfigureButtonsFrame::activateSubmenu(int submenu) +{ + + if (submenu != SUBMENU_PSX_PADNONE) + { + activePad = submenu; + menu::Gui::getInstance().menuLogo->setVisible(false); + } + + //Fill out title text + if (virtualControllers[activePad].control == &controller_GC) + activePadType = ACTIVEPADTYPE_GAMECUBE; +#ifdef HW_RVL + else if (virtualControllers[activePad].control == &controller_Classic) + activePadType = ACTIVEPADTYPE_CLASSIC; + else if (virtualControllers[activePad].control == &controller_WiimoteNunchuk) + activePadType = ACTIVEPADTYPE_WIIMOTENUNCHUCK; + else if (virtualControllers[activePad].control == &controller_Wiimote) + activePadType = ACTIVEPADTYPE_WIIMOTE; + else if (virtualControllers[activePad].control == &controller_WiiUPro) + activePadType = ACTIVEPADTYPE_WIIUPRO; +#endif //HW_RVL + else + activePadType = ACTIVEPADTYPE_NONE; + + if (activePadType == ACTIVEPADTYPE_NONE) + { + sprintf(TITLE_STRING, "PSX Pad %d: No Physical Controller Assigned", activePad+1 ); + + if (activePadAssigned == ACTIVEPADASSIGNED_TRUE) //Reset to "Next Pad" button + { + activePadAssigned = ACTIVEPADASSIGNED_FALSE; + menu::Focus::getInstance().clearPrimaryFocus(); + } + for (int i = 5; i < NUM_FRAME_BUTTONS; i++) + strcpy(FRAME_STRINGS[i], ""); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_UP, NULL); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_LEFT, NULL); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, NULL); + for (int i = 1; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button->setActive(false); + } + else + { + sprintf(TITLE_STRING, "PSX Pad %d: %s Pad %d Mapping", activePad+1, controllerTypeStrings[activePadType], virtualControllers[activePad].number+1 ); + + controller_config_t* currentConfig = virtualControllers[activePad].config; + + if (activePadAssigned == ACTIVEPADASSIGNED_FALSE) //Reset to "Next Pad" button + { + activePadAssigned = ACTIVEPADASSIGNED_TRUE; + } + + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[0].focusUp].button); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[0].focusDown].button); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[0].focusLeft].button); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[0].focusRight].button); + for (int i = 1; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button->setActive(true); + + //Assign text to each button + strcpy(FRAME_STRINGS[5], currentConfig->exit->name); + strcpy(FRAME_STRINGS[6], currentConfig->L1->name); + strcpy(FRAME_STRINGS[7], currentConfig->L2->name); + strcpy(FRAME_STRINGS[8], currentConfig->SELECT->name); + strcpy(FRAME_STRINGS[9], currentConfig->START->name); + strcpy(FRAME_STRINGS[10], currentConfig->R1->name); + strcpy(FRAME_STRINGS[11], currentConfig->R2->name); + strcpy(FRAME_STRINGS[12], currentConfig->DU->name); + strcpy(FRAME_STRINGS[13], currentConfig->DL->name); + strcpy(FRAME_STRINGS[14], currentConfig->DR->name); + strcpy(FRAME_STRINGS[15], currentConfig->DD->name); + strcpy(FRAME_STRINGS[16], currentConfig->TRI->name); + strcpy(FRAME_STRINGS[17], currentConfig->SQU->name); + strcpy(FRAME_STRINGS[18], currentConfig->CIR->name); + strcpy(FRAME_STRINGS[19], currentConfig->CRO->name); + strcpy(FRAME_STRINGS[20], currentConfig->analogL->name); + strcpy(FRAME_STRINGS[21], currentConfig->analogR->name); + if (currentConfig->invertedYL) + strcpy(FRAME_STRINGS[22], "Inverted Y"); + else + strcpy(FRAME_STRINGS[22], "Normal Y"); + if (currentConfig->invertedYR) + strcpy(FRAME_STRINGS[23], "Inverted Y"); + else + strcpy(FRAME_STRINGS[23], "Normal Y"); + strcpy(FRAME_STRINGS[24], currentConfig->L3->name); + strcpy(FRAME_STRINGS[25], currentConfig->R3->name); + } +} + +void ConfigureButtonsFrame::updateFrame(float deltaTime) +{ + activateSubmenu(activePad); +} + +#define NUM_LINES 10 + +void ConfigureButtonsFrame::drawChildren(menu::Graphics &gfx) +{ + if(isVisible()) + { + int base_x = 204; + int base_y = 188; + int lines[NUM_LINES][4] = {{164, 265, 221, 244}, //D-pad (17,56) + {476, 265, 419, 244}, //Tri,Squ,Cir,Cro btns (215,56) + {275, 160, 302, 240}, //SELECT (98,52) + {365, 160, 338, 242}, //START (134,54) + {220, 170, 242, 192}, //L1 (38,4) + {420, 170, 398, 192}, //R1 (194,4) + {220, 200, 232, 204}, //L2 (28,16) + {420, 200, 408, 204}, //R2 (204,16) + {260, 345, 278, 294}, //AnalogL (74,106) + {380, 345, 362, 294}};//AnalogR (158,106) + + GXColor controllerColors[6] = { { 1, 29, 169, 255}, //blue + {254, 32, 21, 255}, //orange/red + { 8, 147, 48, 255}, //green + {255, 192, 1, 255}, //yellow/gold + {150, 150, 255, 255}, //light blue lines + {255, 255, 255, 255}};//white + + //Draw PSX Controller + menu::Image* controllerIcon = NULL; +// gfx.setColor(controllerColors[activePad]); + gfx.setColor(controllerColors[5]); + controllerIcon = menu::Resources::getInstance().getImage(menu::Resources::IMAGE_PSX_CONTROLLER); + controllerIcon->activateImage(GX_TEXMAP0); +// GX_SetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_ZERO,GX_CC_ZERO,GX_CC_RASC); + GX_SetTevColorIn(GX_TEVSTAGE0,GX_CC_ZERO,GX_CC_TEXC,GX_CC_RASC,GX_CC_ZERO); + GX_SetTevColorOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + GX_SetTevAlphaIn(GX_TEVSTAGE0,GX_CA_ZERO,GX_CA_RASA,GX_CA_TEXA,GX_CA_ZERO); + GX_SetTevAlphaOp(GX_TEVSTAGE0,GX_TEV_ADD,GX_TB_ZERO,GX_CS_SCALE_1,GX_TRUE,GX_TEVPREV); + gfx.enableBlending(true); + gfx.drawImage(0, base_x, base_y, 232, 152, 0, 1, 0, 1); + gfx.setTEV(GX_PASSCLR); + + //Draw lines and circles + gfx.setColor(controllerColors[5]); + gfx.setLineWidth(1); + gfx.drawCircle(115, 300, 60, 33); + gfx.drawCircle(525, 300, 60, 33); + + for (int i=0; idraw(gfx); + } + } +} + +extern MenuContext *pMenuContext; + +void Func_NextPad() +{ + activePad = (activePad+1) %2; + + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREBUTTONS)->activateSubmenu(activePad); +} + +void Func_DefaultConfig() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + memcpy(currentConfig, &virtualControllers[activePad].control->config_default, sizeof(controller_config_t)); + + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREBUTTONS)->activateSubmenu(activePad); +} + +static unsigned int which_slot = 0; + +void Func_ToggleConfigSlot() +{ + which_slot = (which_slot+1) %4; + FRAME_STRINGS[2][5] = which_slot + '1'; +} + +void Func_LoadConfig() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + memcpy(currentConfig, &virtualControllers[activePad].control->config_slot[which_slot], sizeof(controller_config_t)); + + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREBUTTONS)->activateSubmenu(activePad); +} + +void Func_SaveConfig() +{ + char buffer [50] = ""; + controller_config_t* currentConfig = virtualControllers[activePad].config; + memcpy(&virtualControllers[activePad].control->config_slot[which_slot], currentConfig, sizeof(controller_config_t)); + + //todo: save button configuration to file here + + sprintf(buffer,"Saved current button mapping to slot %u.",which_slot+1); + menu::MessageBox::getInstance().fadeMessage(buffer); +// menu::MessageBox::getInstance().setMessage(buffer); +} + +void Func_ToggleButtonExit() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->exit->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_menu_combos; + currentConfig->exit = &virtualControllers[activePad].control->menu_combos[currentButton]; + strcpy(FRAME_STRINGS[5], currentConfig->exit->name); +} + +void Func_ToggleButtonL1() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->L1->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->L1 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[6], currentConfig->L1->name); +} + +void Func_ToggleButtonL2() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->L2->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->L2 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[7], currentConfig->L2->name); +} + +void Func_ToggleButtonSelect() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->SELECT->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->SELECT = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[8], currentConfig->SELECT->name); +} + +void Func_ToggleButtonStart() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->START->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->START = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[9], currentConfig->START->name); +} + +void Func_ToggleButtonR1() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->R1->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->R1 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[10], currentConfig->R1->name); +} + +void Func_ToggleButtonR2() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->R2->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->R2 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[11], currentConfig->R2->name); +} + +void Func_ToggleButtonDup() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->DU->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->DU = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[12], currentConfig->DU->name); +} + +void Func_ToggleButtonDleft() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->DL->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->DL = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[13], currentConfig->DL->name); +} + +void Func_ToggleButtonDright() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->DR->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->DR = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[14], currentConfig->DR->name); +} + +void Func_ToggleButtonDdown() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->DD->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->DD = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[15], currentConfig->DD->name); +} + +void Func_ToggleButtonTri() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->TRI->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->TRI = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[16], currentConfig->TRI->name); +} + +void Func_ToggleButtonSqu() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->SQU->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->SQU = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[17], currentConfig->SQU->name); +} + +void Func_ToggleButtonCir() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->CIR->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->CIR = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[18], currentConfig->CIR->name); +} + +void Func_ToggleButtonCro() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->CRO->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->CRO = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[19], currentConfig->CRO->name); +} + +void Func_ToggleAnalogL() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->analogL->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_analog_sources; + currentConfig->analogL = &virtualControllers[activePad].control->analog_sources[currentButton]; + strcpy(FRAME_STRINGS[20], currentConfig->analogL->name); +} + +void Func_ToggleAnalogR() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->analogR->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_analog_sources; + currentConfig->analogR = &virtualControllers[activePad].control->analog_sources[currentButton]; + strcpy(FRAME_STRINGS[21], currentConfig->analogR->name); +} + +void Func_ToggleInvertYL() +{ + int invertedY = virtualControllers[activePad].config->invertedYL; + if (invertedY) + { + virtualControllers[activePad].config->invertedYL = 0; + strcpy(FRAME_STRINGS[22], "Normal Y"); + } + else + { + virtualControllers[activePad].config->invertedYL = 1; + strcpy(FRAME_STRINGS[22], "Inverted Y"); + } +} + +void Func_ToggleInvertYR() +{ + int invertedY = virtualControllers[activePad].config->invertedYR; + if (invertedY) + { + virtualControllers[activePad].config->invertedYR = 0; + strcpy(FRAME_STRINGS[23], "Normal Y"); + } + else + { + virtualControllers[activePad].config->invertedYR = 1; + strcpy(FRAME_STRINGS[23], "Inverted Y"); + } +} + +void Func_ToggleButtonL3() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->L3->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->L3 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[24], currentConfig->L3->name); +} + +void Func_ToggleButtonR3() +{ + controller_config_t* currentConfig = virtualControllers[activePad].config; + int currentButton = currentConfig->R3->index; + currentButton = (currentButton+1) %virtualControllers[activePad].control->num_buttons; + currentConfig->R3 = &virtualControllers[activePad].control->buttons[currentButton]; + strcpy(FRAME_STRINGS[25], currentConfig->R3->name); +} + +void Func_ReturnFromConfigureButtonsFrame() +{ + menu::Gui::getInstance().menuLogo->setVisible(true); + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_INPUT); +} diff --git a/Gamecube/menu/ConfigureButtonsFrame.h b/Gamecube/menu/ConfigureButtonsFrame.h new file mode 100644 index 0000000..da93f59 --- /dev/null +++ b/Gamecube/menu/ConfigureButtonsFrame.h @@ -0,0 +1,47 @@ +/** + * WiiSX - ConfigureButtonsFrame.h + * Copyright (C) 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef CONFIGUREBUTTONSFRAME_H +#define CONFIGUREBUTTONSFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class ConfigureButtonsFrame : public menu::Frame +{ +public: + ConfigureButtonsFrame(); + ~ConfigureButtonsFrame(); + void activateSubmenu(int submenu); + void updateFrame(float deltaTime); + void drawChildren(menu::Graphics& gfx); + + enum ConfigureButtonsSubmenus + { + SUBMENU_PSX_PAD0=0, + SUBMENU_PSX_PAD1, + SUBMENU_PSX_PADNONE, + }; + +private: + +}; + +#endif diff --git a/Gamecube/menu/ConfigureInputFrame.cpp b/Gamecube/menu/ConfigureInputFrame.cpp new file mode 100644 index 0000000..444113e --- /dev/null +++ b/Gamecube/menu/ConfigureInputFrame.cpp @@ -0,0 +1,286 @@ +/** + * WiiSX - ConfigureInputFrame.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "MenuContext.h" +#include "SettingsFrame.h" +#include "ConfigureInputFrame.h" +#include "../libgui/Button.h" +#include "../libgui/TextBox.h" +#include "../libgui/resources.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +//#include "../libgui/MessageBox.h" +//#include "../main/timers.h" +//#include "../main/wii64config.h" + +extern "C" { +#include "../gc_input/controller.h" +} + +void Func_AutoSelectInput(); +void Func_ManualSelectInput(); + +void Func_TogglePad0Type(); +void Func_TogglePad1Type(); +void Func_TogglePad0Assign(); +void Func_TogglePad1Assign(); + +void Func_ReturnFromConfigureInputFrame(); + + +#define NUM_FRAME_BUTTONS 6 +#define FRAME_BUTTONS configureInputFrameButtons +#define FRAME_STRINGS configureInputFrameStrings +#define NUM_FRAME_TEXTBOXES 3 +#define FRAME_TEXTBOXES configureInputFrameTextBoxes + +static char FRAME_STRINGS[16][15] = + { "Pad Assignment", + "PSX Pad 1", + "PSX Pad 2", + "PSX Pad 3", + "PSX Pad 4", + + "Automatic", + "Manual", + "None", + "Gamecube Pad", + "Wii Pad", + "Auto Assign", + "", + "1", + "2", + "3", + "4"}; + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_SEL, FRAME_STRINGS[5], 240.0, 80.0, 135.0, 56.0, 5, 2, 1, 1, Func_AutoSelectInput, Func_ReturnFromConfigureInputFrame }, // Automatic Pad Assignment + { NULL, BTN_A_SEL, FRAME_STRINGS[6], 395.0, 80.0, 120.0, 56.0, 9, 6, 0, 0, Func_ManualSelectInput, Func_ReturnFromConfigureInputFrame }, // Manual Pad Assignment + { NULL, BTN_A_NRM, FRAME_STRINGS[10], 240.0, 150.0, 200.0, 56.0, 0, 3, 4, 4, Func_TogglePad0Type, Func_ReturnFromConfigureInputFrame }, // Toggle Pad 0 Type + { NULL, BTN_A_NRM, FRAME_STRINGS[10], 240.0, 220.0, 200.0, 56.0, 2, 0, 5, 5, Func_TogglePad1Type, Func_ReturnFromConfigureInputFrame }, // Toggle Pad 1 Type + { NULL, BTN_A_NRM, FRAME_STRINGS[11], 460.0, 150.0, 55.0, 56.0, 1, 5, 2, 2, Func_TogglePad0Assign, Func_ReturnFromConfigureInputFrame }, // Toggle Pad 0 Assignment + { NULL, BTN_A_NRM, FRAME_STRINGS[11], 460.0, 220.0, 55.0, 56.0, 4, 1, 3, 3, Func_TogglePad1Assign, Func_ReturnFromConfigureInputFrame }, // Toggle Pad 1 Assignment + +}; + +struct TextBoxInfo +{ + menu::TextBox *textBox; + char* textBoxString; + float x; + float y; + float scale; + bool centered; +} FRAME_TEXTBOXES[NUM_FRAME_TEXTBOXES] = +{ // textBox textBoxString x y scale centered + { NULL, FRAME_STRINGS[0], 125.0, 108.0, 1.0, true }, // Pad Assignment + { NULL, FRAME_STRINGS[1], 125.0, 178.0, 1.0, true }, // Pad 1 + { NULL, FRAME_STRINGS[2], 125.0, 248.0, 1.0, true }, // Pad 2 +}; + +ConfigureInputFrame::ConfigureInputFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + { + FRAME_TEXTBOXES[i].textBox = new menu::TextBox(&FRAME_TEXTBOXES[i].textBoxString, + FRAME_TEXTBOXES[i].x, FRAME_TEXTBOXES[i].y, + FRAME_TEXTBOXES[i].scale, FRAME_TEXTBOXES[i].centered); + add(FRAME_TEXTBOXES[i].textBox); + } + + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_ReturnFromConfigureInputFrame); + setEnabled(true); + activateSubmenu(SUBMENU_REINIT); +} + +ConfigureInputFrame::~ConfigureInputFrame() +{ + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + delete FRAME_TEXTBOXES[i].textBox; + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + +} + +void ConfigureInputFrame::activateSubmenu(int submenu) +{ + if (padAutoAssign == PADAUTOASSIGN_AUTOMATIC) + { + FRAME_BUTTONS[0].button->setSelected(true); + FRAME_BUTTONS[1].button->setSelected(false); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_UP, NULL); + FRAME_BUTTONS[1].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + FRAME_BUTTONS[1].button->setNextFocus(menu::Focus::DIRECTION_UP, NULL); + for (int i = 0; i < 2; i++) + { + FRAME_BUTTONS[i+2].button->setActive(false); + FRAME_BUTTONS[i+2].buttonString = FRAME_STRINGS[10]; + FRAME_BUTTONS[i+4].button->setActive(false); + FRAME_BUTTONS[i+4].buttonString = FRAME_STRINGS[11]; + } + } + else + { + FRAME_BUTTONS[0].button->setSelected(false); + FRAME_BUTTONS[1].button->setSelected(true); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[2].button); + FRAME_BUTTONS[0].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[3].button); + FRAME_BUTTONS[1].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[4].button); + FRAME_BUTTONS[1].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[5].button); + for (int i = 0; i < 2; i++) + { + FRAME_BUTTONS[i+2].button->setActive(true); + FRAME_BUTTONS[i+2].buttonString = FRAME_STRINGS[padType[i]+7]; + FRAME_BUTTONS[i+4].button->setActive(true); + FRAME_BUTTONS[i+4].buttonString = FRAME_STRINGS[padAssign[i]+12]; + } + } +} + +extern MenuContext *pMenuContext; + +void Func_AutoSelectInput() +{ + padAutoAssign = PADAUTOASSIGN_AUTOMATIC; + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_ManualSelectInput() +{ + padAutoAssign = PADAUTOASSIGN_MANUAL; + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_AssignPad(int i) +{ + controller_t* type = NULL; + switch (padType[i]) + { + case PADTYPE_GAMECUBE: + type = &controller_GC; + break; +#ifdef HW_RVL + case PADTYPE_WII: + if (controller_WiiUPro.available[(int)padAssign[i]]) + type = &controller_WiiUPro; + //Note: Wii expansion detection is done in InputStatusBar.cpp during MainFrame draw + else if (controller_Classic.available[(int)padAssign[i]]) + type = &controller_Classic; + else + type = &controller_WiimoteNunchuk; + break; +#endif + } + assign_controller(i, type, (int) padAssign[i]); +} + +void Func_TogglePad0Type() +{ + int i = PADASSIGN_INPUT0; +#ifdef HW_RVL + padType[i] = (padType[i]+1) %3; +#else + padType[i] = (padType[i]+1) %2; +#endif + + if (padType[i]) Func_AssignPad(i); + else unassign_controller(i); + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_TogglePad1Type() +{ + int i = PADASSIGN_INPUT1; +#ifdef HW_RVL + padType[i] = (padType[i]+1) %3; +#else + padType[i] = (padType[i]+1) %2; +#endif + + if (padType[i]) Func_AssignPad(i); + else unassign_controller(i); + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_TogglePad0Assign() +{ + int i = PADASSIGN_INPUT0; + padAssign[i] = (padAssign[i]+1) %4; + + if (padType[i]) Func_AssignPad(i); + + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_TogglePad1Assign() +{ + int i = PADASSIGN_INPUT1; + padAssign[i] = (padAssign[i]+1) %4; + + if (padType[i]) Func_AssignPad(i); + + pMenuContext->getFrame(MenuContext::FRAME_CONFIGUREINPUT)->activateSubmenu(ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_ReturnFromConfigureInputFrame() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_INPUT); +} diff --git a/Gamecube/menu/ConfigureInputFrame.h b/Gamecube/menu/ConfigureInputFrame.h new file mode 100644 index 0000000..a6caec4 --- /dev/null +++ b/Gamecube/menu/ConfigureInputFrame.h @@ -0,0 +1,44 @@ +/** + * Wii64 - ConfigureInputFrame.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef CONFIGUREINPUTFRAME_H +#define CONFIGUREINPUTFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class ConfigureInputFrame : public menu::Frame +{ +public: + ConfigureInputFrame(); + ~ConfigureInputFrame(); + void activateSubmenu(int submenu); + + enum ConfigureInputSubmenus + { + SUBMENU_NONE=0, + SUBMENU_REINIT + }; + +private: + +}; + +#endif diff --git a/Gamecube/menu/CurrentRomFrame.cpp b/Gamecube/menu/CurrentRomFrame.cpp new file mode 100644 index 0000000..c6cf6b9 --- /dev/null +++ b/Gamecube/menu/CurrentRomFrame.cpp @@ -0,0 +1,355 @@ +/** + * Wii64 - CurrentRomFrame.cpp + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "MenuContext.h" +#include "CurrentRomFrame.h" +#include "../libgui/Button.h" +#include "../libgui/resources.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../libgui/MessageBox.h" +#include "../wiiSXconfig.h" +#include "../../psxcommon.h" + +extern "C" { +/*#include "../gc_memory/memory.h" +#include "../gc_memory/Saves.h" +#include "../main/rom.h" +#include "../main/plugin.h" +#include "../main/savestates.h"*/ +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-CARD.h" +extern int LoadMcd(int mcd, fileBrowser_file *savepath); +extern int SaveMcd(int mcd, fileBrowser_file *savepath); +extern long Mooby2CDRgetTN(unsigned char *buffer); +} + +void Func_ShowRomInfo(); +void Func_ResetROM(); +void Func_SwapCD(); +void Func_LoadSave(); +void Func_SaveGame(); +void Func_LoadState(); +void Func_SaveState(); +void Func_StateCycle(); +void Func_ReturnFromCurrentRomFrame(); + +#define NUM_FRAME_BUTTONS 8 +#define FRAME_BUTTONS currentRomFrameButtons +#define FRAME_STRINGS currentRomFrameStrings + +/* Button Layout: + * [Restart Game] [Swap CD] + * [Load MemCard] [Save MemCard] + * [Show ISO Info] + * [Load State] [Slot "x"] + * [Save State] + */ + +static char FRAME_STRINGS[8][15] = + { "Restart Game", + "Swap CD", + "Load MemCards", + "Save MemCards", + "Show ISO Info", + "Load State", + "Save State", + "Slot 0"}; + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_NRM, FRAME_STRINGS[0], 100.0, 60.0, 210.0, 56.0, 6, 2, 1, 1, Func_ResetROM, Func_ReturnFromCurrentRomFrame }, // Reset ROM + { NULL, BTN_A_NRM, FRAME_STRINGS[1], 330.0, 60.0, 210.0, 56.0, 7, 3, 0, 0, Func_SwapCD, Func_ReturnFromCurrentRomFrame }, // Swap CD + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 100.0, 120.0, 210.0, 56.0, 0, 4, 3, 3, Func_LoadSave, Func_ReturnFromCurrentRomFrame }, // Load MemCards + { NULL, BTN_A_NRM, FRAME_STRINGS[3], 330.0, 120.0, 210.0, 56.0, 1, 4, 2, 2, Func_SaveGame, Func_ReturnFromCurrentRomFrame }, // Save MemCards + { NULL, BTN_A_NRM, FRAME_STRINGS[4], 150.0, 180.0, 340.0, 56.0, 2, 5, -1, -1, Func_ShowRomInfo, Func_ReturnFromCurrentRomFrame }, // Show ISO Info + { NULL, BTN_A_NRM, FRAME_STRINGS[5], 150.0, 240.0, 220.0, 56.0, 4, 6, 7, 7, Func_LoadState, Func_ReturnFromCurrentRomFrame }, // Load State + { NULL, BTN_A_NRM, FRAME_STRINGS[6], 150.0, 300.0, 220.0, 56.0, 5, 0, 7, 7, Func_SaveState, Func_ReturnFromCurrentRomFrame }, // Save State + { NULL, BTN_A_NRM, FRAME_STRINGS[7], 390.0, 270.0, 100.0, 56.0, 4, 1, 5, 5, Func_StateCycle, Func_ReturnFromCurrentRomFrame }, // Cycle State +}; + +CurrentRomFrame::CurrentRomFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_ReturnFromCurrentRomFrame); + setEnabled(true); + +} + +CurrentRomFrame::~CurrentRomFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + +} + +extern MenuContext *pMenuContext; +extern char CdromId[10]; +extern char CdromLabel[33]; +extern "C" { +long MoobyCDRgetTN(unsigned char *buffer); +}; + +void Func_ShowRomInfo() +{ + char RomInfo[256] = ""; + char buffer [50]; + + sprintf(buffer,"CD-ROM Label: %s\n",CdromLabel); + strcat(RomInfo,buffer); + sprintf(buffer,"CD-ROM ID: %s\n", CdromId); + strcat(RomInfo,buffer); + sprintf(buffer,"ISO Size: %u Mb\n",isoFile.size/1024/1024); + strcat(RomInfo,buffer); + sprintf(buffer,"Country: %s\n",(!Config.PsxType) ? "NTSC":"PAL"); + strcat(RomInfo,buffer); + sprintf(buffer,"BIOS: %s\n",(Config.HLE==BIOS_USER_DEFINED) ? "USER DEFINED":"HLE"); + strcat(RomInfo,buffer); + unsigned char tracks[2]; + Mooby2CDRgetTN(&tracks[0]); + sprintf(buffer,"Number of tracks %u\n", tracks[1]); + strcat(RomInfo,buffer); + + menu::MessageBox::getInstance().setMessage(RomInfo); +} + +extern BOOL hasLoadedISO; + +extern "C" { +void SysReset(); +void SysInit(); +void SysClose(); +void CheckCdrom(); +void LoadCdrom(); +} + +void Func_SetPlayGame(); + +void Func_ResetROM() +{ + SysClose(); + SysInit (); + CheckCdrom(); + SysReset(); + LoadCdrom(); + menu::MessageBox::getInstance().setMessage("Game restarted"); + Func_SetPlayGame(); +} + +void Func_SwapCD() +{ + //Call Filebrowser with "Swap CD" + pMenuContext->setActiveFrame(MenuContext::FRAME_LOADROM,FileBrowserFrame::FILEBROWSER_SWAPCD); +} + +extern "C" char mcd1Written; +extern "C" char mcd2Written; +extern "C" int LoadState(); +extern "C" int SaveState(); +extern "C" void savestates_select_slot(unsigned int s); + +void Func_LoadSave() +{ + if(!hasLoadedISO) + { + menu::MessageBox::getInstance().setMessage("Please load a ISO first"); + return; + } + + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + case NATIVESAVEDEVICE_USB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_SD) ? &saveDir_libfat_Default:&saveDir_libfat_USB; + saveFile_readFile = fileBrowser_libfat_readFile; + saveFile_writeFile = fileBrowser_libfat_writeFile; + saveFile_init = fileBrowser_libfat_init; + saveFile_deinit = fileBrowser_libfat_deinit; + break; + case NATIVESAVEDEVICE_CARDA: + case NATIVESAVEDEVICE_CARDB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_CARDA) ? &saveDir_CARD_SlotA:&saveDir_CARD_SlotB; + saveFile_readFile = fileBrowser_CARD_readFile; + saveFile_writeFile = fileBrowser_CARD_writeFile; + saveFile_init = fileBrowser_CARD_init; + saveFile_deinit = fileBrowser_CARD_deinit; + break; + } + + // Try loading everything + int result = 0; + saveFile_init(saveFile_dir); + result += LoadMcd(1,saveFile_dir); + result += LoadMcd(2,saveFile_dir); + saveFile_deinit(saveFile_dir); + + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + if (result) menu::MessageBox::getInstance().setMessage("Loaded save from SD card"); + else menu::MessageBox::getInstance().setMessage("No saves found on SD card"); + break; + case NATIVESAVEDEVICE_USB: + if (result) menu::MessageBox::getInstance().setMessage("Loaded save from USB device"); + else menu::MessageBox::getInstance().setMessage("No saves found on USB device"); + break; + case NATIVESAVEDEVICE_CARDA: + if (result) menu::MessageBox::getInstance().setMessage("Loaded save from memcard in slot A"); + else menu::MessageBox::getInstance().setMessage("No saves found on memcard A"); + break; + case NATIVESAVEDEVICE_CARDB: + if (result) menu::MessageBox::getInstance().setMessage("Loaded save from memcard in slot A"); + else menu::MessageBox::getInstance().setMessage("No saves found on memcard B"); + break; + } + mcd1Written = mcd2Written = false; +} + +void Func_SaveGame() +{ + if(!mcd1Written && !mcd2Written) { + menu::MessageBox::getInstance().setMessage("Nothing to save"); + return; + } + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + case NATIVESAVEDEVICE_USB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_SD) ? &saveDir_libfat_Default:&saveDir_libfat_USB; + saveFile_readFile = fileBrowser_libfat_readFile; + saveFile_writeFile = fileBrowser_libfat_writeFile; + saveFile_init = fileBrowser_libfat_init; + saveFile_deinit = fileBrowser_libfat_deinit; + break; + case NATIVESAVEDEVICE_CARDA: + case NATIVESAVEDEVICE_CARDB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_CARDA) ? &saveDir_CARD_SlotA:&saveDir_CARD_SlotB; + saveFile_readFile = fileBrowser_CARD_readFile; + saveFile_writeFile = fileBrowser_CARD_writeFile; + saveFile_init = fileBrowser_CARD_init; + saveFile_deinit = fileBrowser_CARD_deinit; + break; + } + + // Try saving everything + int amountSaves = mcd1Written + mcd2Written; + int result = 0; + saveFile_init(saveFile_dir); + result += SaveMcd(1,saveFile_dir); + result += SaveMcd(2,saveFile_dir); + saveFile_deinit(saveFile_dir); + + if (result==amountSaves) { + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + menu::MessageBox::getInstance().setMessage("Saved game to SD card"); + break; + case NATIVESAVEDEVICE_USB: + menu::MessageBox::getInstance().setMessage("Saved game to USB device"); + break; + case NATIVESAVEDEVICE_CARDA: + menu::MessageBox::getInstance().setMessage("Saved game to memcard in Slot A"); + break; + case NATIVESAVEDEVICE_CARDB: + menu::MessageBox::getInstance().setMessage("Saved game to memcard in Slot B"); + break; + } + mcd1Written = mcd2Written = false; + } + else menu::MessageBox::getInstance().setMessage("Failed to Save"); + +} + +void Func_LoadState() +{ + if(LoadState()) { + menu::MessageBox::getInstance().setMessage("Save State Loaded Successfully"); + } else { + menu::MessageBox::getInstance().setMessage("Save doesn't exist"); + } +} + +void Func_SaveState() +{ + if(SaveState()) { + menu::MessageBox::getInstance().setMessage("Save State Saved Successfully"); + } else { + menu::MessageBox::getInstance().setMessage("Error Saving State"); + } +} + +static unsigned int which_slot = 0; + +void Func_StateCycle() +{ + + which_slot = (which_slot+1) %10; + savestates_select_slot(which_slot); + FRAME_STRINGS[7][5] = which_slot + '0'; + +} + +void Func_ReturnFromCurrentRomFrame() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); +} diff --git a/Gamecube/menu/CurrentRomFrame.h b/Gamecube/menu/CurrentRomFrame.h new file mode 100644 index 0000000..a776455 --- /dev/null +++ b/Gamecube/menu/CurrentRomFrame.h @@ -0,0 +1,37 @@ +/** + * Wii64 - CurrentRomFrame.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef CURRENTROMFRAME_H +#define CURRENTROMFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class CurrentRomFrame : public menu::Frame +{ +public: + CurrentRomFrame(); + ~CurrentRomFrame(); + +private: + +}; + +#endif diff --git a/Gamecube/menu/FileBrowserFrame.cpp b/Gamecube/menu/FileBrowserFrame.cpp new file mode 100644 index 0000000..09f365c --- /dev/null +++ b/Gamecube/menu/FileBrowserFrame.cpp @@ -0,0 +1,563 @@ +/** + * WiiSX - FileBrowserFrame.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include +#include +#include "MenuContext.h" +#include "FileBrowserFrame.h" +#include "../libgui/Button.h" +#include "../libgui/resources.h" +#include "../libgui/MessageBox.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../../psxcommon.h" + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-DVD.h" +#include "../fileBrowser/fileBrowser-CARD.h" +#include "../fileBrowser/fileBrowser-SMB.h" +extern long Mooby2CDRgetTN(unsigned char *buffer); +} + +void Func_PrevPage(); +void Func_NextPage(); +void Func_ReturnFromFileBrowserFrame(); +void Func_Select1(); +void Func_Select2(); +void Func_Select3(); +void Func_Select4(); +void Func_Select5(); +void Func_Select6(); +void Func_Select7(); +void Func_Select8(); +void Func_Select9(); +void Func_Select10(); + +#define NUM_FRAME_BUTTONS 12 +#define NUM_FILE_SLOTS 10 +#define FRAME_BUTTONS fileBrowserFrameButtons +#define FRAME_STRINGS fileBrowserFrameStrings + +static char FRAME_STRINGS[3][5] = + { "Prev", + "Next", + ""}; + + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_NRM, FRAME_STRINGS[0], 35.0, 220.0, 70.0, 40.0, -1, -1, -1, 2, Func_PrevPage, Func_ReturnFromFileBrowserFrame }, // Prev + { NULL, BTN_A_NRM, FRAME_STRINGS[1], 535.0, 220.0, 70.0, 40.0, -1, -1, 2, -1, Func_NextPage, Func_ReturnFromFileBrowserFrame }, // Next + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 40.0, 400.0, 35.0, 11, 3, 0, 1, Func_Select1, Func_ReturnFromFileBrowserFrame }, // File Button 1 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 80.0, 400.0, 35.0, 2, 4, 0, 1, Func_Select2, Func_ReturnFromFileBrowserFrame }, // File Button 2 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 120.0, 400.0, 35.0, 3, 5, 0, 1, Func_Select3, Func_ReturnFromFileBrowserFrame }, // File Button 3 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 160.0, 400.0, 35.0, 4, 6, 0, 1, Func_Select4, Func_ReturnFromFileBrowserFrame }, // File Button 4 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 200.0, 400.0, 35.0, 5, 7, 0, 1, Func_Select5, Func_ReturnFromFileBrowserFrame }, // File Button 5 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 240.0, 400.0, 35.0, 6, 8, 0, 1, Func_Select6, Func_ReturnFromFileBrowserFrame }, // File Button 6 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 280.0, 400.0, 35.0, 7, 9, 0, 1, Func_Select7, Func_ReturnFromFileBrowserFrame }, // File Button 7 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 320.0, 400.0, 35.0, 8, 10, 0, 1, Func_Select8, Func_ReturnFromFileBrowserFrame }, // File Button 8 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 360.0, 400.0, 35.0, 9, 11, 0, 1, Func_Select9, Func_ReturnFromFileBrowserFrame }, // File Button 9 + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 120.0, 400.0, 400.0, 35.0, 10, 2, 0, 1, Func_Select10, Func_ReturnFromFileBrowserFrame }, // File Button 10 +}; + +FileBrowserFrame::FileBrowserFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + + for (int i = 2; i < NUM_FRAME_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setLabelMode(menu::Button::LABEL_SCROLLONFOCUS); + FRAME_BUTTONS[i].button->setLabelScissor(6); + } + + setDefaultFocus(FRAME_BUTTONS[2].button); + setBackFunc(Func_ReturnFromFileBrowserFrame); + setEnabled(true); + +} + +FileBrowserFrame::~FileBrowserFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + +} + +int fileBrowserMode = FileBrowserFrame::FILEBROWSER_LOADISO; + +void FileBrowserFrame::activateSubmenu(int submenu) +{ + fileBrowserMode = submenu; +} + +static fileBrowser_file* dir_entries; +static int num_entries; +static int current_page; +static int max_page; + +void fileBrowserFrame_OpenDirectory(fileBrowser_file* dir); +void fileBrowserFrame_Error(fileBrowser_file* dir, int error_code); +void fileBrowserFrame_FillPage(); +void fileBrowserFrame_LoadFile(int i); +static int dir_comparator(const void* _x, const void* _y); + +void FileBrowserFrame::drawChildren(menu::Graphics &gfx) +{ + if(isVisible()) + { +#ifdef HW_RVL + WPADData* wiiPad = menu::Input::getInstance().getWpad(); +#endif + for (int i=0; i<4; i++) + { + u16 currentButtonsGC = PAD_ButtonsHeld(i); + if (currentButtonsGC ^ previousButtonsGC[i]) + { + u16 currentButtonsDownGC = (currentButtonsGC ^ previousButtonsGC[i]) & currentButtonsGC; + previousButtonsGC[i] = currentButtonsGC; + if (currentButtonsDownGC & PAD_TRIGGER_Z) + { + // Change sort method + fileSortMode ^= 1; + // Resort the list + qsort(dir_entries, num_entries, sizeof(fileBrowser_file), dir_comparator); + current_page = 0; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownGC & PAD_TRIGGER_R) + { + //move to next set & return + current_page = (current_page + 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownGC & PAD_TRIGGER_L) + { + //move to the previous set & return + current_page = (max_page + current_page - 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + } +#ifdef HW_RVL + else if (wiiPad[i].btns_h ^ previousButtonsWii[i]) + { + u32 currentButtonsDownWii = (wiiPad[i].btns_h ^ previousButtonsWii[i]) & wiiPad[i].btns_h; + previousButtonsWii[i] = wiiPad[i].btns_h; + if (wiiPad[i].exp.type == WPAD_EXP_CLASSIC) + { + if (currentButtonsDownWii & CLASSIC_CTRL_BUTTON_ZR) + { + // Change sort method + fileSortMode ^= 1; + // Resort the list + qsort(dir_entries, num_entries, sizeof(fileBrowser_file), dir_comparator); + current_page = 0; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_R) + { + //move to next set & return + current_page = (current_page + 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_L) + { + //move to the previous set & return + current_page = (max_page + current_page - 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + } + else + { + if (currentButtonsDownWii & WPAD_BUTTON_1) + { + // Change sort method + fileSortMode ^= 1; + // Resort the list + qsort(dir_entries, num_entries, sizeof(fileBrowser_file), dir_comparator); + current_page = 0; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownWii & WPAD_BUTTON_PLUS) + { + //move to next set & return + if(current_page+1 < max_page) + current_page = (current_page + 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + else if (currentButtonsDownWii & WPAD_BUTTON_MINUS) + { + //move to the previous set & return + current_page = (max_page + current_page - 1) % max_page; + fileBrowserFrame_FillPage(); + menu::Focus::getInstance().clearPrimaryFocus(); + break; + } + } + } +#endif //HW_RVL + } + + //Draw buttons + menu::ComponentList::const_iterator iteration; + for (iteration = componentList.begin(); iteration != componentList.end(); ++iteration) + { + (*iteration)->draw(gfx); + } + } +} + +void Func_PrevPage() +{ + if(current_page > 0) current_page -= 1; + fileBrowserFrame_FillPage(); +} + +void Func_NextPage() +{ + if(current_page+1 < max_page) current_page +=1; + fileBrowserFrame_FillPage(); +} + +extern MenuContext *pMenuContext; + +void Func_ReturnFromFileBrowserFrame() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); +} + +void Func_Select1() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 0); } + +void Func_Select2() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 1); } + +void Func_Select3() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 2); } + +void Func_Select4() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 3); } + +void Func_Select5() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 4); } + +void Func_Select6() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 5); } + +void Func_Select7() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 6); } + +void Func_Select8() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 7); } + +void Func_Select9() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 8); } + +void Func_Select10() { fileBrowserFrame_LoadFile((current_page*NUM_FILE_SLOTS) + 9); } + + +static char* filenameFromAbsPath(char* absPath) +{ + char* filename = absPath; + // Here we want to extract from the absolute path + // just the filename + // First we move the pointer all the way to the end + // of the the string so we can work our way back + while( *filename ) ++filename; + // Now, just move it back to the last '/' or the start + // of the string + while( filename != absPath && (*(filename-1) != '\\' && *(filename-1) != '/')) + --filename; + return filename; +} + +int loadISO(fileBrowser_file*); +int loadISOSwap(fileBrowser_file*); + +static int dir_comparator(const void* _x, const void* _y){ + const fileBrowser_file* x = (const fileBrowser_file*)_x; + const fileBrowser_file* y = (const fileBrowser_file*)_y; + int xIsDir = x->attr & FILE_BROWSER_ATTR_DIR; + int yIsDir = y->attr & FILE_BROWSER_ATTR_DIR; + // Directories go on top, otherwise alphabetical + if(fileSortMode && xIsDir != yIsDir) + return yIsDir - xIsDir; + else + return stricmp(x->name, y->name); +} + +void fileBrowserFrame_OpenDirectory(fileBrowser_file* dir) +{ + // Free the old menu stuff +// if(menu_items){ free(menu_items); menu_items = NULL; } + if(dir_entries){ free(dir_entries); dir_entries = NULL; } + + // Read the directories and return on error + num_entries = isoFile_readDir(dir, &dir_entries); + if(num_entries <= 0) + { + if(dir_entries) { free(dir_entries); dir_entries = NULL; } + fileBrowserFrame_Error(dir, num_entries); + return; + } + + // Sort the listing + qsort(dir_entries, num_entries, sizeof(fileBrowser_file), dir_comparator); + + current_page = 0; + max_page = (int)ceil((float)num_entries/NUM_FILE_SLOTS); + fileBrowserFrame_FillPage(); +} + +void fileBrowserFrame_Error(fileBrowser_file* dir, int error_code) +{ + char feedback_string[256]; + //disable all buttons + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button->setActive(false); + for (int i = 0; iname) + sprintf(feedback_string,"Error opening directory \"%s\"",&dir->name[0]); + else + strcpy(feedback_string,"An error occured"); +/* FRAME_BUTTONS[2].buttonString = feedback_string; + FRAME_BUTTONS[2].button->setClicked(Func_ReturnFromFileBrowserFrame); + FRAME_BUTTONS[2].button->setActive(true); + for (int i = 1; isetNextFocus(menu::Focus::DIRECTION_UP, NULL); + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + pMenuContext->getFrame(MenuContext::FRAME_FILEBROWSER)->setDefaultFocus(FRAME_BUTTONS[2].button); + menu::Focus::getInstance().clearPrimaryFocus();*/ + menu::MessageBox::getInstance().setMessage(feedback_string); + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); +} + +void fileBrowserFrame_FillPage() +{ + //Restore next focus directions for top item in list + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[2].focusUp].button); + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[2].focusDown].button); + + //disable all buttons + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setActive(false); + FRAME_BUTTONS[i].button->setLabelColor((GXColor) {255,255,255,255}); + } + //set entries according to page + for (int i = 0; i < NUM_FILE_SLOTS; i++) + { + if ((current_page*NUM_FILE_SLOTS) + i < num_entries) + { + FRAME_BUTTONS[i+2].buttonString = filenameFromAbsPath(dir_entries[i+(current_page*NUM_FILE_SLOTS)].name); + FRAME_BUTTONS[i+2].button->setClicked(FRAME_BUTTONS[i+2].clickedFunc); + FRAME_BUTTONS[i+2].button->setActive(true); + if(dir_entries[i+(current_page*NUM_FILE_SLOTS)].attr & FILE_BROWSER_ATTR_DIR) + FRAME_BUTTONS[i+2].button->setLabelColor((GXColor) {255,50,50,255}); + } + else + FRAME_BUTTONS[i+2].buttonString = FRAME_STRINGS[2]; + } + if (!FRAME_BUTTONS[3].button->getActive()) + { //NULL out up/down focus if there's only one item in list + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_UP, NULL); + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + } + //activate next/prev buttons + if (current_page > 0) FRAME_BUTTONS[0].button->setActive(true); + if (current_page+1 < max_page) FRAME_BUTTONS[1].button->setActive(true); + //set default focus past "." and ".." entries + int default_index = 0; + while ( (!strcmp(filenameFromAbsPath(dir_entries[default_index+(current_page*NUM_FILE_SLOTS)].name),".") || + !strcmp(filenameFromAbsPath(dir_entries[default_index+(current_page*NUM_FILE_SLOTS)].name),"..")) && + num_entries > default_index+1 ) default_index++; + pMenuContext->getFrame(MenuContext::FRAME_FILEBROWSER)->setDefaultFocus(FRAME_BUTTONS[default_index+2].button); +} + +extern BOOL hasLoadedISO; +extern char CdromId[10]; +extern char CdromLabel[33]; +extern signed char autoSaveLoaded; +void Func_SetPlayGame(); +extern "C" { +void newCD(fileBrowser_file *file); +} + +void fileBrowserFrame_LoadFile(int i) +{ + char feedback_string[256] = "Failed to load ISO"; + if(dir_entries[i].attr & FILE_BROWSER_ATTR_DIR){ + // Here we are 'recursing' into a subdirectory + // We have to do a little dance here to avoid a dangling pointer + fileBrowser_file* dir = (fileBrowser_file*)malloc( sizeof(fileBrowser_file) ); + memcpy(dir, dir_entries+i, sizeof(fileBrowser_file)); + fileBrowserFrame_OpenDirectory(dir); + free(dir); + menu::Focus::getInstance().clearPrimaryFocus(); + } else if (fileBrowserMode == FileBrowserFrame::FILEBROWSER_LOADISO) { + // We must select this file + int ret = loadISO( &dir_entries[i] ); + + if(!ret){ // If the read succeeded. + strcpy(feedback_string, "Loaded "); + strncat(feedback_string, filenameFromAbsPath(dir_entries[i].name), 36-7); + + char RomInfo[512] = ""; + char buffer [50]; + strcat(RomInfo,feedback_string); + sprintf(buffer,"\nCD-ROM Label: %s\n",CdromLabel); + strcat(RomInfo,buffer); + sprintf(buffer,"CD-ROM ID: %s\n", CdromId); + strcat(RomInfo,buffer); + sprintf(buffer,"ISO Size: %u Mb\n",isoFile.size/1024/1024); + strcat(RomInfo,buffer); + sprintf(buffer,"Country: %s\n",(!Config.PsxType) ? "NTSC":"PAL"); + strcat(RomInfo,buffer); + sprintf(buffer,"BIOS: %s\n",(Config.HLE==BIOS_USER_DEFINED) ? "USER DEFINED":"HLE"); + strcat(RomInfo,buffer); + unsigned char tracks[2]; + Mooby2CDRgetTN(&tracks[0]); + sprintf(buffer,"Number of tracks %u\n", tracks[1]); + strcat(RomInfo,buffer); + + + switch (autoSaveLoaded) + { + case NATIVESAVEDEVICE_NONE: + break; + case NATIVESAVEDEVICE_SD: + strcat(RomInfo,"\nFound & loaded save from SD card\n"); + break; + case NATIVESAVEDEVICE_USB: + strcat(RomInfo,"\nFound & loaded save from USB device\n"); + break; + case NATIVESAVEDEVICE_CARDA: + strcat(RomInfo,"\nFound & loaded save from memcard in slot A\n"); + break; + case NATIVESAVEDEVICE_CARDB: + strcat(RomInfo,"\nFound & loaded save from memcard in slot B\n"); + break; + } + autoSaveLoaded = NATIVESAVEDEVICE_NONE; + + menu::MessageBox::getInstance().setMessage(RomInfo); + } + else // If not. + { +/* switch(ret) { + case ROM_CACHE_ERROR_READ: + strcpy(feedback_string,"A read error occured"); + break; + case ROM_CACHE_INVALID_ROM: + strcpy(feedback_string,"Invalid ROM type"); + break; + default: + strcpy(feedback_string,"An error has occured"); + break; + } +*/ + menu::MessageBox::getInstance().setMessage(feedback_string); + } + +/* //disable all buttons + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button->setActive(false); + //set first entry to report 'success'/'error' and return to main menu + FRAME_BUTTONS[2].buttonString = feedback_string; + FRAME_BUTTONS[2].button->setClicked(Func_ReturnFromFileBrowserFrame); + FRAME_BUTTONS[2].button->setActive(true); + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_UP, NULL); + FRAME_BUTTONS[2].button->setNextFocus(menu::Focus::DIRECTION_DOWN, NULL); + for (int i = 1; igetFrame(MenuContext::FRAME_FILEBROWSER)->setDefaultFocus(FRAME_BUTTONS[2].button); + menu::Focus::getInstance().clearPrimaryFocus();*/ + + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); + //if(hasLoadedISO) Func_SetPlayGame(); + Func_SetPlayGame(); //hasLoadedISO will be set to False if SysInit() fails + } + else if (fileBrowserMode == FileBrowserFrame::FILEBROWSER_SWAPCD) { + //TODO: Properly implement this + int ret = loadISOSwap( &dir_entries[i] ); + if(!ret) { + menu::MessageBox::getInstance().setMessage("Swapped CD"); + } else { + menu::MessageBox::getInstance().setMessage("Error swapping CD"); + } + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); + } +} diff --git a/Gamecube/menu/FileBrowserFrame.h b/Gamecube/menu/FileBrowserFrame.h new file mode 100644 index 0000000..3af59f6 --- /dev/null +++ b/Gamecube/menu/FileBrowserFrame.h @@ -0,0 +1,48 @@ +/** + * WiiSX - FileBrowserFrame.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef FILEBROWSERFRAME_H +#define FILEBROWSERFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class FileBrowserFrame : public menu::Frame +{ +public: + FileBrowserFrame(); + ~FileBrowserFrame(); + void drawChildren(menu::Graphics& gfx); + void activateSubmenu(int submenu); + + enum FilebrowserMode + { + FILEBROWSER_LOADISO=1, + FILEBROWSER_SWAPCD, + + }; + +private: + u16 previousButtonsGC[4]; + u32 previousButtonsWii[4]; + +}; + +#endif diff --git a/Gamecube/menu/LoadRomFrame.cpp b/Gamecube/menu/LoadRomFrame.cpp new file mode 100644 index 0000000..a357aea --- /dev/null +++ b/Gamecube/menu/LoadRomFrame.cpp @@ -0,0 +1,212 @@ +/** + * WiiSX - LoadRomFrame.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "MenuContext.h" +#include "LoadRomFrame.h" +#include "FileBrowserFrame.h" +#include "../libgui/Button.h" +#include "../libgui/resources.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../libgui/MessageBox.h" + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-SMB.h" +#include "../fileBrowser/fileBrowser-DVD.h" +#include "../fileBrowser/fileBrowser-CARD.h" +} + +void Func_LoadFromSD(); +void Func_LoadFromDVD(); +void Func_LoadFromUSB(); +void Func_LoadFromSamba(); +void Func_ReturnFromLoadRomFrame(); + +#define NUM_FRAME_BUTTONS 4 +#define FRAME_BUTTONS loadRomFrameButtons +#define FRAME_STRINGS loadRomFrameStrings + +static char FRAME_STRINGS[4][25] = + { "Load from SD", + "Load from DVD", + "Load from USB", + "Load from Samba"}; + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_NRM, FRAME_STRINGS[0], 150.0, 100.0, 340.0, 56.0, 3, 1, -1, -1, Func_LoadFromSD, Func_ReturnFromLoadRomFrame }, // Load From SD + { NULL, BTN_A_NRM, FRAME_STRINGS[1], 150.0, 180.0, 340.0, 56.0, 0, 2, -1, -1, Func_LoadFromDVD, Func_ReturnFromLoadRomFrame }, // Load From DVD + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 150.0, 260.0, 340.0, 56.0, 1, 3, -1, -1, Func_LoadFromUSB, Func_ReturnFromLoadRomFrame }, // Load From USB + { NULL, BTN_A_NRM, FRAME_STRINGS[3], 150.0, 340.0, 340.0, 56.0, 2, 0, -1, -1, Func_LoadFromSamba, Func_ReturnFromLoadRomFrame }, // Load From Samba +}; + +LoadRomFrame::LoadRomFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_ReturnFromLoadRomFrame); + setEnabled(true); + +} + +LoadRomFrame::~LoadRomFrame() +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + +} + +int loadRomMode = FileBrowserFrame::FILEBROWSER_LOADISO; + +void LoadRomFrame::activateSubmenu(int submenu) +{ + loadRomMode = submenu; +} + + +extern MenuContext *pMenuContext; +extern void fileBrowserFrame_OpenDirectory(fileBrowser_file* dir); + +void Func_LoadFromSD() +{ + // Deinit any existing romFile state + if(isoFile_deinit) isoFile_deinit( &isoFile ); + // Change all the romFile pointers + isoFile_topLevel = &topLevel_libfat_Default; + isoFile_readDir = fileBrowser_libfat_readDir; + isoFile_open = fileBrowser_libfat_open; + isoFile_readFile = fileBrowser_libfatROM_readFile; + isoFile_seekFile = fileBrowser_libfat_seekFile; + isoFile_init = fileBrowser_libfat_init; + isoFile_deinit = fileBrowser_libfatROM_deinit; + // Make sure the romFile system is ready before we browse the filesystem + isoFile_init( isoFile_topLevel ); + + pMenuContext->setActiveFrame(MenuContext::FRAME_FILEBROWSER,loadRomMode); + fileBrowserFrame_OpenDirectory(isoFile_topLevel); +} + +void Func_LoadFromDVD() +{ + // Deinit any existing romFile state + if(isoFile_deinit) isoFile_deinit( &isoFile ); + // Change all the romFile pointers + isoFile_topLevel = &topLevel_DVD; + isoFile_readDir = fileBrowser_DVD_readDir; + isoFile_open = fileBrowser_DVD_open; + isoFile_readFile = fileBrowser_DVD_readFile; + isoFile_seekFile = fileBrowser_DVD_seekFile; + isoFile_init = fileBrowser_DVD_init; + isoFile_deinit = fileBrowser_DVD_deinit; + // Make sure the romFile system is ready before we browse the filesystem + isoFile_init( isoFile_topLevel ); + + pMenuContext->setActiveFrame(MenuContext::FRAME_FILEBROWSER,loadRomMode); + fileBrowserFrame_OpenDirectory(isoFile_topLevel); +} + +void Func_LoadFromUSB() +{ +#ifdef WII + // Deinit any existing romFile state + if(isoFile_deinit) isoFile_deinit( &isoFile ); + // Change all the romFile pointers + isoFile_topLevel = &topLevel_libfat_USB; + isoFile_readDir = fileBrowser_libfat_readDir; + isoFile_open = fileBrowser_libfat_open; + isoFile_readFile = fileBrowser_libfatROM_readFile; + isoFile_seekFile = fileBrowser_libfat_seekFile; + isoFile_init = fileBrowser_libfat_init; + isoFile_deinit = fileBrowser_libfatROM_deinit; + // Make sure the romFile system is ready before we browse the filesystem + isoFile_init( isoFile_topLevel ); + + pMenuContext->setActiveFrame(MenuContext::FRAME_FILEBROWSER,loadRomMode); + fileBrowserFrame_OpenDirectory(isoFile_topLevel); +#else + menu::MessageBox::getInstance().setMessage("Available only for Wii"); +#endif +} + +void Func_LoadFromSamba() +{ +#ifdef HW_RVL + // Deinit any existing romFile state + if(isoFile_deinit) isoFile_deinit( &isoFile ); + // Change all the romFile pointers + isoFile_topLevel = &topLevel_SMB; + isoFile_readDir = fileBrowser_SMB_readDir; + isoFile_open = fileBrowser_SMB_open; + isoFile_readFile = fileBrowser_SMB_readFile; + isoFile_seekFile = fileBrowser_SMB_seekFile; + isoFile_init = fileBrowser_SMB_init; + isoFile_deinit = fileBrowser_SMB_deinit; + // Make sure the romFile system is ready before we browse the filesystem + isoFile_init( isoFile_topLevel ); + + pMenuContext->setActiveFrame(MenuContext::FRAME_FILEBROWSER,loadRomMode); + fileBrowserFrame_OpenDirectory(isoFile_topLevel); +#else + menu::MessageBox::getInstance().setMessage("Available only for Wii"); +#endif +} + +void Func_ReturnFromLoadRomFrame() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); +} diff --git a/Gamecube/menu/LoadRomFrame.h b/Gamecube/menu/LoadRomFrame.h new file mode 100644 index 0000000..422dabc --- /dev/null +++ b/Gamecube/menu/LoadRomFrame.h @@ -0,0 +1,38 @@ +/** + * WiiSX - LoadRomFrame.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef LOADROMFRAME_H +#define LOADROMFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class LoadRomFrame : public menu::Frame +{ +public: + LoadRomFrame(); + ~LoadRomFrame(); + void activateSubmenu(int submenu); + +private: + +}; + +#endif diff --git a/Gamecube/menu/MainFrame.cpp b/Gamecube/menu/MainFrame.cpp new file mode 100644 index 0000000..9114d9d --- /dev/null +++ b/Gamecube/menu/MainFrame.cpp @@ -0,0 +1,336 @@ +/** + * WiiSX - MainFrame.cpp + * Copyright (C) 2009 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "MenuContext.h" +#include "MainFrame.h" +#include "SettingsFrame.h" +#include "../libgui/Button.h" +#include "../libgui/Gui.h" +#include "../libgui/InputStatusBar.h" +#include "../libgui/resources.h" +//#include "../libgui/InputManager.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../libgui/MessageBox.h" +//#include "../main/wii64config.h" +#ifdef DEBUGON +# include +#endif +extern "C" { +#ifdef WII +#include +#endif +/*#include "../gc_memory/memory.h" +#include "../gc_memory/Saves.h" +#include "../main/plugin.h" +#include "../main/savestates.h"*/ +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-CARD.h" +#include "../fileBrowser/fileBrowser-SMB.h" +//#include "../main/gc_dvd.h" +} +#include + +void Func_LoadROM(); +void Func_CurrentROM(); +void Func_Settings(); +void Func_Credits(); +void Func_ExitToLoader(); +void Func_PlayGame(); + +#define NUM_MAIN_BUTTONS 6 +#define FRAME_BUTTONS mainFrameButtons +#define FRAME_STRINGS mainFrameStrings + +char FRAME_STRINGS[7][20] = + { "Load ISO", + "Current ISO", + "Settings", + "Credits", + "Quit", + "Play Game", + "Resume Game"}; + + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_MAIN_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + { NULL, BTN_A_NRM, FRAME_STRINGS[0], 315.0, 60.0, 200.0, 56.0, 5, 1, -1, -1, Func_LoadROM, NULL }, // Load ROM + { NULL, BTN_A_NRM, FRAME_STRINGS[1], 315.0, 120.0, 200.0, 56.0, 0, 2, -1, -1, Func_CurrentROM, NULL }, // Current ROM + { NULL, BTN_A_NRM, FRAME_STRINGS[2], 315.0, 180.0, 200.0, 56.0, 1, 3, -1, -1, Func_Settings, NULL }, // Settings + { NULL, BTN_A_NRM, FRAME_STRINGS[3], 315.0, 240.0, 200.0, 56.0, 2, 4, -1, -1, Func_Credits, NULL }, // Credits + { NULL, BTN_A_NRM, FRAME_STRINGS[4], 315.0, 300.0, 200.0, 56.0, 3, 5, -1, -1, Func_ExitToLoader, NULL }, // Exit to Loader + { NULL, BTN_A_NRM, FRAME_STRINGS[5], 315.0, 360.0, 200.0, 56.0, 4, 0, -1, -1, Func_PlayGame, NULL }, // Play/Resume Game +}; + +MainFrame::MainFrame() +{ + inputStatusBar = new menu::InputStatusBar(450,100); + add(inputStatusBar); + + for (int i = 0; i < NUM_MAIN_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_MAIN_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + setDefaultFocus(FRAME_BUTTONS[0].button); + setEnabled(true); + +} + +MainFrame::~MainFrame() +{ + for (int i = 0; i < NUM_MAIN_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } + delete inputStatusBar; +} + +extern MenuContext *pMenuContext; + +void Func_LoadROM() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_LOADROM,FileBrowserFrame::FILEBROWSER_LOADISO); +} + +extern BOOL hasLoadedISO; + +void Func_CurrentROM() +{ + if(!hasLoadedISO) + { + menu::MessageBox::getInstance().setMessage("Please load an ISO first"); + return; + } + + pMenuContext->setActiveFrame(MenuContext::FRAME_CURRENTROM); +} + +void Func_Settings() +{ + menu::Gui::getInstance().menuLogo->setLocation(580.0, 410.0, -50.0); + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_GENERAL); +} + +void Func_Credits() +{ + char CreditsInfo[512] = ""; +#ifdef HW_RVL + strcat(CreditsInfo,"WiiSXRX Beta 2.2\n"); +#else + strcat(CreditsInfo,"CubeSXRX Beta 2.2\n"); +#endif + strcat(CreditsInfo,"github.com/niuus/WiiSXRX\n"); + strcat(CreditsInfo,"WiiSXRX: NiuuS\n"); + strcat(CreditsInfo,"\n"); + strcat(CreditsInfo,"Original WiiSX Team:\n"); + strcat(CreditsInfo,"emu_kidid - general coding\n"); + strcat(CreditsInfo,"sepp256 - graphics & menu\n"); + strcat(CreditsInfo,"tehpola - audio\n"); + strcat(CreditsInfo,"\n"); + #ifdef HW_RVL + strcat(CreditsInfo,"matguitarist - USB 2.0 Support\n"); + strcat(CreditsInfo,"Daxtsu - libwupc support\n"); + strcat(CreditsInfo,"NiuuS - WiiSXRX logo\n"); +#endif + + menu::MessageBox::getInstance().setMessage(CreditsInfo); +} + +extern char shutdown; + +void Func_ExitToLoader() +{ + if(menu::MessageBox::getInstance().askMessage("Are you sure you want to exit to loader?")) + shutdown = 2; +} + +extern "C" { +void cpu_init(); +void cpu_deinit(); +} + +extern "C" { +extern int SaveMcd(int mcd, fileBrowser_file *savepath); +void pauseAudio(void); void pauseInput(void); +void resumeAudio(void); void resumeInput(void); +void go(void); +} + +//void control_info_init(); + +extern char menuActive; +extern char autoSave; +extern "C" char mcd1Written; +extern "C" char mcd2Written; +extern "C" unsigned int usleep(unsigned int us); + +void Func_PlayGame() +{ + if(!hasLoadedISO) + { + menu::MessageBox::getInstance().setMessage("Please load an ISO first"); + return; + } + + //Wait until 'A' button released before play/resume game + menu::Cursor::getInstance().setFreezeAction(true); + menu::Focus::getInstance().setFreezeAction(true); + int buttonHeld = 1; + while(buttonHeld) + { + buttonHeld = 0; + menu::Gui::getInstance().draw(); + for (int i=0; i<4; i++) + { + if(PAD_ButtonsHeld(i) & PAD_BUTTON_A) buttonHeld++; +#ifdef HW_RVL + WPADData* wiiPad = WPAD_Data(i); + if(wiiPad->err == WPAD_ERR_NONE && wiiPad->btns_h & (WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A)) buttonHeld++; + + WUPCData* data = WUPC_Data(i); + if (data != NULL && data->button & WPAD_CLASSIC_BUTTON_A) buttonHeld++; +#endif + } + } + menu::Cursor::getInstance().setFreezeAction(false); + menu::Focus::getInstance().setFreezeAction(false); + + menu::Gui::getInstance().gfx->clearEFB((GXColor){0, 0, 0, 0xFF}, 0x000000); +#ifdef HW_RVL + pause_netinit_thread(); + pauseRemovalThread(); +#endif + resumeAudio(); + resumeInput(); + menuActive = 0; +#ifdef DEBUGON + _break(); +#endif + go(); +#ifdef DEBUGON + _break(); +#endif + menuActive = 1; + pauseInput(); + pauseAudio(); + + if(autoSave==AUTOSAVE_ENABLE) { + if(mcd1Written || mcd2Written) { //something needs saving + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + case NATIVESAVEDEVICE_USB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_SD) ? &saveDir_libfat_Default:&saveDir_libfat_USB; + saveFile_readFile = fileBrowser_libfat_readFile; + saveFile_writeFile = fileBrowser_libfat_writeFile; + saveFile_init = fileBrowser_libfat_init; + saveFile_deinit = fileBrowser_libfat_deinit; + break; + case NATIVESAVEDEVICE_CARDA: + case NATIVESAVEDEVICE_CARDB: + // Adjust saveFile pointers + saveFile_dir = (nativeSaveDevice==NATIVESAVEDEVICE_CARDA) ? &saveDir_CARD_SlotA:&saveDir_CARD_SlotB; + saveFile_readFile = fileBrowser_CARD_readFile; + saveFile_writeFile = fileBrowser_CARD_writeFile; + saveFile_init = fileBrowser_CARD_init; + saveFile_deinit = fileBrowser_CARD_deinit; + break; + } + // Try saving everything + int amountSaves = mcd1Written + mcd2Written; + int result = 0; + saveFile_init(saveFile_dir); + result += SaveMcd(1,saveFile_dir); + result += SaveMcd(2,saveFile_dir); + saveFile_deinit(saveFile_dir); + if (result==amountSaves) { //saved all of them ok + switch (nativeSaveDevice) + { + case NATIVESAVEDEVICE_SD: + menu::MessageBox::getInstance().fadeMessage("Automatically saved to SD card"); + break; + case NATIVESAVEDEVICE_USB: + menu::MessageBox::getInstance().fadeMessage("Automatically saved to USB device"); + break; + case NATIVESAVEDEVICE_CARDA: + menu::MessageBox::getInstance().fadeMessage("Automatically saved to memcard in Slot A"); + break; + case NATIVESAVEDEVICE_CARDB: + menu::MessageBox::getInstance().fadeMessage("Automatically saved to memcard in Slot B"); + break; + } + mcd1Written = mcd2Written = 0; //nothing new written since save + } + else { + menu::MessageBox::getInstance().setMessage("Failed to save game"); //one or more failed to save + } + + } + } +#ifdef HW_RVL + continueRemovalThread(); + resume_netinit_thread(); +#endif + FRAME_BUTTONS[5].buttonString = FRAME_STRINGS[6]; + menu::Cursor::getInstance().clearCursorFocus(); +} + +void Func_SetPlayGame() +{ + FRAME_BUTTONS[5].buttonString = FRAME_STRINGS[5]; +} + +void Func_SetResumeGame() +{ + FRAME_BUTTONS[5].buttonString = FRAME_STRINGS[6]; +} diff --git a/Gamecube/menu/MainFrame.h b/Gamecube/menu/MainFrame.h new file mode 100644 index 0000000..f6773d4 --- /dev/null +++ b/Gamecube/menu/MainFrame.h @@ -0,0 +1,38 @@ +/** + * Wii64 - MainFrame.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef MAINFRAME_H +#define MAINFRAME_H + +#include "../libgui/Frame.h" +#include "../libgui/InputStatusBar.h" +#include "MenuTypes.h" + +class MainFrame : public menu::Frame +{ +public: + MainFrame(); + ~MainFrame(); + +private: + menu::InputStatusBar *inputStatusBar; +}; + +#endif diff --git a/Gamecube/menu/MenuContext.cpp b/Gamecube/menu/MenuContext.cpp new file mode 100644 index 0000000..322e14c --- /dev/null +++ b/Gamecube/menu/MenuContext.cpp @@ -0,0 +1,162 @@ +/** + * WiiSX - MenuContext.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include "MenuContext.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" + +MenuContext *pMenuContext; + +MenuContext::MenuContext(GXRModeObj *vmode) + : currentActiveFrame(0), + mainFrame(0), + loadRomFrame(0), + fileBrowserFrame(0), + currentRomFrame(0), + settingsFrame(0), + configureInputFrame(0), + configureButtonsFrame(0) +{ + pMenuContext = this; + + menu::Gui::getInstance().setVmode(vmode); + + mainFrame = new MainFrame(); + loadRomFrame = new LoadRomFrame(); + fileBrowserFrame = new FileBrowserFrame(); + currentRomFrame = new CurrentRomFrame(); + settingsFrame = new SettingsFrame(); + configureInputFrame = new ConfigureInputFrame(); + configureButtonsFrame = new ConfigureButtonsFrame(); + + menu::Gui::getInstance().addFrame(mainFrame); + menu::Gui::getInstance().addFrame(loadRomFrame); + menu::Gui::getInstance().addFrame(fileBrowserFrame); + menu::Gui::getInstance().addFrame(currentRomFrame); + menu::Gui::getInstance().addFrame(settingsFrame); + menu::Gui::getInstance().addFrame(configureInputFrame); + menu::Gui::getInstance().addFrame(configureButtonsFrame); + + menu::Focus::getInstance().setFocusActive(true); + setActiveFrame(FRAME_MAIN); +} + +MenuContext::~MenuContext() +{ + delete configureButtonsFrame; + delete configureInputFrame; + delete settingsFrame; + delete currentRomFrame; + delete fileBrowserFrame; + delete loadRomFrame; + delete mainFrame; + pMenuContext = NULL; +} + +bool MenuContext::isRunning() +{ + bool isRunning = true; +// printf("MenuContext isRunning\n"); + draw(); + +/* PADStatus* gcPad = menu::Input::getInstance().getPad(); + if(gcPad[0].button & PAD_BUTTON_START) + isRunning = false;*/ + + return isRunning; +} + +void MenuContext::setActiveFrame(int frameIndex) +{ + if(currentActiveFrame) + currentActiveFrame->hideFrame(); + + switch(frameIndex) { + case FRAME_MAIN: + currentActiveFrame = mainFrame; + break; + case FRAME_LOADROM: + currentActiveFrame = loadRomFrame; + break; + case FRAME_FILEBROWSER: + currentActiveFrame = fileBrowserFrame; + break; + case FRAME_CURRENTROM: + currentActiveFrame = currentRomFrame; + break; + case FRAME_SETTINGS: + currentActiveFrame = settingsFrame; + break; + case FRAME_CONFIGUREINPUT: + currentActiveFrame = configureInputFrame; + break; + case FRAME_CONFIGUREBUTTONS: + currentActiveFrame = configureButtonsFrame; + break; + } + + if(currentActiveFrame) + { + currentActiveFrame->showFrame(); + menu::Focus::getInstance().setCurrentFrame(currentActiveFrame); + menu::Cursor::getInstance().setCurrentFrame(currentActiveFrame); + } +} + +void MenuContext::setActiveFrame(int frameIndex, int submenu) +{ + setActiveFrame(frameIndex); + if(currentActiveFrame) currentActiveFrame->activateSubmenu(submenu); +} + +menu::Frame* MenuContext::getFrame(int frameIndex) +{ + menu::Frame* pFrame = NULL; + switch(frameIndex) { + case FRAME_MAIN: + pFrame = mainFrame; + break; + case FRAME_LOADROM: + pFrame = loadRomFrame; + break; + case FRAME_FILEBROWSER: + pFrame = fileBrowserFrame; + break; + case FRAME_CURRENTROM: + pFrame = currentRomFrame; + break; + case FRAME_SETTINGS: + pFrame = settingsFrame; + break; + case FRAME_CONFIGUREINPUT: + pFrame = configureInputFrame; + break; + case FRAME_CONFIGUREBUTTONS: + pFrame = configureButtonsFrame; + break; + } + + return pFrame; +} + +void MenuContext::draw() +{ + menu::Gui::getInstance().draw(); +} diff --git a/Gamecube/menu/MenuContext.h b/Gamecube/menu/MenuContext.h new file mode 100644 index 0000000..423938d --- /dev/null +++ b/Gamecube/menu/MenuContext.h @@ -0,0 +1,71 @@ +/** + * WiiSX - MenuContext.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef MENUCONTEXT_H +#define MENUCONTEXT_H + +#include "../libgui/Gui.h" +#include "../libgui/Frame.h" +#include "../libgui/InputManager.h" +#include "MainFrame.h" +#include "LoadRomFrame.h" +#include "FileBrowserFrame.h" +#include "CurrentRomFrame.h" +#include "SettingsFrame.h" +#include "ConfigureInputFrame.h" +#include "ConfigureButtonsFrame.h" + +#include "MenuTypes.h" + +class MenuContext +{ +public: + explicit MenuContext(GXRModeObj *vmode); + ~MenuContext(); + bool isRunning(); + void setActiveFrame(int frameIndex); + void setActiveFrame(int frameIndex, int submenu); + menu::Frame* getFrame(int frameIndex); + enum FrameIndices + { + FRAME_MAIN=1, + FRAME_LOADROM, + FRAME_FILEBROWSER, + FRAME_CURRENTROM, + FRAME_SETTINGS, + FRAME_CONFIGUREINPUT, + FRAME_CONFIGUREBUTTONS + + }; + +private: + void draw(); + menu::Frame *currentActiveFrame; + MainFrame *mainFrame; + LoadRomFrame *loadRomFrame; + FileBrowserFrame *fileBrowserFrame; + CurrentRomFrame *currentRomFrame; + SettingsFrame *settingsFrame; + ConfigureInputFrame *configureInputFrame; + ConfigureButtonsFrame *configureButtonsFrame; + +}; + +#endif diff --git a/Gamecube/menu/MenuResources.S b/Gamecube/menu/MenuResources.S new file mode 100644 index 0000000..a8ec8e9 --- /dev/null +++ b/Gamecube/menu/MenuResources.S @@ -0,0 +1,78 @@ + .rodata + + .globl BackgroundTexture + .balign 32 + BackgroundTexture: + .incbin "../menu/resources/bg.tx" + .globl BackgroundTexture_length + BackgroundTexture_length: + .long (BackgroundTexture_length - BackgroundTexture) + + .globl LogoTexture + .balign 32 + LogoTexture: +#ifdef HW_RVL + .incbin "../menu/resources/wiiSX.tx" +#else + .incbin "../menu/resources/cubeSX.tx" +#endif + .globl LogoTexture_length + LogoTexture_length: + .long (LogoTexture_length - LogoTexture) + + .globl LoadingTexture + .balign 32 + LoadingTexture: + .incbin "../menu/resources/Loading.tx" + .globl LoadingTexture_length + LoadingTexture_length: + .long (LoadingTexture_length - LoadingTexture) + + .globl ControlEmptyTexture + .balign 32 + ControlEmptyTexture: + .incbin "../menu/resources/cntrlEmpty.tx" + .globl ControlEmptyTexture_length + ControlEmptyTexture_length: + .long (ControlEmptyTexture_length - ControlEmptyTexture) + + .globl ControlGamecubeTexture + .balign 32 + ControlGamecubeTexture: + .incbin "../menu/resources/cntrlGC.tx" + .globl ControlGamecubeTexture_length + ControlGamecubeTexture_length: + .long (ControlGamecubeTexture_length - ControlGamecubeTexture) + + .globl ControlClassicTexture + .balign 32 + ControlClassicTexture: + .incbin "../menu/resources/cntrlClassic.tx" + .globl ControlClassicTexture_length + ControlClassicTexture_length: + .long (ControlClassicTexture_length - ControlClassicTexture) + + .globl ControlWiimoteNunchuckTexture + .balign 32 + ControlWiimoteNunchuckTexture: + .incbin "../menu/resources/cntrlWNC.tx" + .globl ControlWiimoteNunchuckTexture_length + ControlWiimoteNunchuckTexture_length: + .long (ControlWiimoteNunchuckTexture_length - ControlWiimoteNunchuckTexture) + + .globl ControlWiimoteTexture + .balign 32 + ControlWiimoteTexture: + .incbin "../menu/resources/cntrlWM.tx" + .globl ControlWiimoteTexture_length + ControlWiimoteTexture_length: + .long (ControlWiimoteTexture_length - ControlWiimoteTexture) + + .globl PsxControllerTexture + .balign 32 + PsxControllerTexture: + .incbin "../menu/resources/psxCntrl.tx" + .globl PsxControllerTexture_length + PsxControllerTexture_length: + .long (PsxControllerTexture_length - PsxControllerTexture) + diff --git a/Gamecube/menu/MenuResources.h b/Gamecube/menu/MenuResources.h new file mode 100644 index 0000000..e0b92d2 --- /dev/null +++ b/Gamecube/menu/MenuResources.h @@ -0,0 +1,34 @@ +/** + * Wii64 - MenuResources.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef MENURESOURCES_H +#define MENURESOURCES_H + +extern u8 BackgroundTexture[]; +extern u8 LogoTexture[]; +extern u8 LoadingTexture[]; +extern u8 ControlEmptyTexture[]; +extern u8 ControlGamecubeTexture[]; +extern u8 ControlClassicTexture[]; +extern u8 ControlWiimoteNunchuckTexture[]; +extern u8 ControlWiimoteTexture[]; +extern u8 PsxControllerTexture[]; + +#endif diff --git a/Gamecube/menu/MenuTypes.h b/Gamecube/menu/MenuTypes.h new file mode 100644 index 0000000..6e95e2a --- /dev/null +++ b/Gamecube/menu/MenuTypes.h @@ -0,0 +1,30 @@ +/** + * Wii64 - MenuTypes.h + * Copyright (C) 2009 sepp256 + * + * Wii64 homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef MENUDEFS_H +#define MENUDEFS_H + +class MenuContext; +class MainFrame; +class LoadRomFrame; + +//extern MenuContext *pMenuContext; + +#endif diff --git a/Gamecube/menu/SettingsFrame.cpp b/Gamecube/menu/SettingsFrame.cpp new file mode 100644 index 0000000..e423913 --- /dev/null +++ b/Gamecube/menu/SettingsFrame.cpp @@ -0,0 +1,1308 @@ +/** + * WiiSX - SettingsFrame.cpp + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#include + +#include "MenuContext.h" +#include "SettingsFrame.h" +#include "../libgui/Button.h" +#include "../libgui/TextBox.h" +#include "../libgui/resources.h" +#include "../libgui/FocusManager.h" +#include "../libgui/CursorManager.h" +#include "../libgui/MessageBox.h" +#include "../wiiSXconfig.h" +#include "../../psxcommon.h" + +extern "C" { +#include "../gc_input/controller.h" +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-CARD.h" +} + +extern void Func_SetPlayGame(); + +void Func_TabGeneral(); +void Func_TabVideo(); +void Func_TabInput(); +void Func_TabAudio(); +void Func_TabSaves(); + +void Func_CpuInterp(); +void Func_CpuDynarec(); +void Func_BiosSelectHLE(); +void Func_BiosSelectSD(); +void Func_BiosSelectUSB(); +void Func_BiosSelectDVD(); +void Func_BootBiosYes(); +void Func_BootBiosNo(); +void Func_ExecuteBios(); +void Func_SaveSettingsSD(); +void Func_SaveSettingsUSB(); + +void Func_ShowFpsOn(); +void Func_ShowFpsOff(); +void Func_FpsLimitAuto(); +void Func_FpsLimitOff(); +void Func_FrameSkipOn(); +void Func_FrameSkipOff(); +void Func_ScreenMode4_3(); +void Func_ScreenMode16_9(); +void Func_ScreenForce16_9(); +void Func_DitheringNone(); +void Func_DitheringDefault(); +void Func_DitheringAlways(); +void Func_ScalingNone(); +void Func_Scaling2xSai(); + +void Func_ConfigureInput(); +void Func_ConfigureButtons(); +void Func_PsxTypeStandard(); +void Func_PsxTypeAnalog(); +void Func_DisableRumbleYes(); +void Func_DisableRumbleNo(); +void Func_SaveButtonsSD(); +void Func_SaveButtonsUSB(); +void Func_ToggleButtonLoad(); + +void Func_DisableAudioYes(); +void Func_DisableAudioNo(); +void Func_DisableXaYes(); +void Func_DisableXaNo(); +void Func_DisableCddaYes(); +void Func_DisableCddaNo(); +void Func_VolumeToggle(); + +void Func_MemcardSaveSD(); +void Func_MemcardSaveUSB(); +void Func_MemcardSaveCardA(); +void Func_MemcardSaveCardB(); +void Func_AutoSaveYes(); +void Func_AutoSaveNo(); +void Func_SaveStateSD(); +void Func_SaveStateUSB(); + +void Func_ReturnFromSettingsFrame(); + +extern BOOL hasLoadedISO; +extern int stop; +extern char menuActive; + +extern "C" { +void SysReset(); +int SysInit(); +void SysClose(); +void SysStartCPU(); +void CheckCdrom(); +void LoadCdrom(); +void pauseAudio(void); void pauseInput(void); +void resumeAudio(void); void resumeInput(void); +} + +#define NUM_FRAME_BUTTONS 54 +#define NUM_TAB_BUTTONS 5 +#define FRAME_BUTTONS settingsFrameButtons +#define FRAME_STRINGS settingsFrameStrings +#define NUM_FRAME_TEXTBOXES 21 +#define FRAME_TEXTBOXES settingsFrameTextBoxes + +/* +General Tab: +Select CPU Core: Interpreter; Dynarec +Select Bios: HLE; SD; USB +Boot Games Through Bios: Yes; No +Execute Bios +Save settings.cfg: SD; USB + +Video Tab: +Show FPS: Yes; No +Limit FPS: Auto; Off; xxx +Frame Skip: On; Off +Screen Mode: 4:3; 16:9 +Scaling: None; 2xSaI +Dithering: None; Game Dependent; Always + +Input Tab: +Assign Controllers (assign player->pad) +Configure Button Mappings +PSX Controller Type: Standard/Analog/Light Gun +Number of Multitaps: 0, 1, 2 + +Audio Tab: +Disable Audio: Yes; No +Disable XA: Yes; No +Disable CDDA: Yes; No +Volume Level: ("0: low", "1: medium", "2: loud", "3: loudest") + Note: iVolume=4-ComboBox_GetCurSel(hWC);, so 1 is loudest and 4 is low; default is medium + +Saves Tab: +Memcard Save Device: SD; USB; CardA; CardB +Auto Save Memcards: Yes; No +Save States Device: SD; USB +*/ + +static char FRAME_STRINGS[56][24] = + { "General", + "Video", + "Input", + "Audio", + "Saves", + //Strings for General tab (starting at FRAME_STRINGS[5]) + "Select CPU Core", + "Select Bios", + "Boot Through Bios", + "Execute Bios", + "Save settings.cfg", + "Interpreter", + "Dynarec", + "HLE", + "SD", + "USB", + "DVD", + "Yes", + "No", + //Strings for Video tab (starting at FRAME_STRINGS[18])..was[]) + "Show FPS", + "Limit FPS", + "Frame Skip", + "Screen Mode", + "Dithering", + "Scaling", + "On", + "Off", + "Auto", + "4:3", + "16:9", + "Force 16:9", + "None", + "2xSaI", + "Default", + "Always", + //Strings for Input tab (starting at FRAME_STRINGS[34]..was[]) + "Configure Input", + "Configure Buttons", + "PSX Controller Type", + "Disable Rumble", + "Standard", + "Analog", + "Save Button Configs", + "Auto Load Slot:", + "Default", + //Strings for Audio tab (starting at FRAME_STRINGS[43]) ..was[47] + "Disable Audio", + "Disable XA", + "Disable CDDA", + "Volume", + "loudest", //iVolume=1 + "loud", + "medium", + "low", //iVolume=4 + //Strings for Saves tab (starting at FRAME_STRINGS[51]) ..was[55] + "Memcard Save Device", + "Auto Save Memcards", + "Save States Device", + "CardA", + "CardB"}; + + +struct ButtonInfo +{ + menu::Button *button; + int buttonStyle; + char* buttonString; + float x; + float y; + float width; + float height; + int focusUp; + int focusDown; + int focusLeft; + int focusRight; + ButtonFunc clickedFunc; + ButtonFunc returnFunc; +} FRAME_BUTTONS[NUM_FRAME_BUTTONS] = +{ // button buttonStyle buttonString x y width height Up Dwn Lft Rt clickFunc returnFunc + //Buttons for Tabs (starts at button[0]) + { NULL, BTN_A_SEL, FRAME_STRINGS[0], 25.0, 30.0, 110.0, 56.0, -1, -1, 4, 1, Func_TabGeneral, Func_ReturnFromSettingsFrame }, // General tab + { NULL, BTN_A_SEL, FRAME_STRINGS[1], 155.0, 30.0, 100.0, 56.0, -1, -1, 0, 2, Func_TabVideo, Func_ReturnFromSettingsFrame }, // Video tab + { NULL, BTN_A_SEL, FRAME_STRINGS[2], 275.0, 30.0, 100.0, 56.0, -1, -1, 1, 3, Func_TabInput, Func_ReturnFromSettingsFrame }, // Input tab + { NULL, BTN_A_SEL, FRAME_STRINGS[3], 395.0, 30.0, 100.0, 56.0, -1, -1, 2, 4, Func_TabAudio, Func_ReturnFromSettingsFrame }, // Audio tab + { NULL, BTN_A_SEL, FRAME_STRINGS[4], 515.0, 30.0, 100.0, 56.0, -1, -1, 3, 0, Func_TabSaves, Func_ReturnFromSettingsFrame }, // Saves tab + //Buttons for General Tab (starts at button[5]) + { NULL, BTN_A_SEL, FRAME_STRINGS[10], 295.0, 100.0, 160.0, 56.0, 0, 7, 6, 6, Func_CpuInterp, Func_ReturnFromSettingsFrame }, // CPU: Interp + { NULL, BTN_A_SEL, FRAME_STRINGS[11], 465.0, 100.0, 130.0, 56.0, 0, 9, 5, 5, Func_CpuDynarec, Func_ReturnFromSettingsFrame }, // CPU: Dynarec + { NULL, BTN_A_SEL, FRAME_STRINGS[12], 295.0, 170.0, 70.0, 56.0, 5, 11, 10, 8, Func_BiosSelectHLE, Func_ReturnFromSettingsFrame }, // Bios: HLE + { NULL, BTN_A_SEL, FRAME_STRINGS[13], 375.0, 170.0, 55.0, 56.0, 5, 12, 7, 9, Func_BiosSelectSD, Func_ReturnFromSettingsFrame }, // Bios: SD + { NULL, BTN_A_SEL, FRAME_STRINGS[14], 440.0, 170.0, 70.0, 56.0, 6, 12, 8, 10, Func_BiosSelectUSB, Func_ReturnFromSettingsFrame }, // Bios: USB + { NULL, BTN_A_SEL, FRAME_STRINGS[15], 520.0, 170.0, 70.0, 56.0, 6, 12, 9, 7, Func_BiosSelectDVD, Func_ReturnFromSettingsFrame }, // Bios: DVD + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 295.0, 240.0, 75.0, 56.0, 7, 13, 12, 12, Func_BootBiosYes, Func_ReturnFromSettingsFrame }, // Boot Thru Bios: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 380.0, 240.0, 75.0, 56.0, 8, 13, 11, 11, Func_BootBiosNo, Func_ReturnFromSettingsFrame }, // Boot Thru Bios: No + { NULL, BTN_A_NRM, FRAME_STRINGS[8], 295.0, 310.0, 200.0, 56.0, 11, 14, -1, -1, Func_ExecuteBios, Func_ReturnFromSettingsFrame }, // Execute Bios + { NULL, BTN_A_NRM, FRAME_STRINGS[13], 295.0, 380.0, 55.0, 56.0, 13, 0, 15, 15, Func_SaveSettingsSD, Func_ReturnFromSettingsFrame }, // Save Settings: SD + { NULL, BTN_A_NRM, FRAME_STRINGS[14], 360.0, 380.0, 70.0, 56.0, 13, 0, 14, 14, Func_SaveSettingsUSB, Func_ReturnFromSettingsFrame }, // Save Settings: USB + //Buttons for Video Tab (starts at button[16]) + { NULL, BTN_A_SEL, FRAME_STRINGS[24], 325.0, 100.0, 75.0, 56.0, 1, 18, 17, 17, Func_ShowFpsOn, Func_ReturnFromSettingsFrame }, // Show FPS: On + { NULL, BTN_A_SEL, FRAME_STRINGS[25], 420.0, 100.0, 75.0, 56.0, 1, 19, 16, 16, Func_ShowFpsOff, Func_ReturnFromSettingsFrame }, // Show FPS: Off + { NULL, BTN_A_SEL, FRAME_STRINGS[26], 325.0, 170.0, 75.0, 56.0, 16, 20, 19, 19, Func_FpsLimitAuto, Func_ReturnFromSettingsFrame }, // FPS Limit: Auto + { NULL, BTN_A_SEL, FRAME_STRINGS[25], 420.0, 170.0, 75.0, 56.0, 17, 21, 18, 18, Func_FpsLimitOff, Func_ReturnFromSettingsFrame }, // FPS Limit: Off + { NULL, BTN_A_SEL, FRAME_STRINGS[24], 325.0, 240.0, 75.0, 56.0, 18, 23, 21, 21, Func_FrameSkipOn, Func_ReturnFromSettingsFrame }, // Frame Skip: On + { NULL, BTN_A_SEL, FRAME_STRINGS[25], 420.0, 240.0, 75.0, 56.0, 19, 24, 20, 20, Func_FrameSkipOff, Func_ReturnFromSettingsFrame }, // Frame Skip: Off + { NULL, BTN_A_SEL, FRAME_STRINGS[27], 230.0, 310.0, 75.0, 56.0, 20, 25, 24, 23, Func_ScreenMode4_3, Func_ReturnFromSettingsFrame }, // ScreenMode: 4:3 + { NULL, BTN_A_SEL, FRAME_STRINGS[28], 325.0, 310.0, 75.0, 56.0, 20, 26, 22, 24, Func_ScreenMode16_9, Func_ReturnFromSettingsFrame }, // ScreenMode: 16:9 + { NULL, BTN_A_SEL, FRAME_STRINGS[29], 420.0, 310.0, 155.0, 56.0, 21, 27, 23, 22, Func_ScreenForce16_9, Func_ReturnFromSettingsFrame }, // ScreenMode: Force 16:9 + { NULL, BTN_A_SEL, FRAME_STRINGS[30], 230.0, 380.0, 75.0, 56.0, 22, 1, 27, 26, Func_DitheringNone, Func_ReturnFromSettingsFrame }, // Dithering: None + { NULL, BTN_A_SEL, FRAME_STRINGS[32], 325.0, 380.0, 110.0, 56.0, 23, 1, 25, 27, Func_DitheringDefault, Func_ReturnFromSettingsFrame }, // Dithering: Game Dependent + { NULL, BTN_A_SEL, FRAME_STRINGS[33], 455.0, 380.0, 110.0, 56.0, 24, 1, 26, 25, Func_DitheringAlways, Func_ReturnFromSettingsFrame }, // Dithering: Always + { NULL, BTN_A_SEL, FRAME_STRINGS[30], 325.0, 430.0, 75.0, 56.0, -1, -1, 29, 29, Func_ScalingNone, Func_ReturnFromSettingsFrame }, // Scaling: None + { NULL, BTN_A_SEL, FRAME_STRINGS[31], 420.0, 430.0, 75.0, 56.0, -1, -1, 28, 28, Func_Scaling2xSai, Func_ReturnFromSettingsFrame }, // Scaling: 2xSai + //Buttons for Input Tab (starts at button[30]) + { NULL, BTN_A_NRM, FRAME_STRINGS[34], 90.0, 100.0, 220.0, 56.0, 2, 32, 31, 31, Func_ConfigureInput, Func_ReturnFromSettingsFrame }, // Configure Input Assignment + { NULL, BTN_A_NRM, FRAME_STRINGS[35], 325.0, 100.0, 235.0, 56.0, 2, 32, 30, 30, Func_ConfigureButtons, Func_ReturnFromSettingsFrame }, // Configure Button Mappings + { NULL, BTN_A_SEL, FRAME_STRINGS[38], 285.0, 170.0, 130.0, 56.0, 30, 34, 33, 33, Func_PsxTypeStandard, Func_ReturnFromSettingsFrame }, // PSX Controller Type: Standard + { NULL, BTN_A_SEL, FRAME_STRINGS[39], 425.0, 170.0, 110.0, 56.0, 31, 35, 32, 32, Func_PsxTypeAnalog, Func_ReturnFromSettingsFrame }, // PSX Controller Type: Analog + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 285.0, 240.0, 75.0, 56.0, 32, 36, 35, 35, Func_DisableRumbleYes, Func_ReturnFromSettingsFrame }, // Disable Rumble: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 380.0, 240.0, 75.0, 56.0, 33, 37, 34, 34, Func_DisableRumbleNo, Func_ReturnFromSettingsFrame }, // Disable Rumble: No + { NULL, BTN_A_NRM, FRAME_STRINGS[13], 285.0, 310.0, 55.0, 56.0, 34, 38, 37, 37, Func_SaveButtonsSD, Func_ReturnFromSettingsFrame }, // Save Button Mappings: SD + { NULL, BTN_A_NRM, FRAME_STRINGS[14], 350.0, 310.0, 70.0, 56.0, 35, 38, 36, 36, Func_SaveButtonsUSB, Func_ReturnFromSettingsFrame }, // Save Button Mappings: USB + { NULL, BTN_A_NRM, FRAME_STRINGS[42], 285.0, 380.0, 135.0, 56.0, 36, 2, -1, -1, Func_ToggleButtonLoad, Func_ReturnFromSettingsFrame }, // Auto Load Button Config Slot: Default,1,2,3,4 + //Buttons for Audio Tab (starts at button[39]) ..was[41] + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 345.0, 100.0, 75.0, 56.0, 3, 41, 40, 40, Func_DisableAudioYes, Func_ReturnFromSettingsFrame }, // Disable Audio: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 440.0, 100.0, 75.0, 56.0, 3, 42, 39, 39, Func_DisableAudioNo, Func_ReturnFromSettingsFrame }, // Disable Audio: No + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 345.0, 170.0, 75.0, 56.0, 39, 43, 42, 42, Func_DisableXaYes, Func_ReturnFromSettingsFrame }, // Disable XA: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 440.0, 170.0, 75.0, 56.0, 40, 44, 41, 41, Func_DisableXaNo, Func_ReturnFromSettingsFrame }, // Disable XA: No + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 345.0, 240.0, 75.0, 56.0, 41, 45, 44, 44, Func_DisableCddaYes, Func_ReturnFromSettingsFrame }, // Disable CDDA: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 440.0, 240.0, 75.0, 56.0, 42, 45, 43, 43, Func_DisableCddaNo, Func_ReturnFromSettingsFrame }, // Disable CDDA: No + { NULL, BTN_A_NRM, FRAME_STRINGS[47], 345.0, 310.0, 170.0, 56.0, 43, 3, -1, -1, Func_VolumeToggle, Func_ReturnFromSettingsFrame }, // Volume: low/medium/loud/loudest + //Buttons for Saves Tab (starts at button[46]) ..was[48] + { NULL, BTN_A_SEL, FRAME_STRINGS[13], 295.0, 100.0, 55.0, 56.0, 4, 50, 49, 47, Func_MemcardSaveSD, Func_ReturnFromSettingsFrame }, // Memcard Save: SD + { NULL, BTN_A_SEL, FRAME_STRINGS[14], 360.0, 100.0, 70.0, 56.0, 4, 51, 46, 48, Func_MemcardSaveUSB, Func_ReturnFromSettingsFrame }, // Memcard Save: USB + { NULL, BTN_A_SEL, FRAME_STRINGS[54], 440.0, 100.0, 90.0, 56.0, 4, 51, 47, 49, Func_MemcardSaveCardA, Func_ReturnFromSettingsFrame }, // Memcard Save: Card A + { NULL, BTN_A_SEL, FRAME_STRINGS[55], 540.0, 100.0, 90.0, 56.0, 4, 51, 48, 46, Func_MemcardSaveCardB, Func_ReturnFromSettingsFrame }, // Memcard Save: Card B + { NULL, BTN_A_SEL, FRAME_STRINGS[16], 295.0, 170.0, 75.0, 56.0, 46, 52, 51, 51, Func_AutoSaveYes, Func_ReturnFromSettingsFrame }, // Auto Save Memcards: Yes + { NULL, BTN_A_SEL, FRAME_STRINGS[17], 380.0, 170.0, 75.0, 56.0, 47, 53, 50, 50, Func_AutoSaveNo, Func_ReturnFromSettingsFrame }, // Auto Save Memcards: No + { NULL, BTN_A_SEL, FRAME_STRINGS[13], 295.0, 240.0, 55.0, 56.0, 50, 4, 53, 53, Func_SaveStateSD, Func_ReturnFromSettingsFrame }, // Save State: SD + { NULL, BTN_A_SEL, FRAME_STRINGS[14], 360.0, 240.0, 70.0, 56.0, 51, 4, 52, 52, Func_SaveStateUSB, Func_ReturnFromSettingsFrame }, // Save State: USB +}; + +struct TextBoxInfo +{ + menu::TextBox *textBox; + char* textBoxString; + float x; + float y; + float scale; + bool centered; +} FRAME_TEXTBOXES[NUM_FRAME_TEXTBOXES] = +{ // textBox textBoxString x y scale centered + //TextBoxes for General Tab (starts at textBox[0]) + { NULL, FRAME_STRINGS[5], 155.0, 128.0, 1.0, true }, // CPU Core: Pure Interp/Dynarec + { NULL, FRAME_STRINGS[6], 155.0, 198.0, 1.0, true }, // Bios: HLE/SD/USB/DVD + { NULL, FRAME_STRINGS[7], 155.0, 268.0, 1.0, true }, // Boot Thru Bios: Yes/No + { NULL, FRAME_STRINGS[9], 155.0, 408.0, 1.0, true }, // Save settings.cfg: SD/USB + //TextBoxes for Video Tab (starts at textBox[4]) + { NULL, FRAME_STRINGS[18], 190.0, 128.0, 1.0, true }, // Show FPS: On/Off + { NULL, FRAME_STRINGS[19], 190.0, 198.0, 1.0, true }, // Limit FPS: Auto/Off + { NULL, FRAME_STRINGS[20], 190.0, 268.0, 1.0, true }, // Frame Skip: On/Off + { NULL, FRAME_STRINGS[21], 130.0, 338.0, 1.0, true }, // ScreenMode: 4x3/16x9/Force16x9 + { NULL, FRAME_STRINGS[22], 130.0, 408.0, 1.0, true }, // Dithering: None/Game Dependent/Always + { NULL, FRAME_STRINGS[23], 190.0, 478.0, 1.0, true }, // Scaling: None/2xSai + //TextBoxes for Input Tab (starts at textBox[10]) + { NULL, FRAME_STRINGS[36], 145.0, 198.0, 1.0, true }, // PSX Controller Type: Analog/Digital/Light Gun + { NULL, FRAME_STRINGS[37], 145.0, 268.0, 1.0, true }, // Disable Rumble: Yes/No + { NULL, FRAME_STRINGS[40], 145.0, 338.0, 1.0, true }, // Save Button Configs: SD/USB + { NULL, FRAME_STRINGS[41], 145.0, 408.0, 1.0, true }, // Auto Load Slot: Default/1/2/3/4 + //TextBoxes for Audio Tab (starts at textBox[14]) ..was[12] + { NULL, FRAME_STRINGS[43], 210.0, 128.0, 1.0, true }, // Disable Audio: Yes/No + { NULL, FRAME_STRINGS[44], 210.0, 198.0, 1.0, true }, // Disable XA Audio: Yes/No + { NULL, FRAME_STRINGS[45], 210.0, 268.0, 1.0, true }, // Disable CDDA Audio: Yes/No + { NULL, FRAME_STRINGS[46], 210.0, 338.0, 1.0, true }, // Volume: low/medium/loud/loudest + //TextBoxes for Saves Tab (starts at textBox[18]) ..was[16] + { NULL, FRAME_STRINGS[51], 150.0, 128.0, 1.0, true }, // Memcard Save Device: SD/USB/CardA/CardB + { NULL, FRAME_STRINGS[52], 150.0, 198.0, 1.0, true }, // Auto Save Memcards: Yes/No + { NULL, FRAME_STRINGS[53], 150.0, 268.0, 1.0, true }, // Save State Device: SD/USB +}; + +SettingsFrame::SettingsFrame() + : activeSubmenu(SUBMENU_GENERAL) +{ + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + FRAME_BUTTONS[i].button = new menu::Button(FRAME_BUTTONS[i].buttonStyle, &FRAME_BUTTONS[i].buttonString, + FRAME_BUTTONS[i].x, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].height); + + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + if (FRAME_BUTTONS[i].focusUp != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[FRAME_BUTTONS[i].focusUp].button); + if (FRAME_BUTTONS[i].focusDown != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[FRAME_BUTTONS[i].focusDown].button); + if (FRAME_BUTTONS[i].focusLeft != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_LEFT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusLeft].button); + if (FRAME_BUTTONS[i].focusRight != -1) FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_RIGHT, FRAME_BUTTONS[FRAME_BUTTONS[i].focusRight].button); + FRAME_BUTTONS[i].button->setActive(true); + if (FRAME_BUTTONS[i].clickedFunc) FRAME_BUTTONS[i].button->setClicked(FRAME_BUTTONS[i].clickedFunc); + if (FRAME_BUTTONS[i].returnFunc) FRAME_BUTTONS[i].button->setReturn(FRAME_BUTTONS[i].returnFunc); + add(FRAME_BUTTONS[i].button); + menu::Cursor::getInstance().addComponent(this, FRAME_BUTTONS[i].button, FRAME_BUTTONS[i].x, + FRAME_BUTTONS[i].x+FRAME_BUTTONS[i].width, FRAME_BUTTONS[i].y, + FRAME_BUTTONS[i].y+FRAME_BUTTONS[i].height); + } + + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + { + FRAME_TEXTBOXES[i].textBox = new menu::TextBox(&FRAME_TEXTBOXES[i].textBoxString, + FRAME_TEXTBOXES[i].x, FRAME_TEXTBOXES[i].y, + FRAME_TEXTBOXES[i].scale, FRAME_TEXTBOXES[i].centered); + add(FRAME_TEXTBOXES[i].textBox); + } + + setDefaultFocus(FRAME_BUTTONS[0].button); + setBackFunc(Func_ReturnFromSettingsFrame); + setEnabled(true); + activateSubmenu(SUBMENU_GENERAL); +} + +SettingsFrame::~SettingsFrame() +{ + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + delete FRAME_TEXTBOXES[i].textBox; + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + menu::Cursor::getInstance().removeComponent(this, FRAME_BUTTONS[i].button); + delete FRAME_BUTTONS[i].button; + } +} + +void SettingsFrame::activateSubmenu(int submenu) +{ + activeSubmenu = submenu; + + //All buttons: hide; unselect + for (int i = 0; i < NUM_FRAME_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(false); + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[i].button->setActive(false); + } + //All textBoxes: hide + for (int i = 0; i < NUM_FRAME_TEXTBOXES; i++) + { + FRAME_TEXTBOXES[i].textBox->setVisible(false); + } + switch (activeSubmenu) //Tab buttons: set visible; set focus up/down; set selected + { //Config buttons: set visible; set selected + case SUBMENU_GENERAL: + setDefaultFocus(FRAME_BUTTONS[0].button); + for (int i = 0; i < NUM_TAB_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[5].button); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[14].button); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 0; i < 4; i++) + FRAME_TEXTBOXES[i].textBox->setVisible(true); + FRAME_BUTTONS[0].button->setSelected(true); + if (dynacore == DYNACORE_INTERPRETER) FRAME_BUTTONS[5].button->setSelected(true); + else FRAME_BUTTONS[6].button->setSelected(true); + FRAME_BUTTONS[7+biosDevice].button->setSelected(true); + if (LoadCdBios == BOOTTHRUBIOS_YES) FRAME_BUTTONS[11].button->setSelected(true); + else FRAME_BUTTONS[12].button->setSelected(true); + for (int i = 5; i < 16; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setActive(true); + } + break; + case SUBMENU_VIDEO: + setDefaultFocus(FRAME_BUTTONS[1].button); + for (int i = 0; i < NUM_TAB_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[16].button); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[26].button); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 4; i < 9; i++) + FRAME_TEXTBOXES[i].textBox->setVisible(true); + FRAME_BUTTONS[1].button->setSelected(true); + if (showFPSonScreen == FPS_SHOW) FRAME_BUTTONS[16].button->setSelected(true); + else FRAME_BUTTONS[17].button->setSelected(true); + if (frameLimit == FRAMELIMIT_AUTO) FRAME_BUTTONS[18].button->setSelected(true); + else FRAME_BUTTONS[19].button->setSelected(true); + if (frameSkip == FRAMESKIP_ENABLE) FRAME_BUTTONS[20].button->setSelected(true); + else FRAME_BUTTONS[21].button->setSelected(true); + if (screenMode == SCREENMODE_4x3) FRAME_BUTTONS[22].button->setSelected(true); + else if (screenMode == SCREENMODE_16x9) FRAME_BUTTONS[23].button->setSelected(true); + else FRAME_BUTTONS[24].button->setSelected(true); + FRAME_BUTTONS[25+iUseDither].button->setSelected(true); + for (int i = 16; i < 28; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setActive(true); + } + break; + case SUBMENU_INPUT: + setDefaultFocus(FRAME_BUTTONS[2].button); + for (int i = 0; i < NUM_TAB_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[30].button); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[38].button); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 10; i < 14; i++) + FRAME_TEXTBOXES[i].textBox->setVisible(true); + FRAME_BUTTONS[2].button->setSelected(true); + FRAME_BUTTONS[32+controllerType].button->setSelected(true); + FRAME_BUTTONS[34+rumbleEnabled].button->setSelected(true); + for (int i = 30; i < 39; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setActive(true); + } + break; + case SUBMENU_AUDIO: + setDefaultFocus(FRAME_BUTTONS[3].button); + for (int i = 0; i < NUM_TAB_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[39].button); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[45].button); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 14; i < 18; i++) + FRAME_TEXTBOXES[i].textBox->setVisible(true); + FRAME_BUTTONS[3].button->setSelected(true); + if (audioEnabled == AUDIO_DISABLE) FRAME_BUTTONS[39].button->setSelected(true); + else FRAME_BUTTONS[40].button->setSelected(true); + if (Config.Xa == XA_DISABLE) FRAME_BUTTONS[41].button->setSelected(true); + else FRAME_BUTTONS[42].button->setSelected(true); + if (Config.Cdda == CDDA_DISABLE) FRAME_BUTTONS[43].button->setSelected(true); + else FRAME_BUTTONS[44].button->setSelected(true); + FRAME_BUTTONS[45].buttonString = FRAME_STRINGS[46+iVolume]; + for (int i = 39; i < 46; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 43; i <= 44; i++) //disable CDDA buttons + { + FRAME_BUTTONS[i].button->setActive(false); + } + break; + case SUBMENU_SAVES: + setDefaultFocus(FRAME_BUTTONS[4].button); + for (int i = 0; i < NUM_TAB_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_DOWN, FRAME_BUTTONS[46].button); + FRAME_BUTTONS[i].button->setNextFocus(menu::Focus::DIRECTION_UP, FRAME_BUTTONS[52].button); + FRAME_BUTTONS[i].button->setActive(true); + } + for (int i = 18; i < 21; i++) + FRAME_TEXTBOXES[i].textBox->setVisible(true); + FRAME_BUTTONS[4].button->setSelected(true); + FRAME_BUTTONS[46+nativeSaveDevice].button->setSelected(true); + if (autoSave == AUTOSAVE_ENABLE) FRAME_BUTTONS[50].button->setSelected(true); + else FRAME_BUTTONS[51].button->setSelected(true); + if (saveStateDevice == SAVESTATEDEVICE_SD) FRAME_BUTTONS[52].button->setSelected(true); + else FRAME_BUTTONS[53].button->setSelected(true); + for (int i = 46; i < NUM_FRAME_BUTTONS; i++) + { + FRAME_BUTTONS[i].button->setVisible(true); + FRAME_BUTTONS[i].button->setActive(true); + } + break; + } +} + +void SettingsFrame::drawChildren(menu::Graphics &gfx) +{ + if(isVisible()) + { +#ifdef HW_RVL + WPADData* wiiPad = menu::Input::getInstance().getWpad(); +#endif + for (int i=0; i<4; i++) + { + u16 currentButtonsGC = PAD_ButtonsHeld(i); + if (currentButtonsGC ^ previousButtonsGC[i]) + { + u16 currentButtonsDownGC = (currentButtonsGC ^ previousButtonsGC[i]) & currentButtonsGC; + previousButtonsGC[i] = currentButtonsGC; + if (currentButtonsDownGC & PAD_TRIGGER_R) + { + //move to next tab + if(activeSubmenu < SUBMENU_SAVES) + { + activateSubmenu(activeSubmenu+1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + else if (currentButtonsDownGC & PAD_TRIGGER_L) + { + //move to the previous tab + if(activeSubmenu > SUBMENU_GENERAL) + { + activateSubmenu(activeSubmenu-1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + } +#ifdef HW_RVL + else if (wiiPad[i].btns_h ^ previousButtonsWii[i]) + { + u32 currentButtonsDownWii = (wiiPad[i].btns_h ^ previousButtonsWii[i]) & wiiPad[i].btns_h; + previousButtonsWii[i] = wiiPad[i].btns_h; + if (wiiPad[i].exp.type == WPAD_EXP_CLASSIC) + { + if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_R) + { + //move to next tab + if(activeSubmenu < SUBMENU_SAVES) + { + activateSubmenu(activeSubmenu+1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + else if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_L) + { + //move to the previous tab + if(activeSubmenu > SUBMENU_GENERAL) + { + activateSubmenu(activeSubmenu-1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + } + else + { + if (currentButtonsDownWii & WPAD_BUTTON_PLUS) + { + //move to next tab + if(activeSubmenu < SUBMENU_SAVES) + { + activateSubmenu(activeSubmenu+1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + else if (currentButtonsDownWii & WPAD_BUTTON_MINUS) + { + //move to the previous tab + if(activeSubmenu > SUBMENU_GENERAL) + { + activateSubmenu(activeSubmenu-1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + } + } + else if (WUPC_ButtonsHeld(i) ^ previousButtonsWii[i]) + { + u32 wupcHeld = WUPC_ButtonsHeld(i); + u32 currentButtonsDownWii = (wupcHeld ^ previousButtonsWii[i]) & wupcHeld; + previousButtonsWii[i] = wupcHeld; + + if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_R) + { + //move to next tab + if (activeSubmenu < SUBMENU_SAVES) + { + activateSubmenu(activeSubmenu + 1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + else if (currentButtonsDownWii & WPAD_CLASSIC_BUTTON_FULL_L) + { + //move to the previous tab + if (activeSubmenu > SUBMENU_GENERAL) + { + activateSubmenu(activeSubmenu - 1); + menu::Focus::getInstance().clearPrimaryFocus(); + } + break; + } + } +#endif //HW_RVL + } + + //Draw buttons + menu::ComponentList::const_iterator iteration; + for (iteration = componentList.begin(); iteration != componentList.end(); ++iteration) + { + (*iteration)->draw(gfx); + } + } +} + +extern MenuContext *pMenuContext; + +void Func_TabGeneral() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_GENERAL); +} + +void Func_TabVideo() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_VIDEO); +} + +void Func_TabInput() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_INPUT); +} + +void Func_TabAudio() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_AUDIO); +} + +void Func_TabSaves() +{ + pMenuContext->setActiveFrame(MenuContext::FRAME_SETTINGS,SettingsFrame::SUBMENU_SAVES); +} + +void Func_CpuInterp() +{ + for (int i = 5; i <= 6; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[5].button->setSelected(true); + + int needInit = 0; + if(hasLoadedISO && dynacore != DYNACORE_INTERPRETER){ SysClose(); needInit = 1; } + dynacore = DYNACORE_INTERPRETER; + if(hasLoadedISO && needInit) { + SysInit(); + CheckCdrom(); + SysReset(); + LoadCdrom(); + Func_SetPlayGame(); + menu::MessageBox::getInstance().setMessage("Game Reset"); + } +} + +void Func_CpuDynarec() +{ + for (int i = 5; i <= 6; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[6].button->setSelected(true); + + int needInit = 0; + if(hasLoadedISO && dynacore != DYNACORE_DYNAREC){ SysClose(); needInit = 1; } + dynacore = DYNACORE_DYNAREC; + if(hasLoadedISO && needInit) { + SysInit (); + CheckCdrom(); + SysReset(); + LoadCdrom(); + Func_SetPlayGame(); + menu::MessageBox::getInstance().setMessage("Game Reset"); + } +} + +void Func_BiosSelectHLE() +{ + for (int i = 7; i <= 10; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[7].button->setSelected(true); + + int needInit = 0; + if(hasLoadedISO && biosDevice != BIOSDEVICE_HLE){ SysClose(); needInit = 1; } + biosDevice = BIOSDEVICE_HLE; + if(hasLoadedISO && needInit) { + SysInit (); + CheckCdrom(); + SysReset(); + LoadCdrom(); + Func_SetPlayGame(); + menu::MessageBox::getInstance().setMessage("Game Reset"); + } +} + +int checkBiosExists(int testDevice) +{ + fileBrowser_file testFile; + memset(&testFile, 0, sizeof(fileBrowser_file)); + + biosFile_dir = (testDevice == BIOSDEVICE_SD) ? &biosDir_libfat_Default : &biosDir_libfat_USB; + sprintf(&testFile.name[0], "%s/SCPH1001.BIN", &biosFile_dir->name[0]); + biosFile_readFile = fileBrowser_libfat_readFile; + biosFile_open = fileBrowser_libfat_open; + biosFile_init = fileBrowser_libfat_init; + biosFile_deinit = fileBrowser_libfat_deinit; + biosFile_init(&testFile); //initialize the bios device (it might not be the same as ISO device) + return biosFile_open(&testFile); +} + +void Func_BiosSelectSD() +{ + for (int i = 7; i <= 10; i++) + FRAME_BUTTONS[i].button->setSelected(false); + + int needInit = 0; + if(checkBiosExists(BIOSDEVICE_SD) == FILE_BROWSER_ERROR_NO_FILE) { + menu::MessageBox::getInstance().setMessage("BIOS not found on SD"); + if(hasLoadedISO && biosDevice != BIOSDEVICE_HLE){ SysClose(); needInit = 1; } + biosDevice = BIOSDEVICE_HLE; + FRAME_BUTTONS[7].button->setSelected(true); + } + else { + if(hasLoadedISO && biosDevice != BIOSDEVICE_SD){ SysClose(); needInit = 1; } + biosDevice = BIOSDEVICE_SD; + FRAME_BUTTONS[8].button->setSelected(true); + } + if(hasLoadedISO && needInit) { + SysInit (); + CheckCdrom(); + SysReset(); + LoadCdrom(); + Func_SetPlayGame(); + menu::MessageBox::getInstance().setMessage("Game Reset"); + } +} + +void Func_BiosSelectUSB() +{ + for (int i = 7; i <= 10; i++) + FRAME_BUTTONS[i].button->setSelected(false); + + int needInit = 0; + if(checkBiosExists(BIOSDEVICE_USB) == FILE_BROWSER_ERROR_NO_FILE) { + menu::MessageBox::getInstance().setMessage("BIOS not found on USB"); + if(hasLoadedISO && biosDevice != BIOSDEVICE_HLE){ SysClose(); needInit = 1; } + biosDevice = BIOSDEVICE_HLE; + FRAME_BUTTONS[7].button->setSelected(true); + } + else { + if(hasLoadedISO && biosDevice != BIOSDEVICE_USB){ SysClose(); needInit = 1; } + biosDevice = BIOSDEVICE_USB; + FRAME_BUTTONS[9].button->setSelected(true); + } + if(hasLoadedISO && needInit) { + SysInit (); + CheckCdrom(); + SysReset(); + LoadCdrom(); + Func_SetPlayGame(); + menu::MessageBox::getInstance().setMessage("Game Reset"); + } +} + +void Func_BiosSelectDVD() +{ + menu::MessageBox::getInstance().setMessage("DVD BIOS not implemented"); +} + +void Func_BootBiosYes() +{ + /* If HLE bios selected, boot thru bios shouldn't make a difference. TODO: Check this. + if(biosDevice == BIOSDEVICE_HLE) { + menu::MessageBox::getInstance().setMessage("You must select a BIOS, not HLE"); + return; + }*/ + + for (int i = 11; i <= 12; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[11].button->setSelected(true); + + LoadCdBios = BOOTTHRUBIOS_YES; +} + +void Func_BootBiosNo() +{ + for (int i = 11; i <= 12; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[12].button->setSelected(true); + + LoadCdBios = BOOTTHRUBIOS_NO; +} + +void Func_ExecuteBios() +{ + if(biosDevice == BIOSDEVICE_HLE) { + menu::MessageBox::getInstance().setMessage("You must select a BIOS, not HLE"); + return; + } + if(hasLoadedISO) { + //TODO: Implement yes/no that current game will be reset + SysClose(); + } + + //TODO: load/save memcards here + if(SysInit() < 0) { + menu::MessageBox::getInstance().setMessage("Failed to initialize system.\nTry loading an ISO."); + return; + } + CheckCdrom(); + SysReset(); + pauseRemovalThread(); + resumeAudio(); + resumeInput(); + menuActive = 0; + SysStartCPU(); + menuActive = 1; + pauseInput(); + pauseAudio(); + continueRemovalThread(); +} + +extern void writeConfig(FILE* f); + +void Func_SaveSettingsSD() +{ + fileBrowser_file* configFile_file; + int (*configFile_init)(fileBrowser_file*) = fileBrowser_libfat_init; + configFile_file = &saveDir_libfat_Default; + struct stat s; + if (stat("sd:/wiisxrx/", &s)) { + menu::MessageBox::getInstance().setMessage("Error opening directory sd:/wiisxrx"); + return; + } + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "sd:/wiisxrx/settings.cfg", "wb" ); //attempt to open file + if(f) { + writeConfig(f); //write out the config + fclose(f); + menu::MessageBox::getInstance().setMessage("Saved settings.cfg to SD"); + return; + } + } + menu::MessageBox::getInstance().setMessage("Error saving settings.cfg to SD"); +} + +void Func_SaveSettingsUSB() +{ + fileBrowser_file* configFile_file; + int (*configFile_init)(fileBrowser_file*) = fileBrowser_libfat_init; + configFile_file = &saveDir_libfat_USB; + struct stat s; + if (stat("usb:/wiisxrx/", &s)) { + menu::MessageBox::getInstance().setMessage("Error opening directory usb:/wiisxrx"); + return; + } + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "usb:/wiisxrx/settings.cfg", "wb" ); //attempt to open file + if(f) { + writeConfig(f); //write out the config + fclose(f); + menu::MessageBox::getInstance().setMessage("Saved settings.cfg to USB"); + return; + } + } + menu::MessageBox::getInstance().setMessage("Error saving settings.cfg to USB"); +} + +void Func_ShowFpsOn() +{ + for (int i = 16; i <= 17; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[16].button->setSelected(true); + showFPSonScreen = FPS_SHOW; +} + +void Func_ShowFpsOff() +{ + for (int i = 16; i <= 17; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[17].button->setSelected(true); + showFPSonScreen = FPS_HIDE; +} + +extern "C" void GPUsetframelimit(unsigned long option); + +void Func_FpsLimitAuto() +{ + for (int i = 18; i <= 19; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[18].button->setSelected(true); + frameLimit = FRAMELIMIT_AUTO; + GPUsetframelimit(0); +} + +void Func_FpsLimitOff() +{ + for (int i = 18; i <= 19; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[19].button->setSelected(true); + frameLimit = FRAMELIMIT_NONE; + GPUsetframelimit(0); +} + +void Func_FrameSkipOn() +{ + for (int i = 20; i <= 21; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[20].button->setSelected(true); + frameSkip = FRAMESKIP_ENABLE; + GPUsetframelimit(0); +} + +void Func_FrameSkipOff() +{ + for (int i = 20; i <= 21; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[21].button->setSelected(true); + frameSkip = FRAMESKIP_DISABLE; + GPUsetframelimit(0); +} + +void Func_ScreenMode4_3() +{ + for (int i = 22; i <= 24; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[22].button->setSelected(true); + screenMode = SCREENMODE_4x3; +} + +void Func_ScreenMode16_9() +{ + for (int i = 22; i <= 24; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[23].button->setSelected(true); + screenMode = SCREENMODE_16x9; +} + +void Func_ScreenForce16_9() +{ + for (int i = 22; i <= 24; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[24].button->setSelected(true); + screenMode = SCREENMODE_16x9_PILLARBOX; +} + +void Func_DitheringNone() +{ + for (int i = 25; i <= 27; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[25].button->setSelected(true); + iUseDither = USEDITHER_NONE; + GPUsetframelimit(0); +} + +void Func_DitheringDefault() +{ + for (int i = 25; i <= 27; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[26].button->setSelected(true); + iUseDither = USEDITHER_DEFAULT; + GPUsetframelimit(0); +} + +void Func_DitheringAlways() +{ + for (int i = 25; i <= 27; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[27].button->setSelected(true); + iUseDither = USEDITHER_ALWAYS; + GPUsetframelimit(0); +} + +void Func_ScalingNone() +{ + //TODO: Implement 2xSaI scaling and then make it an option. +} + +void Func_Scaling2xSai() +{ + //TODO: Implement 2xSaI scaling and then make it an option. +} + +void Func_ConfigureInput() +{ +// menu::MessageBox::getInstance().setMessage("Input configuration not implemented"); + pMenuContext->setActiveFrame(MenuContext::FRAME_CONFIGUREINPUT,ConfigureInputFrame::SUBMENU_REINIT); +} + +void Func_ConfigureButtons() +{ +// menu::MessageBox::getInstance().setMessage("Button Mapping not implemented"); + pMenuContext->setActiveFrame(MenuContext::FRAME_CONFIGUREBUTTONS,ConfigureButtonsFrame::SUBMENU_PSX_PADNONE); +} + +void Func_PsxTypeStandard() +{ + for (int i = 32; i <= 33; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[32].button->setSelected(true); + controllerType = CONTROLLERTYPE_STANDARD; +} + +void Func_PsxTypeAnalog() +{ + for (int i = 32; i <= 33; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[33].button->setSelected(true); + controllerType = CONTROLLERTYPE_ANALOG; +} + +void Func_DisableRumbleYes() +{ + for (int i = 34; i <= 35; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[34].button->setSelected(true); + rumbleEnabled = RUMBLE_DISABLE; +} + +void Func_DisableRumbleNo() +{ + for (int i = 34; i <= 35; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[35].button->setSelected(true); + rumbleEnabled = RUMBLE_ENABLE; +} + +void Func_SaveButtonsSD() +{ + fileBrowser_file* configFile_file; + int (*configFile_init)(fileBrowser_file*) = fileBrowser_libfat_init; + int num_written = 0; + configFile_file = &saveDir_libfat_Default; + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "sd:/wiisxrx/controlG.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_GC); //write out GC controller mappings + fclose(f); + num_written++; + } +#ifdef HW_RVL + f = fopen( "sd:/wiisxrx/controlC.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_Classic); //write out Classic controller mappings + fclose(f); + num_written++; + } + f = fopen( "sd:/wiisxrx/controlN.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_WiimoteNunchuk); //write out WM+NC controller mappings + fclose(f); + num_written++; + } + f = fopen( "sd:/wiisxrx/controlW.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_Wiimote); //write out Wiimote controller mappings + fclose(f); + num_written++; + } + f = fopen("sd:/wiisxrx/controlP.cfg", "wb"); //attempt to open file + if (f) { + save_configurations(f, &controller_WiiUPro); //write out Wii U Pro controller mappings + fclose(f); + num_written++; + } +#endif //HW_RVL + } + if (num_written == num_controller_t) + menu::MessageBox::getInstance().setMessage("Saved Button Configs to SD"); + else + menu::MessageBox::getInstance().setMessage("Error saving Button Configs to SD"); +} + +void Func_SaveButtonsUSB() +{ + fileBrowser_file* configFile_file; + int (*configFile_init)(fileBrowser_file*) = fileBrowser_libfat_init; + int num_written = 0; + configFile_file = &saveDir_libfat_USB; + if(configFile_init(configFile_file)) { //only if device initialized ok + FILE* f = fopen( "usb:/wiisxrx/controlG.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_GC); //write out GC controller mappings + fclose(f); + num_written++; + } +#ifdef HW_RVL + f = fopen( "usb:/wiisxrx/controlC.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_Classic); //write out Classic controller mappings + fclose(f); + num_written++; + } + f = fopen( "usb:/wiisxrx/controlN.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_WiimoteNunchuk); //write out WM+NC controller mappings + fclose(f); + num_written++; + } + f = fopen( "usb:/wiisxrx/controlW.cfg", "wb" ); //attempt to open file + if(f) { + save_configurations(f, &controller_Wiimote); //write out Wiimote controller mappings + fclose(f); + num_written++; + } + f = fopen("usb:/wiisxrx/controlP.cfg", "wb"); //attempt to open file + if (f) { + save_configurations(f, &controller_WiiUPro); //write out Wii U Pro controller mappings + fclose(f); + num_written++; + } +#endif //HW_RVL + } + if (num_written == num_controller_t) + menu::MessageBox::getInstance().setMessage("Saved Button Configs to USB"); + else + menu::MessageBox::getInstance().setMessage("Error saving Button Configs to USB"); +} + +void Func_ToggleButtonLoad() +{ + loadButtonSlot = (loadButtonSlot + 1) % 5; + if (loadButtonSlot == LOADBUTTON_DEFAULT) + strcpy(FRAME_STRINGS[42], "Default"); + else + sprintf(FRAME_STRINGS[42], "Slot %d", loadButtonSlot+1); +} + +void Func_DisableAudioYes() +{ + for (int i = 39; i <= 40; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[39].button->setSelected(true); + audioEnabled = AUDIO_DISABLE; +} + +void Func_DisableAudioNo() +{ + for (int i = 39; i <= 40; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[40].button->setSelected(true); + audioEnabled = AUDIO_ENABLE; +} + +void Func_DisableXaYes() +{ + for (int i = 41; i <= 42; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[41].button->setSelected(true); + Config.Xa = XA_DISABLE; +} + +void Func_DisableXaNo() +{ + for (int i = 41; i <= 42; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[42].button->setSelected(true); + Config.Xa = XA_ENABLE; +} + +void Func_DisableCddaYes() +{ + for (int i = 43; i <= 44; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[43].button->setSelected(true); + Config.Cdda = CDDA_DISABLE; +} + +void Func_DisableCddaNo() +{ +/* for (int i = 43; i <= 44; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[44].button->setSelected(true); + Config.Cdda = CDDA_ENABLE;*/ + menu::MessageBox::getInstance().setMessage("CDDA audio is not implemented"); +} + +extern "C" void SetVolume(void); + +void Func_VolumeToggle() +{ + iVolume--; + if (iVolume<1) + iVolume = 4; + FRAME_BUTTONS[45].buttonString = FRAME_STRINGS[46+iVolume]; + volume = iVolume; + SetVolume(); +} + +void Func_MemcardSaveSD() +{ + for (int i = 46; i <= 49; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[46].button->setSelected(true); + nativeSaveDevice = NATIVESAVEDEVICE_SD; +} + +void Func_MemcardSaveUSB() +{ + for (int i = 46; i <= 49; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[47].button->setSelected(true); + nativeSaveDevice = NATIVESAVEDEVICE_USB; +} + +void Func_MemcardSaveCardA() +{ + for (int i = 46; i <= 49; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[48].button->setSelected(true); + nativeSaveDevice = NATIVESAVEDEVICE_CARDA; +} + +void Func_MemcardSaveCardB() +{ + for (int i = 46; i <= 49; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[49].button->setSelected(true); + nativeSaveDevice = NATIVESAVEDEVICE_CARDB; +} + +void Func_AutoSaveYes() +{ + for (int i = 50; i <= 51; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[50].button->setSelected(true); + autoSave = AUTOSAVE_ENABLE; +} + +void Func_AutoSaveNo() +{ + for (int i = 50; i <= 51; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[51].button->setSelected(true); + autoSave = AUTOSAVE_DISABLE; +} + +void Func_SaveStateSD() +{ + for (int i = 52; i <= 53; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[52].button->setSelected(true); + saveStateDevice = SAVESTATEDEVICE_SD; +} + +void Func_SaveStateUSB() +{ + for (int i = 52; i <= 53; i++) + FRAME_BUTTONS[i].button->setSelected(false); + FRAME_BUTTONS[53].button->setSelected(true); + saveStateDevice = SAVESTATEDEVICE_USB; +} + +void Func_ReturnFromSettingsFrame() +{ + menu::Gui::getInstance().menuLogo->setLocation(580.0, 70.0, -50.0); + pMenuContext->setActiveFrame(MenuContext::FRAME_MAIN); +} + diff --git a/Gamecube/menu/SettingsFrame.h b/Gamecube/menu/SettingsFrame.h new file mode 100644 index 0000000..8db22e1 --- /dev/null +++ b/Gamecube/menu/SettingsFrame.h @@ -0,0 +1,51 @@ +/** + * WiiSX - SettingsFrame.h + * Copyright (C) 2009, 2010 sepp256 + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + +#ifndef SETTINGSFRAME_H +#define SETTINGSFRAME_H + +#include "../libgui/Frame.h" +#include "MenuTypes.h" + +class SettingsFrame : public menu::Frame +{ +public: + SettingsFrame(); + ~SettingsFrame(); + void activateSubmenu(int submenu); + void drawChildren(menu::Graphics& gfx); + + enum SettingsSubmenus + { + SUBMENU_GENERAL=0, + SUBMENU_VIDEO, + SUBMENU_INPUT, + SUBMENU_AUDIO, + SUBMENU_SAVES + }; + +private: + int activeSubmenu; + u16 previousButtonsGC[4]; + u32 previousButtonsWii[4]; + +}; + +#endif diff --git a/Gamecube/menu/resources/Loading.tx b/Gamecube/menu/resources/Loading.tx new file mode 100644 index 0000000..0df5182 Binary files /dev/null and b/Gamecube/menu/resources/Loading.tx differ diff --git a/Gamecube/menu/resources/bg.tx b/Gamecube/menu/resources/bg.tx new file mode 100644 index 0000000..28610a7 --- /dev/null +++ b/Gamecube/menu/resources/bg.tx @@ -0,0 +1 @@ +3466789:456788::466789:;56788:;;;<<=??@A;<=??@AC<==?@AAC==??@ACCCCDEGGHJCDEGGHIKDEFGHIJKDEGGHIKLKLMOOPQRKLMOPQRSLMOOQRSTMNOPQRSUTUVWYYZ\TUWXYZ[]VVWYZ[]]VWYY[\]^]^_abcdf^_aacdfg_`abcegh_abcdfhihikmoqstikmnpstvjmnprsuwlmoqsuvyvyz{}€ƒxy{}€‚„y{|€‚„†z|€ƒ…‡…†ˆŠ‹Ž†‡‰‹ŒŽ‘‡‰‹ŒŽ‘’ˆ‹ŒŽ‘’”‘’”•—˜™š’”–—˜™šœ”–—˜™›œ•—˜š›œž›œžžžžžŸŸŸ žžŸŸ¡¡¢¢Ÿ ¡¢¢£££žžžž›Ÿ ŸŸŸž¢¢¢¡¡ŸŸž££££¢¢¡Ÿš™˜—•“’œ›™˜—•“‘œ›™˜–”’žœ›™—–”ŽŒ‹‰’•˜Œ‰’•˜‘ŠŽ‘•˜’Ž’•™ ¤¨«¯²µ¢¤©«¯²µ¡¤©«¯³¶¡¤¨¬¯²¶¹»¾ÁÃÆÈ˹»¿ÁÃÆÈʸ¼¾ÁÅÇÉ̹¼¿ÂÅÇÉÌÍÎÑÒÓÕÖØÍÎÐÓÔÕØÙÎÏÒÓÔÖØÙÎÏÒÔÕÖÙÚÙÚÛÜÝÞßàÙÛÜÝÞßàßÚÛÜÝßßßàÛÛÝßßßààßàááâáâãààáââäããàâáãäãäåââããäååäääããääãâããååãããääååååäåãäååååäåäáâààßßÞÝãáâàààÞÞããááàßßÞäããâààßßÛÚÙØÕÓÒÏÛÚÙØÕÔÒÏÜÛÚ××ÔÓÑÜÛÚÙÖÔÓÑÎÌÊÇÅ¿¼ÎÌÊÇÄÁ¿¼ÎÌÉÇľ¼ÎÌÉÇÅÁ¾¼ºº˜œž¢¤§º¸¢œž¢¤§º¶©œž¢¤§º¶´™ž¡¤§©¬­¯°²³µ©ª­¯°²³µ©«¬¯°²´µ©ª¬¯°²´´µ¶¶¶¶µµ´¶¶¶¶¶¶´´¶¶¶¶¶µµµ¶¶¶µ¶¶¶µ²°¯®«©¦¤³°°®«©¨¤³±°®¬ª¨¥³±°¯­ª¨¥¢¯±µ¶º¼¾¢¬°³µ¸»½£§¯²´¶º¼££¯°´¶¹»ÁÃÇÈÊÍÏÒÁÂÆÈÊÍÎÐÀÂÄÇÉÌÎÑ¿ÁÃÇÈËÍÏÓÕÖÙÚÜÜÝÓÔÖÙÚÚÝÞÓÔÖØÚÛÜÞÒÔÕØÙÚÜÞßàààâáääßßààâãããßàààâãäãßàààâãäããäååååääääåååååäååååååååååååäååäãääãáâáàåããäãâââåäåããäãáåååääãäãàààßÞÞÝÜàáààßÞÞÝâááàßßßÞáâááàßàßÛÚÙÙ×ÖÕÔÜÛÚÚÙ×ÖÕÝÜÛÚÚÙ×ÖÞÝÜÛÚÚÙ×ÓÑÏÎÍÊÈÆÔÓÑÏÎÌÊÈÔÓÒÑÏÍËÉÖÔÓÒÐÎÍËÄÁ¿¼º·µ²ÆÄÂÀ¼º¶µÈÅÂÁ¾¼º¶ÈÇÅÂÁ¼º¸°¬¨¥£ž›—°¯ª§¥¡žš³°®©¦£Ÿµ²¯«©¤¡ž”‘ŒŠ…z}—“Œ‡…||˜”’‰†|›—“Œ‰„€€ƒ„†‡Š‹€ƒ…†‰ŠŒ€ƒ…†‰ŠŒ‚…†‰ŠŒŒ‘‘‘““ŒŽ‘’’’”‘’’””’’“”–““”••“”””•–•••–”–•–———••–—–––––—“’’‘Ž”“’’’‘Ž–””’’’‘–••““’‘‘Œ‹Šˆ††„‚Œ‹‰ˆ†…„ŽŒ‹‹‰‡†…ŒŒŠ‰‡†~|zywu‚€~{zywƒ€}{zx…ƒ~|zytspomlihusrpnmkivtsqonljxutrqnmlgecbb`_^gfdcba_^hgfdcaa_ihfdcba`][ZZXWVU]\[ZYWVU^]\[YYWV_]\[ZYXWSRQPONMLUSRQPONMUTSRPOOMUTSRQPONKJIHGFEDLJIHGGEDLKKIHGFEMLKIHGGECBA@?>==DCBA@?>=DCCA@??>;:997655<;998765<;:99875=<;99876443110//5332100/5442200/5532210057789:;<67899;<=7899:;<=789::<<==>?@ABCD=??@ACCD>?@ABCDE?@AACDEEEFGHIJKLEGHIJKLMGGHIKKMNGHIJKLMOMOPQRSUUNOPRSTUVOPQRSUVWOQRSTUVXWXYZ[]^_WYZ[\]_`XYZ\]^_aYZ[]^_aaaacdfgikabcfghklbcdghjlncdfgikmomnqstvyznprtuxy{oqsuwyz}qstvxz|~|~ƒ…†ˆ}€ƒ„†ˆŠ~€‚„…‡‰‹€ƒ…‡ˆ‹ŒŠŒ‘’“–‹‘’“•—ŒŽ’“•—˜Ž‘“”–˜™—˜š›žŸ˜š›žžŸ¡™›žž ¢£›œžŸ ¡£¤¡¢££¤£¤¤¢£¤¤¤¤¥¥£¤¤¥¦§¦§¤¥¦§¨§©©¤¤¤£££¢¡¥¥¥¤¤¤££§§¦§¥¥¤£©©©§¨§¥¥Ÿžœš™—•¢ žœš˜—£¡ žœš˜¤£¡ ž›™“‘‘•™•’Œ’•™–”‘’•˜—•“‘‘•˜¡¥¨¬¯³¶¡¥¨¬°³¶¡¥¨¬°³¶¡¤¨¬°³¶¹¼ÀÂÄÇÉ̺¼ÀÂÅÈÊͺ¼ÀÂÆÈËͺ¼ÀÂÆÈËÍÎÑÓÔÕØÙÚÎÑÓÔ×ØÙÚÎÑÓÔÖÙÚÚÐÒÓÕÖÙÚÛÛÝÞßàààâÛÝßßßáááÜÞßààáâãÜÞßààââãâäãäääåæäãåååæåæãåäåæææåääååæåæææåææææåäææææææåååææææææåçæçççæææäääââààßäåããâàßßåäåãâáàßååääãáààÝÛÚÙ×ÔÓÑÞÜÚÙ×ÕÓÐÞÝÚÙØÕÓÒÞÜÜÚØÕÔÒÎËÉÇž¼ÎÍÉÇÄ¿¼ÏÍÊÇÄ¿¼ÏÍËÈÄÂÀ¼º¶¶œž £¥º¶´¤ž¡£¥º¶´ª¡£¥º¶´²™Ÿ£¥©ª­¯°²³µ¨ª­¯°±³µ¨ª­¯°±³µ¨ª­¯°±³µ¶¶¶·¶¶¶µ¶¶¶··µ¶µ¶¶¶·¶¶¶µ¶µ····µ¶´²°¯­«©§´³°°®«©¦µ³±°®«ª¨µ³±°¯­ª¨¤¡­¯²µ·»¤¢©®°´·º¥¢¦®°³¶¸¥£¢¬¯±µ·½ÀÂÆÈÊÍϼ¿ÂÅÇÉÌλ¿ÁÃÆÉÌλ½ÀÂÆÈËÍÑÓÕÖÙÚÛÝÑÓÔÖÙÚÛÜÏÒÔÖ×ÚÚÝÏÒÔÕØÙÚÜßàààâããäßàààâããåÝßààâããåÞßßáâããåååäåæåææååååææææåäåæææææåäææææææååäåååããææåäåååäææåæåäåäæææææåäåãââááàßàãäââááàßäãäââááàääãäââááßÞÝÜÛÚÚØàßÞÝÜÛÚÙßßßÞÝÜÚÚàßßÞÞÝÛÛ×ÖÔÓÒÐÎÌÙ×ÕÔÓÑÏÎÙØ×ÕÔÓÑÏÙÙØÖÔÓÒÐËÈÇÄÁ¿¼ºÌÊÈÆÂÁ¾¼ÍËÈÇÅÂÀ¼ÎÍËÈÇÄ¿¶µ°®ª§£¡¸µ³¯­©¥£»¸´²¯ª¨¤¼¹¶³°¬ª¦˜–’Ž‹†‚ž›—“‘Œ‰† ™–’‹†£žœ˜“‘Œˆ‚…‡‰‹Œ|‚…‡‰‹Œ„€„…‡ˆ‹Œƒ€ƒ…‡ˆ‹Œ‘‘’”••‘’“”•—Ž‘’“”––’’“–—————˜˜˜˜——˜˜˜———˜—˜—˜™™˜˜—˜™˜™˜˜™——••”“’‘˜——–•”“’—˜——–•”’™˜—˜—–•“‘ŽŒ‹Šˆ†‘Œ‹Š‡’‘Ž‹‹‰“‘‘ŽŒ‹Š…„‚€~{z†…„€}{‡†…ƒ~|ˆ†…„‚€}yvusrpnmyxvtsqomzywutrpn{zxwtsqojigfdcbaljhgecbbmkigfdcbnljhgfdb_^]\[YXW`_^][ZZXa_^^\[ZYa`_^][ZZVVTSRQOOWVUSRQPOWVVTSRQOXWVUSRQPMLKKIHGFNMLKIIGGOMLKKIHGONMLKIIGEDCBA@?>EDCCA@??FEDCBA@?GEDCCA@?=<;:9987>=<;9987>=<;:997?==<;98855432200654422107554322076544211899:;<=?89:;<<=?99:;<=??9:;<<=?@?@ACCDEG@AACDEFG@ACCDEGGABCDEFGHGHIKLMNOHIKKLMOPIIKLMOOPIKKLMOPQPQRTUVWXQRSTUWXZRSTVVWYZRSUVWYY[Z[\^^`abZ\]^_abc[\^_`acd\^^`abcecfghkmnpdghjlnoqfgikmnpsghjlnprtrtuxy{}stwyz}€tvxz|~€uxy{}‚‚…†ˆŠŒ‚„†‡Š‹Žƒ…‡‰‹ŒŽ…†ˆŠŒ‘‘’”–—™›‘’”–—˜šœ’“•—˜šœ“”—˜™›žœžž ¡£¤¤ž ¡£¤¥¦ž ¡£¤¥¦§Ÿ¢£¤¥¦¨©¥¦¨¨©©©ª§¨©ªªªª«©©ªª««¬¬ªª««­­®®ªª©©©¨¨¦««ªªªª©¨­¬¬««ªª©®®®­­««ª¥¤£¡ ž›§¥¤£¡Ÿžœ¨§¥¤£¡ž©¨§¥¤¢ ž˜–”’‘‘•˜š˜–“’‘•˜›˜—•’’•™š˜–““”˜¢¤¨¬°³¶¡¤©¬¯³¶Ÿ¤©¬¯³¶œ ¤¨«¯³¶º½ÀÂÆÈÊͺ½ÀÂÆÈËͺ½ÀÃÆÈËͺ¼ÀÃÆÈËÎÏÒÔÕØÙÚÛÏÒÔÕØÙÚÜÏÒÔÕØÚÛÝÏÒÔ××ÚÛÜÝßààááäãÞßßáââãåÝßààâäääßààáâãååäååæåæççåææåææçæåæåææççèæåææççèççççççççææèèçæçççèèèèèèæçèèèèçèèæææååãâààææåääãáàæåæåäãâàæææååãâàßÞÛÚØÖÔÒßÞÛÚÙÖÔÓàÞÝÚÙÖÔÓàÞÜÛÙØÖÓÏÍËÈÆÂÀ¼ÏÍÊÈÆÂÀ½ÑÎÌÈÆÃÀ½ÐÎÌÉÆÃÁ½º¶´³žŸ£¤º·´±¤ ¢¤º·´±ª¢¤»·µ±±›¡¤¨©«®¯±²´¦©«®°±²µ§©«®¯±³³§©ª¬¯°²´¶µ¶···¶¶µ¶¶···¶¶µ¶¶···¶µµµ¶····µµ´²°¯¬ª©µ³³°¯®«©µµ²²°®«©¶µ³±°®¬ª¥£¡«®°´¶§¤¡§­¯³¶§¤¢£¬¯±µ¨¥£¡«®°´º¼ÀÂÄÇÉ̸»¿ÁÃÇÈÌ·»½ÁÂÆÈʶº¼ÀÂÄÈËÎÐÓÕ×ÙÚÛÎÑÓÔ×ÙÚÛÍÏÒÔÕØÚÛÍÏÒÓÕØÙÚÞßßááããåÝßààâáääÜÞßààáäãÜÞßààâãäååææææææååææææææåäææææææääæææææææææææååäææææææååæææææææåææææææææåääãäââáäåääãäââåäåääããáååäååãäãáààßßÝÝÜááààßßÞÜâàáßàßÞÝáâààßßÞÞÚÚÙØÕÔÓÒÛÚÙØ×ÕÔÓÜÚÚÙØÖÔÓÝÜÚÚÙØÕÔÏÎÌÉÈÅÃÁÑÏÍËÉÇÄÂÒÐÎÌÊÈÆÂÓÑÏÍËÈÇľ»¸µ±¯«¨¿¼¹·´°­©À¾»¸µ±®¬Â¿½¹·´°­¥ ™–’‹¦£žœ˜“‘Œ¨¥ ™–’ª¦£žœ—“†„‚…‡ˆ‹Œˆ‚…‡ˆ‹Œ‹†ƒ…‡ˆ‹ŒŒ‡……†ˆ‹Œ’’”•——‘’“”–—˜‘’“•–——‘’“•–———˜™™™šš™˜™™š™™™™˜˜š™›œœœ™™™›œ›››™˜˜˜˜—–•™š™™˜˜—–ššš™™˜˜—›œ›™™˜˜—”’’‘ŽŒ‹”“’‘ŽŒ•”“’‘ŽŒ—–”’‘‘Š‡†…ƒ€‹‰‡†„ƒ€‹Šˆ†…„‚€Œ‹Š‡†…ƒ}zyxutsq~{zyvusr}{yxvts€~|zywusnmkihfdcpnlkhgfdpomlihferpnmjigfba`^^\[Zca`_^][Zcba`_]\[dca`_^]\YWVVTSRQZXWVUTRQZYXVVTSRZZXWVUTRPNMLKKIHPONMLKIIQPNMLKKIQPONMLKIGFEDCBA@GGEDCCA@HGFEDCBAHGGEDCBA?>=<;:98??==;;:8@?>=<;:9@??==;::776443218765443187665332886654439:;<=??@:;<=>?@A:;<=??@A;<=>?@ABACCDEFHIBCDEGGHICCDEGHIJCDEGGHIKJKLMOOQRKKMNOPQRKLMOOQRSKMNOPQSTSTUVXYZ[SUVWXZ[\UUWXZZ\]UVWYZ[\]]^_`bcdf]_`bbdfg^_abcdgh_`bbdegihilmoqsuhjmnprtvjlnorsuwkmnpstwxwyz}~€‚„xz{~ƒ…y{}€ƒ…†z|~€‚„†‡†‡Š‹‘’‡‰‹ŒŽ’“ˆŠŒ‘“•‰‹‘’”–”–—™›žŸ–—˜šœžŸ¡—˜šœž ¢˜™›ž ¢£¡£¤¥¦¨©ª£¤¥¦¨©ª«£¤¦¨©ª«¬¤¦§©ª«¬­ª«¬®®¯¯¯¬­®¯¯°¯°®¯¯¯°°±±¯°°±±±²³¯¯¯¯®®­¬°°¯°¯¯®­²²°°°°¯¯³²³²±±°°ª©¨§¥£¢ «ªª¨§¥£¡®¬ª©¨¦¤£¯­¬ª©§¥¤žœ™—•”“˜ž›˜—”•˜ žš˜•–—¢Ÿ›™–—— ¤¨«¯³¶œ £§ª¯²¶œŸ£§«¯²¶›ž£§«®²µº¼ÀÂÆÈËι¼ÀÂÆÈËι¼ÀÂÆÈËι¼ÀÂÆÈËÎÏÓÔ×ÙÙÜÜÐÓÔÖÙÚÛÝÐÓÔ×ØÚÛÞÏÓÔ×ÙÚÛÞÞààáâääåßààâäääæßßàâãåååßààâãååæææçççèçèåæççèççéæçæèççééæççèèééêççèççèèçêêêêéçèèêêêêéêèçéééêêêéçççåæääãáçæææåäãáèæçåååãâèççææääâàßÜÛÙØÕÓàßÞÛÚØÕÔààÞÝÚÙ×ÔáàßÜÚÙÖÔÐÎÌÉÇÃÁ½ÒÏÍÉÇÄÁ¿ÒÏÍËÇžÒÏÍÊÈÅ¿»·µ±°¡¡£»¸µ²¯¥ £¼¹µ³¯«¢¼¹¶²°¯œ¢¥¨ª­¯°±´¥¨ª­¯°±³¤¨©«®¯²²¤¦©«®¯°³´¶¶····¶µ¶µ····¶µµµ····¶³µ¶¶····¶´´±°¯­ªµµ´²°¯¬ª¶µ´³°¯®«µµµ²²¯®«¨¥£ ¨­°²©§¤ ¦«¯²©¦¤¢¢«®°ª¨¤£ ª­¯¶¸¼¾ÁÃÇɵ·»½ÁÃÆÈ´¶º¼ÀÂÅȳµ¹»¿ÂÅÇÌÎÑÓÔÖÙÚËÎÏÒÔÖØÚÊÍÏÒÔÕØÙÉÍÎÐÓÕ×ÙÛÞßßááããÛÝßààââãÚÝÝßààâäÚÛÞßßáââåäåæææææäåååææææãåäæææææãåäæææææææææææææææææææææææåææææææåææææææææååååãäææåäåääãææåååååãææææäååäââááààßßäáâàáààßäãáâáàßßãäââááààÝÜÛÚÙØÖÕÞÞÜÚÚÙØÖÞÞÝÛÚÚÙ×ßßÝÜÚÚÙØÔÒÐÎÍÊÈÆÔÓÒÏÍÌÉÇÕÔÒÑÎÍÊÈÖÔÓÒÏÍÌÉÃÁ¾»¹µ±®Ä¿¼¹·´°ÆÂÁ¾»·µ²ÇÄ¿¼º¶²«¨¤¡œ™–‘¬©¥£ž›–“¯ª¨£Ÿ˜•¯¬¨¥¢žš—Š‚††‰‹Œ‹‡„†‰‹Œ‘Œˆ‡†ˆ‹Œ’‹‰†‰‹Œ‘’””–˜˜‘’””—˜˜‘’””—˜˜’””—˜™˜š›œ›™™œ›™››œœ™š›œž›››™š˜˜œ›œš™™œœœš™žžœœš——•“’‘——–•“’‘˜˜—•”’‘‘™˜˜—–“’‘‹‹ˆ‡…„‚ŽŒ‹Šˆ†…ƒŒ‹‰‡†„ŽŒ‹Šˆ†…€}{zxvt€~}zywuƒ€~{zxw„€}zyxsqomlihgtrpnmkigtsqomljhutrpnmkiecba`_]\fdca`_^]gecba`_]gfdca`_^[ZYXVVTS\ZZXWVUT\[ZYXVVT][ZZXWVURQPNMLKKRQPONMLKSRQOOMLKSRQPONMLIHGFECCAIHGGEDCCKIHGEEDCJIHGGEDCA@?=<<;:A@??=<;:AA@?=<<:CA@??=<;987655329986554399876544:9977644;<=??@AC<=>?@ABC<=>?@ACC<=?@ABCDCDEGHIJKDEGGHIJLDEGHIKKLEGGHIKLMLMNPQRSTMNOPQSTVMOPQRSUVOOPQSTVVVWXZZ\]^VWYZ[\^_WXY[\]^_WYZ[]^_`_abceghj`acdfgikabceghklacdfhilmlnprtuxymoqsuvyznprtvxz{oqsuwy{}{}€ƒ…†ˆ}€‚„†ˆŠ~„…‡‰‹€ƒ…†ˆŠŒ‹ŒŽ’“–—Œ‘“•—˜ŒŽ‘’”–˜™Ž’“•—˜›™šžŸ¡£¤šœŸ¡£¤¥›ž ¢£¥§œžŸ¢£¤¦¨¥¨©ª«¬®¯§©ª«¬®¯°¨ªª¬­¯°±©ª¬­¯°±±°°±±²³´³°²²´´µµµ±³´µµ¶µ¶³´µ¶¶¶¶¶³³´´³²±°µµµµµ´³²¶¶¶µ¶µµ´·¸¶¶¶¶¶µ°¯­¬ª©§¤±°¯­¬ª¨¦²±°¯­«©¨´²±°®¬ª©£¡žœš˜–—¤£ ž›™—˜¥£¡Ÿš—˜§¥£ ž›™˜›Ÿ£¦ª¯±µ›ž¢¦ª®±µšž£¦ª­±µš¡¥©­°´¸¼¿ÂÆÈÊ͸¼¿ÂÅÈÊ͸»¾ÂÄÈËÍ·»¿ÁÅÇËÍÏÓÔ×ÙÚÛÞÏÓÔ×ÙÚÛÞÏÑÔ×ÙÚÛÞÏÒÔ×ÙÚÛÞßàââääæåßàââääæåßàâããäæåßàâããåææççèçèêééçæèèèêêèçæèçêéééæèçèêêèëéèèèéêééèëëêèéêêëêëêëèééëëëëêêéêçèæææåããçèæçåååãéçèçåæåãéçççææåäáàßÜÛÙ×ÕáàßÞÛÚØÕáàßÞÛÚØÕâáàÞÜÚÙÖÓÑÎËÈÆÂÀÓÐÎÌÈÆÃÀÓÒÎÌÉÇÃÁÔÒÏÍÉÇÄÁ¼º¶´°¯¡¡½º¶´°®¤¡½»·µ±®«¾»·µ±¯­¤§©ª¬¯°²£¥¨ª­¯°±£¤¨ª«®¯±¢¤¦©«®¯°´µ¶¶····´µ¶µ····³µµ¶¶···³³µµ¶··¶µ¶µ³±°¯­µ¶´´±°¯­µµµ´²°¯­¶¶µ³³°¯®ª¨¥£Ÿ§«¯ª¨¥£ ¥ª®«©§¤¢ ª­«©§¤¢ž©«±µ·»½ÁÃÇ°´¶º¼ÀÂƯ³µ¹»¿Âį±µ·»½ÁÃÈÌÎÐÓÔ×ØÈËÍÏÒÔÕØÇÉÌÎÑÓÕ×ÇÉÌÎÐÓÔ×ÚÛÝßààââÙÚÝÞßààâÙÚÛÞßßáâØÚÛÝßààáãååååæææãäääææææããåäååææáäãääææææææææææææææææææææææææææææææææææææææåååååæææææäååæææææäååææææååååãäãáâààßäãäáâááàåãäãáâáàääääáâàáàÞÞÝÛÚÚÙßßßÝÜÚÚÙßàÞÞÜÛÚÚßàßÞÝÜÚÙ×ÕÔÒÑÎÍÊØÖÔÓÑÏÍËÙÖÕÔÒÐÎÌÙØÕÔÓÑÏÍÈÆÂÀ½»¸µÉÇÄÁ¿»¹¶ÊÈÅÂÀ¼º¶ËÈÇÃÁ¾»¹±®ª¦£Ÿœ˜²¯¬¨¥ ™´°­ª¥¢Ÿ›µ²¯ª¨¤Ÿœ“Œ‡†ˆŠŒ–’Š…‡‰Œ—’‹„‡ŠŒ˜•‘Œ†‡ŠŒ’””—˜˜’””—˜˜’””—˜™’’•—˜™šœ›œžžšœžžž™›žžŸ™›žžŸŸžžžžœ›žžžž›žŸŸžŸŸŸžžžš˜˜—–•“’›š˜——•”’›š™˜˜—•“›š™˜—–•‘Œ‹‰‡†’ŽŒŠ‰†’‘ŽŒ‹Š‡“‘‘ŒŠ‰…ƒ€~{zx…„‚€|{y†…‚~{z†…„€|{wtsqonljxutrpnmkywtsqomlyxutrpnmhgecba`_igfdca`_jhgecba`kigfdca`]\[ZYWVV^][ZZXWV^]\[ZYWV_^][ZZXWTSRQOOMLUSRQPOMMVTSRPOOMUUSRQPOMKJIHGEDDKKIHGGEDLKJIHGEDLKJIHGFECA@??==;CBA@?>=EDCCA@??<;:99776=;;:8866=<;:9876=<;:9987?@ACCDEG@AACDEFG@ACCDEGG@ACDEFGHHIJKLMNPHIKKMNOPIJKLMOOQIJKLMOPQQRSTUWXZQRTUVWYZRSTUWXZZRSUVWYZ[Z\^^`abc[]^_`acd\]^_abce\^_`acdfeghjmnqsfhilnorsghjmnpsthilnorsutwyz|~€‚uxy{~ƒwyz}€‚„xy{~ƒ…„†ˆŠŒ‘…‡‰‹ŒŽ‘’†ˆŠŒŽ’“‡‰‹‘’•“•—˜›ž ”–˜šœŸ¡–—™›ž ¢—˜šœžŸ¡£¢£¥¦©ª«­£¤¦¨©ª¬®¤¥§©ª«®¯¤¦¨ª«­¯°¯°±³´µ¶·¯°²´µ¶·¸°±´µ¶¶¸º±³µ¶¶·º»¸ºº»¼»¼¼º»»»¼½½½»»¼¼½¾¾¿»¼¼¾¾¿À¿½¼½¼¼»»»¾¾½½½½¼¼¿ÀÀ¿¾½½¼ÀÁÁ¿À¿¾¾¹¸·¶µ³±¯»¹¸·µ´²°¼»¹¸¶µ´±¼¼»º·¶µ²­ª©¦¤¢žœ®¬ª¨¤£ ž°®ª©¦¤¡Ÿ°¯¬ª¨¤£Ÿ›œž£§ª®²šŸ¢¦ª®±œž¢¦©­°œ¡¥©¬°µ¹¼ÀÂÆÈ̵¸¼¿ÂÆÈ˵¸»¿ÂÄÈÊ´·»¾ÁÅÇËÎÑÓÖØÙÛÜÎÑÓÔ×ÙÛÝÍÏÓÔÖÙÚÝÍÏÒÔ×ÙÚÜßßàãääææßàáâääææÞßáâãåæåÞßàáãåååçèçéêéêëçèçéêéêëççèèêéêëçæèçêêéëëëëëëëëéëëëëëëêêëëëëëëëéëëëëëëëéêêçèæææåêêçèæææäêêçèæææäêêçèææååãâàßÞÛÚØäâààÝÝÚÙäãáàßÜÚÙäãáßÞÝÛÙÕÔÒÎÌÉÇÃ×ÔÒÏÍÊÇÅ×ÔÒÏÍËÈÄÖÔÓÑÎÊÈÆÁ½»·µ±¯«Á¿»¸µ²¯«Â¿¼¸¶³¯­ÂÀ¼º¶³°¬¦¡¤§©ª¬¯¨ £¥¨ª¬®© ¢¤§©«®ª£¢¤§©ª¬°±³µµ¶¶µ¯±²´µµ¶¶¯±²´´¶¶¶¯°±³µµµ¶¶¶¶´´³±¯¶¶¶µ³³±°¶¶¶µ´²²°¶¶¶µµ³±°®«©¦¤¢Ÿ¥®«ª¨¥£Ÿ¡¯­ª¨¥£¡ž¯­ª©¥¤ žª¬°²¶¸¼¿©«¯±µ·»½¨ª®°´¶º¼¦ª¬°²¶¸¼ÂÄÇÉÍÎÐÓÁÃÇÉÌÎÐÒÀÂÆÈÊÍÎÒ¿ÂÄÇÉÌÎÑÔÖÙÚÛÝßßÔÖØÚÚÜÞßÓÕ×ÙÚÛÝßÓÔ×ØÚÛÝÞààâããäåäßáâáäãååàààââäãåßßàááããäåæææææææäåææææææåäåååæææäååäåææææææææäååæææåååååæææåäåååææåäååååååãääááâååâääááâååâääááâåãããäááâáàßàÞÝÝÜááßàßßÞÜááßàßßÝÜááààßÞÞÜÛÚÙ×ÕÔÓÐÚÚÙØÖÔÓÑÛÚÙØ×ÔÔÒÛÚÚØ×ÕÔÒÎÍËÈÆÃÁ½ÏÍËÈÆÃÁ¿ÏÎÌÉÇžÑÎÍÊÈÆÂÀ»·´°­ª¥¢»¹µ±®ª§£¼¹¶³¯«¨¤¼º¶´°­©¥Ÿš—’ŽŠ‰‹Ÿœ˜“‹Š‰¡˜•‘ŠŠ¢žš–’Ž‹‰ŒŽ‘’••˜™Œ‘’“–˜™Œ’“–˜™Œ‘“–—™›œŸž  ››Ÿ Ÿ¡››ŸŸŸ¢›œž ¡¢¢¢¢¡¢ ŸŸ¡¡¡¡¡¢  ¡¡££¡¡¢ ¡£££¢£¡¢Ÿžžœ›™˜ŸŸž›™™ Ÿžœš™  žžžœœš—–”’‘ŽŒ˜—•“’‘˜—–”’‘Ž˜˜—•“’‘‹Š‡†…‚€ŒŠ‰†…„€Œ‹Š‡†…ƒ€ŒŠ‰†…„~{zxvtsq}zywusr~{zxvts€~|zywusomlihfdconlkhgedqnmkigfdronljhgeba_^]\ZYbb`_]\[Zcaa_^]\Zcba`^^\[XWVUSRQPYWVVTSQPZXWUUSRQYYWVUSRQOMLKJIHGOOMLKIHGPOMLKKIHPONMKKIHFECCAA@?GEDCCA@?GEDDCA@?GGEDCB@?==<:9887>=<;:987?==;:998?=<<:988ABCDEFGHACCDEGHIACDEGGHICCDEFHIJIKLMNOPRKKLMOPQRJLMOOPRSKLMNPQRSSTUWXZZ\SUVWYZ[\TVVXYZ[]UVWXY[\]]^_abceg]_`acdfh^_abcegh_`bbdfgihjmnqstwilmorsuxkmnqstwylmorsuxyyz}€‚„†y{~„…‡z}€‚„†ˆ{~ƒ…‡‰ˆŠŒŽ’“–‰‹‘’”—ŠŒŽ’“–—‹‘’”—˜—™›ž¡¢¤˜šœžŸ¢£¤™›ž¡£¤¥šœžŸ¢£¥¦¥¨©ª¬®¯°§©ª«­¯°±¨©ª­®°±²©ª«®¯°²´²´µ¶¸¹º»´µ¶·¹º»¼´¶¶¸¹»»½µ¶·¹»¼¼¾¼½½¿ÀÀÁÁ½½¿ÀÁÁ½¿ÀÁÁÁ¿ÀÁÂÂÂÂÃÁÁÁÁÀÁ¿¿ÁÁÁÁÂÁÁÀÃÃÃÃÂÂÂÁÃÃÃÃÃÂÂÁ¾¼¼»¹·¶´¿½¼¼º¹¶µÀ¿¾¼»º¸¶ÁÀ¿¾¼»¹·²°®«©¦¤¡³±¯¬ª¨¤¢´²°®ª©¦£µ³°¯¬ª¨¤žž ¤¨¬¯Ÿž ¤§«¯¡žž£§«®¢žžž£¦ª­³·º½ÁÃÇɲ¶º¼ÀÃÇɲµ¸¼ÀÂÆȱµ¸»¾ÂÅÈÍÏÒÔÖØÚÛÌÎÐÓÕØÙÛÌÎÐÓÕØÙÛÊÍÐÓÔÖÙÚÞßàáãåååÞßàâããååÜÞßàãääæÝÞßàâãååææèçêêéëæçèçèêéêæççèèêêèåçæèçéééëëëëëëëèêëëëëëëèêêëëëêêéèêêëêêèêêêçèæææåêêçèæææåéêçèæææåêèèèæææåããâàßÜÛÙäâáàßÝÛÚåâáàßÞÛÚåäáàßÞÛÚØÖÓÑÎÌÈÆØÕÓÐÎÌÉÇ×ÕÔÒÏÍÉÇÙ×ÔÒÏÍËÇÃÀ½º¶´°®ÃÁ½»·µ±®ÄÁ¾»¸µ±¯ÅÁ¿¼¹µ³¯ª¦ £¥¨ª­«¨Ÿ£¥¨ª««©¡¢¤¦©«¬©¢ £¥¨ª®°±³³´¶¶®¯°²´µµµ­¯°±³´´¶­®¯±³´´µ¶¶¶µµ³±°¶¶¶µµ³²°¶¶¶µµ³±±µ¶¶µ´´³±¯¬«©§¤¢Ÿ¯®«©¦¤¢Ÿ°®«ª¨¥£Ÿ°®¬ª¨¥£¡£©«¯±µ·» ¨ª®°´¶º§ª¬°²¶¹ž¤©«¯±µ·½ÁÃÇÈËÍϼÀÂÅÈÊÍλ¿ÂÄÇÉÌλ½ÀÂÆÈÊÍÒÔÕØÙÚÛÝÑÓÔÖÙÚÛÝÐÒÔÕØÙÚÛÏÒÓÕ×ÙÚÛßàààâáäãÞßßààââäÝßßàááâãÝÞßàààâáääåååäååãääåååååäãäåååååãäããåäåååäåååååååååååååååååååååååååååääãääãääááâäâääãááâãããããâáâãäääáâââááàààÞÝÜááàààÞÝÞááàààÞßÞáààààÞßÝÜÛÙÙØÕÔÓÜÚÙÙØÖÔÓÛÚÚÙ××ÔÔÛÛÚÚÙÖÖÓÐÎÍÊÈÆÃÁÒÏÍÌÉÇÃÁÒÏÎÌÉÇÅÂÒÑÎÍÊÈƽ»·µ±®ª¦¾¼¸µ±¯ª§À¼º¶³¯«¨À½º¶´°­©£ž›—“Œ†£ œ˜”‡¥ ™•‘Œ‹¥¡žš–’Ž‹‹’“–—˜‹Ž‘”•—˜‹Œ‘“”—˜‹ŒŽ‘“”—˜›œž  ¡šœžž ¢¡šœžžŸ¢¡™œžžŸ¢££££££££¡£££¢¢¢£££¢£¤¤£¢£££¤¤¤£¤£¢ ŸŸœ›¡¡ Ÿžžœ£¡¡ žžœ¢¢¡ Ÿžž™˜—–”’‘š˜˜—•“’‘›™˜—–“’‘œš˜˜–”“’ŽŒ‹‰‡†„‚Ž‹Šˆ†…ƒŒ‹‰‡…„‹Š‡†…€}{yxut~|zywt‚€|zyxu‚~{zxvrqnmjigfsqomlihftrpnmkhgtspnmkigdcb`_^][dcba_^]\ecbb`_]\fdcaa_^]ZYWVVTSR[YXWVUSR[ZYWVUTS[ZZXWUTSQONMLKIIQPOMLKKIQPOOMLKIRQOOMLKJHGEDCCA@HGEEDCA@HGGEDCBAHHFEDCCA??=<;:98??==;::9??=<<:99@??=<;:9CDEFGHIKCDEFGHIKCDEGHIKKDEGGHIJLKMNOPQSTLMNOQRSTLMOPQRSUMOOPRSTUVVWYZ[]^UWXY[\^^VWYZ[]^_WXZZ\]^__abceghk`bbdfgik`bcdfhjlabcfgikmmnprtvxzmoqsuwy{nprtvxz|oqsuwy{}|~€‚„†ˆŠ}ƒ…‡‰‹~€‚„†ˆŠŒƒ…‡‰‹ŒŒŽ’“–—™‘’”—˜šŽ’“–—™›Ž‘’•—˜šœ›ž¡£¤¦¨œžŸ¢£¥§©ž £¤¦¨©žŸ¢£¥§©ª©«¬¯°±³µª«®¯°²´µ«¬¯°±³µ¶«®¯°³´¶¶¶·¸º»¼½¿¶¸º»¼½¾¿·¹»¼½½ÀÁ¸º»¼½¿ÀÁÀÁÂÂÃÃÄÃÁÂÂÂÄÄÅÅÁÂÂÄÄÅÆÇÂÂÄÅÆÆÆÇÅÅÅÄÄÄÃÃÅÆÆÆÅÅÄÄÇÆÆÆÇÆÅÅÇÈÈÈÇÇÇÆÂÁÀ¿½¼º¸ÂÂÁÀ¾¼»ºÃÃÂÁÀ½¼»ÅÃÂÂÁ¿½»¶´²°®ª¨¦·µ³°¯¬©§¹¶´²°­ª©º·µ³±®¬©£ žž¢¥©­¤¢žŸ¡¤©¬¥£ Ÿ ¤§«¦¤¡ Ÿ£§«°´·»¿ÁÄÇ°´¶º½ÁÃǯ³¶º¼ÀÃÇ®±µ¹¼ÀÂÆËÍÏÒÔ×ÙÚÉÍÏÒÔÕØÚÉÌÎÑÓÕØÙÈÌÎÐÓÕ×ÙÜÞßàáãååÛÞßàââäåÛÜßßàâääÚÝÞààáãåææçèçèêéææçæèçééæåæçèççêååæççèçèéèêêêèéêééèèèéêêêéêêêéêêééêêêêêêééçèçææåêççèçææåéçèççææåèèèæçææååäáàßÞÛÚåäáààÝÝÚåäááàÞÝÚåäâààßÝÛÙ×ÔÒÏÍÊÈÙ×ÔÓÏÎÊÈÙÖÔÓÑÎÌÈÙØÖÓÐÎÌÉÅÂÀ¼¹¶³°ÆÂÀ¼º¶´°ÆÃÁ½»·´±ÇÃÁ½»·µ±­ª¤ £¥¨ª®ª§Ÿ¢¤¦©®ª¨ ¡¤¦¨¯«©¢ £¥¨«®¯°±³µ´«­¯°±²´´ª¬®°°²³µª«®¯°±³´¶¶µµµ´³±µ¶¶´µ´²²µ´µµµ³³±´µµµµ³²±¯®¬ª©¦¤¡°¯¬ª©§¤¢°¯­¬©¦¤¢°¯®«ª¨¥£ž¢¨ª®°´¶Ÿž§©­¯³µŸ¦©«¯±µ ¢¨ª®±´º¼ÀÂÅÇÉ̹»¾ÁÃÇÉÌ·»½ÁÃÆÈʶº¼¿ÂÄÇÉÎÑÓÔÖØÙÚÍÏÒÔÕ×ÙÚÍÏÑÓÔÖØÙÌÎÐÒÔÕØÙÛÝßßßààâÛÝÞÞààáàÚÛÝÞßààáÚÛÜÞßßßàáãäãããååâáâääããâáâáâããääàáâááãäãäååååäâãäääãâãããããããääääääääääãääääââáâàäããáââááããáâáâááãáâáââàáááßààÞßÝááßààÞßÝááßààÞßÝáààààÞßÝÛÜÚÚØ×ÕÔÝÜÛÙÙ×ÕÔÜÛÛÙÙØÖÔÝÛÛÙÙØÖÔÓÑÎÍËÈÆÃÓÑÏÍÊÈÆÃÓÒÏÎÌÊÇÅÓÒÏÍÌÉÇÄÁ½»·´°®ªÁ¿»¸µ±®«Â¾¼¹µ²¯«ÂÀ¼º¶²¯¬¦£Ÿš—“‰§£Ÿ›˜“Œ§¤ œ˜•‘Œ¨¥¡™•‘‰ŒŽ‘’•—˜‰Œ‘’•—˜ŒŒ‘’•—˜‡Œ’”–˜™œžžŸ¡£™œžŸ¡¡£™œž  ¡£™œž  ¢¢¢¤¤¤¤¤¤¤£¤¤¤¤¤¤¤£¤¤¤£££¤£¤¤¤¥¥¤£££¡¡ žž¤¢£¡ Ÿžž££¢¢¢ žž¤£££¡ Ÿžœš™˜—–“’œ™˜˜–•’œ›™˜—•“žœœ™˜—–”‘Œ‹ˆ†…’ŽŒ‹Š‡†’‘ŒŠˆ†’‘Œ‹‰‡„€~}zyw„ƒ€}{yx…ƒ€~{zy…„‚€|zyusronljhutrqnmjhwtsqomliwutronljgecba_^^gfdca`_]hfdcba_^hgecba`^\[YXWVUS][ZYWVVT][ZZXWUU^\[YYWVURQPOMLKJSQPOOMKKSRQOOMLKTRQPOMLKIHGFDDCAIHGGEDCBJHHGEDCCJIHGEDDC@??==;:9A??=<<:9A@??=<;:A@??==;:DEGGIJKLDEGHIJKLEGGHIKLMEFHIJKLMMNPQRSUVNOPQSTVVNOQRSTUWOPQRSUVWWXY[\]_`WYZ[]^_aXY[\^^`bYZ[]^_`bacdfhilnbceghkmnbdfgilmocdghjlnportuxz|~pstvyz|rsuxz{~€stwyz}€€‚„†ˆŠŒ€‚…†ˆ‹ŒŽ„†‡ŠŒƒ…†‰‹Œ‘’“–—™›‘’•—˜šœž‘“–—™›ž’”–˜šœžŸž¡£¤¦¨©«Ÿ¢£¥§©ª«¡£¤¥¨©«¬¢£¤¦©ª«®­¯°±´µ¶·®¯°³´¶·¹¯°±´µ¶·º¯°³´¶·¹ºº»¼½¾ÀÁÁº»¼½ÀÁ»¼½¿ÀÁÂü¼¾ÀÁÁÃÃÂÄÅÅÇÇÈÈÃÄÅÇÇÈÇÈÄÆÇÇÈÈÉÈÅÆÇÈÈÉÉÊÇÇÇÇÇÈÇÇÉÉÉÉÉÈÇÈÉÊÉÊÊÈÉÈÉÉËÊÉÊÉÈÆÅÄÂÁÀ¾¼ÇÆÅÃÂÁ¿½ÈÇÆÄÃÂÀ¿ÈÈÇÆÄÂÁÀ»¸¶´±¯­ª¼º·µ³°®«¼»¹¶´±¯¬½¼º·µ³°®§¥¢ž £¦ª©¥£Ÿ ¢¥©ª§¤¡¡Ÿ¥¨ª¨¤£ ¡¤§­±µ¸»¿ÂÄ­°´·»½ÁÄ«¯³¶º½Á믲¶¹¼ÀÂÈËÍÏÒÔ×ÙÇÉÍÏÒÔÕØÇÉÌÎÑÓÕØÆÈÌÎÑÓÔÖÚÛÞßàáâäÙÛÜßßàâãÙÚÝÞààâãÙÚÜÞßàáâäæåçççèèååææçæèçäåæåæçæèäåååæççæçééêêéêèèçééééçèèèèèèèèèèèçèèèçèèçèæçææåèèçççåæåèèæçæåæäèæçææææäåäâààßÝÛåäâààßÝÚãäááàßÜÜããâààßÜÜÙØÕÓÐÎÌÉÚØÕÔÒÏÍÉÚØÕÔÒÏÍËÚ×ÖÔÒÏÍÊÇÄÁ¿»¹µ²Çž¼¸¶³ÈÅÂÀ¼º¶³ÈÆÂÀ¼º¶´¯«©¥Ÿ£¤¦°¬©§ž¢¤¦°­ª¦¡ £¥°®ª¨¢Ÿ£¤©«¬¯°±²³¨ª¬®°°²³¨©«®¯°²²¦©ª­¯¯°²µµµµµ³´±³µµµµ³´²³´´µ´´´²³²µµµ³´²°°®«ª¨¥£°°­­ª©¥¤°°¯¬ª©§¤°°®­ª©¦¤¡ž §ª¬°²¢ž¦©«¯±¢Ÿ¤¨ª®°¡Ÿ¡¦ª­¯¶¸»¾ÁÃÇÈ´·»¼ÀÂÅÈ´¶¹¼¿ÁÄdzµ·»¾ÀÂÆËÍÏÑÓÔ×ØÉÌÎÑÒÔÕØÉËÍÏÒÓÔ×ÈÊÍÎÑÓÔÕÙÚÛÝÞÞàßÙÚÚÜÝßßàØÙÚÛÜÝßßØÙÙÚÜÝÞÞàààâââáãßàààââáâßßààááââßßßààááàâääääâãáâááááââââááââááââáãâââââââáââàááááââàááàââáàáááááàáááááàáàààßßßÝàßààßßßÝßàààßßÝÞàààßÞÞÝÞÝÛÛÙÙØ×ÕÝÛÛÙÙ××ÕÛÜÛÙÙ××ÔÛÜÛÙÙ×ÖÖÔÒÏÎÌÉÇÆÔÒÑÎÍËÈÆÔÓÐÎÍÊÈÆÔÓÑÎÍÊÈÆÂÀ¼º¶´°­ÂÀ½»·´°­ÃÁ½»·µ±®ÃÁ¾»¸µ±®©¥¡žš–’Žª¦¢ž›–“Žª¦£Ÿ›—“«§£ œ˜”Š‹’“•˜‹‹‘“–˜Š‰Ž’“–˜Œ‹Œ‘“–˜™›ž  ¢¢™›ž ¡¡¢š›ž ¡¡¢ššž ¡¡£¤¤£¥¥¥¤¥¤¤¤¤¥¥¥¥¤£¥¥¥¥¥¥£¤¥¥¤¥¥¤¤¤¤£¢¡ ž¥¤¤££¡ Ÿ¥¤£¤£¢¡ ¥¤¤¤££¡ žœ›˜——”žž›™˜—–žœš˜˜–Ÿžœš™˜—“‘Œ‹Š‡“’‘ŒŠ‰•’‘ŽŒ‹‰•“’‘ŽŒŠ†…‚€~{z†…„€~|z‡†„‚€|{‡†…‚~{xvtsqnmkyvtsqomlyxutronmzxvtsqnmigfdcb`_ihfdcba_khgecba`kigfdcb`]][ZYXVV^][ZZXWU^^\[YYWV_]][ZYXVTSRPOOMKUSRQOOMLUTRQPOMLVTRRPOOMKIHGGEDCKJHHFEDCKKIHGEEDLKIHGGEDB@??==;;CA@?>=<;CA@??=<;CAA@?=<=EDCA@??=ECCAA@?=EDCB@??=HJKLMOPQIJKMNOPQIKLMNOQRJKLMOPQRRSUVWYZ[STUWXZZ\SUUWXY[\TUVWYZ[]]^_abceg^^`bbdfg]_`acdfh^_abceghhjmoqsuwilnortuxjlnqstwyjmoqsuwyy{~„…‡z|~€‚„†‰z|€‚…‡‰{~„†‡ŠŠŒ‘“–—‹Œ‘’”–˜‹‘“•—˜Œ’“–˜™™œŸ £¤¦šœžŸ¢£¥§šž¡£¤¥¨œŸ¡£¤§©¨ª«®¯°²´©ª¬®°±³µ©«­¯°±´µª«®¯°³´µµ·¹º¼¼¿À¶·º»¼½¿Á¶¸º»¼¾ÀÁ·¹»»½¾ÁÂÁÂÃÅÇÈÈÉÁÂÄÆÇÇÉÊÂÃÅÇÇÈÉÊÂÄÆÇÇÉÊËÊÌÍÍÎÎÏÏËÌÍÎÎÏÏÐÌÌÎÍÏÏÐÐÌÍÍÎÎÐÐÒÐÐÏÏÏÏÐÏÏÑÒÒÒÐÐÐÒÒÑÑÑÑÒÑÑÑÓÓÓÒÑÑÏÎÎÌÌÉÈÇÏÏÎÍÌËÉÈÐÏÎÍÍÌÊÈÑÐÏÎÎÍËÉÆÃÂÀ½»¸¶ÇÅÂÁ¾¼º¶ÇÆÃÁ¿½»·ÈÆÄÂÀ½»¹´°®ª¨¥¢¢µ±¯«©¥£¢µ³¯¬ª¦¤¢¶´±®ª¨¤¢£¦ª­°µ·»¡¥©­°´¶º¡¥¨«¯²¶¸¡£§ª®±µ·½ÁÃÇÉÌÎѼÀÂÆÈËÍϼÀÂÄÈËÍÏ»¿ÁÃÇÉÌÎÓÔ×ÙÚÛÝÞÒÔÕØÙÚÜÞÑÓÕ×ÙÚÛÝÑÓÔÖØÚÚÜßààââäãåßàààââããÞßßááâãäÞÞààáááãåäåæåæææåååäååååãåäåååååäããåäåååæååååäããåäåååãäâååååãäãáäåäãäãáâáááßßÝÝÜâàààßÞÝÛâáààÞÞÝÛàáßàÞÞÜÛÚÙÖÖÔÒÏÍÚÙÖÖÔÒÏÍÙÙÖÖÔÒÏÎÚØÖÖÔÒÏÎÊÈÆÃÁ½»¸ËÈÆÃÁ¾»¹ÌÉÇÃÁ¿¼¸ÌÊÇÅÁ¾¼¹µ²¯«©¥£µ³¯­©§£ž¶²°¬ª¦¤Ÿ¶´°®ª§¤¡Ÿ¢¤¦¨ª«®ž¡£¥¨©«­ £¤¦©ª«Ÿ¢¤¦¨ª«¯°°°²²²±®¯°±°²²±®¯°°°±°±­¯¯¯±±±±±°°¯­«©¨±°°¯­«ª©±°°®®«ª©±°°¯®¬ª©¥£¢žœš£¥¦¤¢Ÿš¡¤¦¤¢Ÿ›Ÿ£¦¤£Ÿš›£©«¯°´·º¼§ª¬¯³µ¸»¦©«¯±´¶º¤¨«®°´¶¹¿ÁÃÆÈÊÌνÁÂÅÇÉÌͼ¿ÂÄÆÈËÍ»¾ÁÃÅÇÉÌÏÒÓÔÖ×ØÙÏÐÒÔÔÖØÙÎÏÒÓÔÕ×ØÍÏÑÒÔÔÖ×ÙÚÚÜÛÝÝÝÙÙÚÚÜÛÝÞÙÚÙÚÚÜÛÜØÙÚÙÚÚÛÜÞßßßßßßßÝÝÝßßßßßÝÞÝÝÝÝÝÞÛÜÝÞÞÞÞÝßßßßßßßßßßßßßÞÝÝÞÞÝÝÝÝÝÞÝÝÝÞÞÝÞÝÝÝÞÞÜÛÜÚÝÞÞÜÜÜÛÛÝÝÜÜÜÛÛÛÝÛÛÜÜÚÚÚÛÚÙÙÙØÖÔÚÙÚØ××ÕÕÚÚÙØØ×ÕÔÙÚÙÙ×ÖÕÔÔÓÑÎÎÌÉÇÓÓÑÏÎÌÉÇÔÒÑÏÍÌÉÇÓÑÑÏÍÌÉÇÅ¿½»·´±ÅÂÀ½»·´°ÅÂÀ½»·µ±ÄÂÀ½»·µ±®ª§£ž›˜”®ª§£Ÿ›—”®ª§£Ÿœ˜”®ª§£Ÿœ˜”Œˆ’•—‘Œˆ’•—‘ŒŠ’”—‘ŒŠ’•—˜›žŸ¡£¤˜›žŸ¡£¤˜›žŸ¡£¤˜›žŸ¡£¤¤¤¦§¨§§¨¤¥¥§§§©©¤¦¥¨§©©©¥¥¥¨§¨©©§§¨§¥¥¥£©¨§¨¦¦¤¤©©§§§¥¥¤©©©§¨¥¥¥££¡Ÿžžš¤¢¢ žœ££¡¡ žœ£££¡Ÿžœš˜—•”‘‘™˜—–“’‘š˜—–”’‘›˜˜—•’’Œ‹Š‡†…ƒ€ŽŒ‰ˆ†…ƒŒ‹‰†…„ŽŒ‹‰‡†„‚}{yxutr~{zxvts€~|zywts€}zywutpnmkhgedqnmkigfdqpmligfdronljhgeba`^^\[Ycb`_]\[Zcaa_^][Zcba_^][ZXWVUSRQPYWVUSSQPYWVVTSRPZXWUTSRPOMLKKIGGOMMKJIHGOOMKKIHGPNMLKIIGEDCCA@?>EEDCA@??GECCAA??FEDCB@@?KKLMOPQSJLMOOPRSKLMOOQRSKLMOPQRTTVVXZZ\]TUWXZ[\^UVWYZ[]^UVWYZ[]^^`abdfgi_`bcdfhj_abceghj_abcfgillnortuxzlnqstwyzmnqsuwy{mortuxz{|~€‚„†‰‹|€‚…‡‰‹~„†‡ŠŒ~€‚„†‰‹ŒŒ‘’•—˜š‘“•—˜š’“–˜™œ‘’•—˜šœœžŸ¢¤¥§©ž¡£¤¦¨ªŸ¡£¤¦©ªžŸ¢¤¥¨©ªª­®°±³µ¶«­¯°²´µ¶«®¯°²µ¶·­®°±´µ¶··º»¼½ÀÁ¹º¼¼¾ÀÁ¹»¼½¿Áº»¼½ÀÁÂÃÃÅÆÇÈÉÊÌÃÅÇÈÈÉËÌÄÆÇÈÈÊÌÍÄÆÇÈÉËÌÍÌÎÎÏÏÏÒÑÍÍÎÏÐÑÑÒÎÎÎÐÐÑÒÒÎÎÏÏÒÑÓÒÒÒÓÓÓÓÓÒÒÒÓÓÓÓÒÒÒÓÔÔÔÔÓÓÓÓÔÔÔÔÔÔÑÑÐÎÎÍÌÊÒÑÐÏÎÎÌÊÒÒÒÐÎÎÍÌÓÓÑÑÐÎÎÌÈÇÅÃÁ¿¼ºÉÇÆÃÁÀ½»ÉÈÇÅÂÁ½»ËÈÇÅÃÁ¿¼¶´±¯«©¥£·µ²°­©§¤¸¶´°®ª¨¤º·µ±¯«©¥¢£¦ª¬°´¶¢¡¥©«¯³¶£ ¤¨ª¯±µ¢¡£¦ª®°´»½ÁÂÆÈÊͺ¼ÀÂÄÈÊ͹»¿ÁÃÇÉÌ·»½ÁÂÆÈÊÏÒÓÕØÙÚÛÎÐÓÔ×ØÚÚÎÐÒÔÕØÙÚÍÏÑÓÔ×ØÚÝÞßààáááÜÝßßßààâÛÝÞÞàßààÚÛÝÞßàßàâääãããäãââãääãããáâáââäääááââááááäããääâââäääãâáâàäãâááâààáááââàáááààßßÝÜÚáàßßßÞÜÚàßàÞÝÝÛÛßàßßÝÝÛÚÚÙÖÖÔÒÏÎÚÙÖÖÔÒÏÎÙÙÖÖÔÒÏÎÚÙÖÕÔÒÏÎÌÉÇÅÂÀ¼ºÌÉÇÄÂÀ¼ºËÉÇÅÂÀ½»ËÉÈÆ¿½»¶´°®ª¨¤¢·´±®«¨¥¢·µ±¯«©¥£·µ±¯«©¦£œž £¥§©ªœŸ¢¤§©ªžŸ¢£¥¨© œž¡£¤¦©¬®¯°°±±±«­¯¯°°±±ª¬®¯°¯°°ª«­¯¯¯°¯±°°¯®¬ª©±¯°¯®­«©°°¯¯®­«ª°°°®­­«ª§¥£¡žœ™¡¨¥£ žœ™Ÿ¨¥¤¢ž™œ¨¥¤¢Ÿ›š¤§©¬¯²µ¸£¥©«¯°´¶¢¤¨ª¬°³µ¡£¦©«¯±µº½ÀÂÄÇÈ˺¼¾ÁÂÆÇɸ»½ÀÂÅÇȶº¼¿ÁÃÆÈÍÎÏÒÓÔÔÖÌÍÎÐÒÓÔÕËÍÎÏÑÓÔÔÉÌÍÎÐÒÓÔ×ØÙÚÙÚÛÚÖØÙÙÚÙÚÛÖÖ×ÙÙÚÙÚÔÕ××ÙÙÚÚÜÜÛÛÝÜÞÞÚÛÜÜÛÛÛÛÛÚÚÛÛÜÜÜÙÚÛÛÛÚÚÚÞÞÞÞÝÝÜÛÛÛÛÛÛÜÛÜÜÛÛÜÜÜÝÜÜÜÜÛÚÚÚÛÜÛÝÛÛÛÛÙÜÜÚÛÛÛÚÚÚÚÛÚÛÚÚÙÛÛÛÚÙÚÚÚÚÙØØØÖÔÔÚÙÙ×ÖÖÕÓÙØÙ×ÖÖÔÔØÙ××ÖÔÔÔÓÒÐÎÍÌÊÇÓÒÏÎÍÊÈÇÓÑÏÎÍËÈÇÓÐÏÎÌÊÈÇÄÂÀ½»·µ±ÅÂÀ¾»·´°ÄÂÀ½º·´±ÅÂÀ¼º·´±®ª§£Ÿœ˜”®ª§£Ÿœ˜”®ª§£Ÿœ˜”®ª§£Ÿœ˜”‘Œ‰’•—ŒŠ’•—‘Œ‰’•—‘Œˆ’”—˜›žŸ¡£¤˜›žŸ¢££˜›žŸ¢££˜›žŸ¢££¥¥§§¨©©©¤¦§§©©©©¤¦§§©©©©¤¦¨§©©©ª©©©¨§§¦¤©©©©§¨¥¥©¨©©¨¨¦¥ª©¨©©§¦¦¤¤£¢ žžœ¤¤£¢¡Ÿ¥££¢ Ÿž¤¤¤£¡Ÿž›™˜—•“’‘œ™˜—–“’‘œš˜—–”’‘œ›˜˜–•“’Œ‹Š‡†…‚Ž‹Šˆ†…ƒŒ‹‰†…„Œ‹‰‡†„€}{zxut~{zxvt~}zywt€|zywurqnmkhgesqnmjigfsqomligfsromlihfdbb`_]\[dca`_]\[dcaa_^][ecba_^][YXWVUSRQZYWVUSRQZYXVVTRRZZXVVTSRPOMLKJHHPOMLKKIHPOOLLJIHQOOMLKIHGEDCCA@?GEECBA@?GFDDCA@?GGEDCAA@KMNOPRSTKMOOQRSULMNOQRSULMOPQSTVVWXY[\^_UWXY[\]_VWYZ[]^_VWYZ[]^_`acdfhil`aceghkmabcegikmabdfgilnnprtwyz}npstvy{}orsuxz{~ortvxz}€‚…†ˆ‹„…‡Š‹€„†ˆŠŒŽ€ƒ…†ˆ‹ŒŽ‘“”—˜š’“–—™œ’”–˜šœž‘’”—˜›žž¡£¤¥¨ª«Ÿ¡£¤§©ª«Ÿ¢£¥§©ª­¡¢¤¥¨©«¬­¯°²´µ¶¹®¯°³µµ·¹®°±³µ¶·º¯°±´µ¶¹ºº¼¼¿ÀÁÂû¼½¿ÁÂÂÄ»¼½ÀÁÂÄļ½¾ÀÁÂÃÅÅÇÈÉÉËÍÍÆÇÈÈÊÌÌÎÆÇÈÉÊËÍÍÇÈÉÉËÍÍÎÍÏÐÐÑÓÒÓÎÎÐÒÑÒÓÓÏÏÐÑÓÒÔÔÎÐÑÒÒÓÓÓÓÔÔÓÓÓÔÔÔÓÔÕÕÕÔÓÓÔÔÕÕÕÔÔÔÔÕÕÕÕÕÔÔÓÓÑÐÏÎÍÔÔÒÒÑÐÎÍÓÓÓÓÒÐÎÍÔÓÔÓÒÑÏÎÌÉÈÆÃÂÀ½ÌÊÈÇÅÂÀ½ÍÊÉÇÅÃÁ¿ÍÌÉÈÆÃÁ¿º·µ³¯­©¦»¹¶²°­ª¦¼º¶´±®ª¨¼»·µ±¯«©£¢¢¥©¬°²¤£ ¤¨«¯±¤¢¡£§ª®°¥¢¡£¥©¬°¶º¼ÀÂÅÇɵ¹»¿ÁÃÇÉ´·»½ÁÃÆȲ¶º¼¿ÂÅÇÌÎÑÓÔÕØÙÌÍÏÒÓÕ×ØÊÍÎÐÓÔÕØÉÌÎÏÒÓÕ×ÚÛÜÞßßàßÚÚÛÝÝßßßÙÚÚÛÝÞÞßØÙÚÛÜÝÞÞàààâââââßàááààááßßààááááßààßààááâââáàááààààáááààááááààààááààßàààààßßÝÛÛÚßßÞÝÞÜÚÚàÞßÝÝÜÛÙßÞÝÞÛÜÛÙÚØ×ÕÔÑÑÎÙ××ÕÔÑÑÎÙØ×ÕÔÒÐÎÙØÖÕÔÒÐÎÍÉÈÆÂÁ½»ÍËÈÆÄÁ½»ÌËÈÆÃÁ¿»ÍËÈÆÃÁ¿¼¸µ³¯­©§£¹µ²°¬ª¦¤¸¶³°­ª§¤¹¶´°®ª¨¤¡›Ÿ¢¤¦¨ œž¡£¥§¢œž £¤§¢ŸšŸ¢¤¥ª«­®®°°°©ª«­¯¯°°¨ª«­®®¯¯¨©ª«­®®¯°°°®­­«ª°°°®­­¬ª°°¯®­­¬ª¯¯¯¯­­«ª¨§¤¢Ÿš˜¨¦¤£Ÿž›˜©§¤£¡žœ™©¦¥£ žœ™Ÿ£¤¨ª®°³¡¤§ª¬¯²š £¦©«¯°˜Ÿ¢¤¨ª¬°¶¹»½ÁÂÅǵ·»¼¿ÁÃÆ´¶¹¼½ÀÂŲµ·º½¿ÁÃÈËÌÎÏÑÒÓÈÉÌÍÎÏÒÓÇÈÊÌÎÏÐÒÆÈÉËÍÎÏÑÔÕÖ××ÙÙÚÔÔÕÖ××ÙØÓÓÔÕÕ××ÙÒÓÔÕÕÕ××ÙÙÚÚÛÚÛÛÙÚÚÚÙÚÚÛØÙÚÙÚÚÚÙØØØÙÚÚÚÚÛÛÛÛÛÛÛÚÛÛÛÛÛÛÚÚÙÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÛÚÚÙÚÚÚÙÙÙÚÚÙÚÙÙÚÚÚÚÙØÙÙÚÚÚÙØÙÙ×ØØ×ÖÖÕÓÓÙ××ÖÕÔÔÓ×ØÖÖÔÔÔÓØÖÖÔÔÓÓÒÑÑÎÎÌËÈÇÒÐÎÍÌÉÈÅÑÏÎÍÌÉÇÆÐÏÎÍËÉÇÆÃÂÀ¼º¶´°ÃÁ¾¼º¶´°ÃÁ¾¼º¶´°ÃÁ¿¼¸¶³°®ª§£Ÿœ˜”­ª¦£ž›—”­ª¦£Ÿ›˜“¬©¦¢ž›—“‘ŒŠ’•—‘Œˆ’•—ŒŠ’•—Œ‰’”—˜›žŸ¢£¤˜›ž ¢£¤™šž¡¢£¤˜šž¡¡£¤¤¥¨¨©¨ªª¥¥§©©©©ª¦§§©¨ªªª¥¦§©¨ªªªª©©©¨¨¨¥ªªª©©¨¨¦ªªª©©©§§ªªªª¨©§¦¤¤¤£¢ ž¦¥££¢ Ÿ¦¥££¡¡Ÿž¦¤¤££ Ÿžœšš˜–”“’›™˜—–“’œ™˜—–“’œš˜—–•’Œ‹Š‡†„‘ŒŒŠ‡†…‘Ž‹Š‰†…‘ŒŠ‰†…ƒ€|{yxuƒ€~{yxu‚‚€~{zyw„~}zywsronmkhgtsqnmkhgtsqnmkjgtsqpmligecba_^^\fcbb`^^\fdbb`_]]fdcaa_^]ZZXWUUSR[YYWVUSR[ZYWVUSS[ZYXVVTRQPNMLKIIQPOMLKKIQPOMMKKIRPOOLLJIGFEDCB@?HGEDCCA@HGEECBA@HGFEDCA@MNOPRSTVMOOQRSUVMNOQRSUVMOPQRTVVWXY[\]_`WXY[\]_aWYZ[]^_aWYZ[]^_bbcdfhjlnbceghkmnbcegikmobdfgilnoqstwyz|psuwy{~rsuxz{~€rtvxz}€ƒ…‡Š‹„†‡ŠŒ‚„†‰‹Œ‘ƒ…†ˆ‹ŒŽ‘‘“–—™›ž’“–˜™œžŸ’•—˜›œž ’”—˜šž  £¤§¨ª«®¢£¥¦©ª¬®¢£¥¨©ª­¯£¤¦¨ª«­¯¯°³´µ·¸º°±³µ¶·º»°±´µ¶¸º»°²´¶¶¹»¼»½¾ÁÁÂÄƼ½ÀÁÂÃÅƼ¾ÀÁÂÃÅƼ¿ÀÂÂÃÆÇÇÇÈÊÌÌÎÎÇÈÊËËÍÍÏÈÈÉËÍÍÎÎÇÈÊËÍÎÎÏÏÏÑÓÒÔÔÔÏÑÑÓÓÓÓÕÐÑÑÒÔÔÔÔÏÑÓÓÔÓÕÔÔÕÔÖÖÖÕÔÕÔÖÖÕÕÖÖÔÖÕÖÖÖÖÖÖÖÖÖ××ÖÕÔÔÓÓÓÒÐÎÔÔÔÔÓÒÐÏÖÔÕÓÔÓÑÏÕÖÕÔÔÓÒÑÎÌÊÈÇÅÂÀÎÍËÉÇÅÃÁÎÍÌÉÈÆÃÁÎÍÌËÈÇŽ»¹µ³°­©¾¼¸¶´°®ª¿¼º·´±¯«À¼»·µ±¯«¦£¢ ¤¨«¯¨¤¢ ¤§ª®¨¤¢ £¥©­©¥¢¡¢¤©«±µ¹»¾ÁÃÇ°´·»¼ÀÂÅ°²¶º¼¿Áį±µ¸»½ÁÂÈËÍÏÑÓÔÕÈÉÌÎÐÒÔÕÇÉËÍÏÑÓÔÆÈÊÍÎÐÒÔØÙÚÚÛÜÝÞ×ØÙÚÚÜÜÝÕ×ÙÚÚÚÜÜÔÖ×ÙÚÚÚÜÞßàßààßßÞÞÞßàßààÝÞßÞÞßààÜÞÝßÞßÞÞßßàààààßàààààßßßàààßßÞßßÞÞÞßßÞßÝßßÝÝÜÚÚÚßÝÞÛÜÚÚÚÝÞÝÜÚÛÙÙÞÝÛÛÛÚÚÙØØÖÔÓÑÐÎÙ×ÕÔÓÒÐÎÙ×ÕÔÓÒÏÎ××ÕÔÓÒÏÎÍËÈÅÃÁ¾¼ÍËÈÇÃÁ¾¼ÍËÈÇÃÁÀ¼ÍËÈÇÄÂÀ¼º¶´°®«¨¥º¶´±¯«©¥º·µ±¯«©¥º·µ±¯¬©¦¢Ÿšž £¥£Ÿ›œ ¢¤£ œšž¢££¡ž™œž¡£¦©ª«¬­¯®¦¨©ª¬­­®¥§©ª«¬­®¤§¨ªª¬­­¯¯®¯­­«ª¯¯¯®®¬«ª¯¯¯¯­­«ª¯¯¯¯­­«ª©¨¥£¡ž™©¨¥¤¢Ÿ›©¨¥¤¢Ÿšª¨¥¤¢Ÿœ— £§©«¯˜›Ÿ£¤¨ª­˜™ž¡¤§©¬˜—žŸ£¥¨ª±µ¶º¼¾Á°³µ¸»¼À¯²´¶º¼¾Á®°´¶¸»½ÀÄÇÈÊÌÍÎÏÃÆÇÉËÍÎÏÂÄÇÈÊÌÍÎÂÃÆÇÉÊÌÎÒÓÓÔÕÖÕ×ÐÑÓÔÔÕÕÕÏÑÒÓÔÔÕÕÎÏÑÒÓÔÔÕ××ÙÙØÙÙÚ×Ø×ØÙÙÙØÖÖØ×××ÙÙÕÖÕ×ØØ××ÚÚÙÚÚÚÚÚØØÙÙÙÙØØÙÙÙÙÙÙÙÙ××ÙÙÙÙØ×ÙÙØÙØÙ×ØÙÙÙÙØ×Ø×ØÙØ××Ø×Õ×××Ø×ÖÕÖ×ÕÖÕÔÔÒÒÕÖÔÔÓÓÓÑÖÔÕÓÔÒÒÑÔÕÔÔÓÓÑÏÐÎÎÍÊÈÇÄÐÎÍÌÊÈÇÅÏÎÍÌÉÈÆÃÏÎÍÊÉÇÆÃÂÁ½»¹¶²¯ÂÀ½»¸µ³¯ÂÀ½»·µ±¯Á¾¼º·µ±®¬©¥¢ž›—’«©¤¢žš–“«¨¥¡š—’«¨¤¡™–’ŒŠ‘’”—‹‰Ž‘’•—‹Š‘’–—Ž‹‰‘”–˜šœž¡¢¤¤šœŸ¡££¥™œŸ¡£¤¤™œžŸ £¤¤¥§¨©©©ªª¦§§©©ªªª¦¨¨¨ªªªª¦¨©¨ªªªªªªªª©©§¨ªªªª©©¨¨ªªªªª¨©§ªªªªª¨©§¥¤¤¤¢¢Ÿž¥¥¤¤£¡Ÿž¦¦¤¤£¢ ž¦¥¥¤¢¢ŸŸ››™˜–•“žœ›˜˜—•“žšš˜—”“žšš˜—””‘Œ‹ˆ‡†’Œ‹‰‡†’Œ‹Š‡…’‘‹Š‡†„€~|zyvƒ‚€}{yx…ƒ€|{yx„ƒ€~{zxusronlihutronlkhusqpnmjhutsqnmkhfdcba_^]gecba`^^gedba_^^gecbb`_^\ZZXWVTS\[YXWUTS\ZZXWUUS\[YYWVUTQQOOMKKIRPPNMLKIRQPOMLKIRQPOMLKKHGGECCAAHGGEDCAAIHFEDCCAHHGEDCCANOPRSTUWOOQRSTUWNPQRSUVWOPQRSUVXXY[\]_`aXY[\]_`bYZ[]^_abYZ[]^_abcdfhjlnqceghkmnpcegikmorcfgilnorstwyz|suwy{~suxz{~€‚tvxz}€ƒƒ…‡Š‹‘„†‡ŠŒ’„†‰‹Œ‘’…†ˆ‹ŒŽ‘’“–—™œŸ “–˜™œŸ¢•—˜›ž ¢”—˜šž ££¤¦©ª«®¯£¥§©ª­®¯¤¥¨©ª¬¯°¤¦¨©«®¯°°³µµ·¹»¼±³µ¶·º»¼±´µ¶¸º»¼²´¶¶¹»¼¼½¿ÀÂÃÄÆǽÀÁÂÃÄÆǾÀÁÂÃÅÇÈ¿ÀÂÂÃÆÇÇÈÉËÌÍÎÎÏÈÉÊËÍÍÏÐÈÉÌÍÍÎÎÐÈÊËÍÎÎÏÐÑÑÓÓÔÔÔÕÑÑÒÔÓÔÔÖÒÒÓÔÔÕÔÖÑÓÓÔÔÕÖÕÖÖÖØØØØ×ÕÖØØ×ØØ×Õ××××Ö××××××ØÙØ×ÕÖÕÕÓÓÓÑ×ÕÖÔÔÔÓÒ××ÕÖÕÓÓÒ×ØÖÖÔÔÔÓÏÎÍÊÉÇÄÂÐÎÍÌÉÇÆÃÑÏÎÌÊÈÆÃÑÏÎÍÊÈÇÅÀ½»¸¶³¯­Á¿¼º¶´°®Á¿¼º·µ±¯ÂÀ½»·µ²¯ª¦£¢Ÿ¤§ªª¨¤¡Ÿ£¥©«¨¤¢ ¢¤¨«©¥¢¡ ¤¦®°´¶º½À¬°³¶¸¼¾Á«¯±µ·»½Áª®°´¶º¼¿ÄÇÉÌÍÏÑÓÃÇÈËÍÎÐÒÂÅÇÉÌÍÏÑÂÄÇÈÊÍÎÐÔÕ×ØÙÙÚÛÓÔÕØÙÙÙÚÓÔÕÖ×ØÚÙÒÓÔÕ×ØÙÚÜÜÞÝÝßßÞÚÜÛÝÞÝÝÝÚÚÜÛÜÜÞÞÙÚÚÛÜÛÛÜßßßßßÝÝÞÝÝÝÝÝÞÞÝÞÞÞÞÞÝÜÛÝÝÝÝÛÛÜÜÝÛÝÚÛÙÚØÛÜÛÛÚÚÙÙÜÛÛÚÙÚØØÚÛÛÙÙÙÙ×Ø×ÕÔÓÒÏÎ×ÖÔÓÓÒÏÎØÕÕÔÓÑÏÎÖÕÔÔÓÑÏÎÍËÈÇÅÂÀ¾ÌËÈÇÅÂÀ½ÍËÈÇÄÂÀ½ÍËÈÇÅ¿½»·µ²¯­©§»¸µ³°¬ª¦»¹µ²°­ª¨»¹¶³°®ª¨£ ž™šŸ¢¤¡žššž¡¤¢žœ˜œž ¤¢Ÿœ˜šŸ¤¥¨©ª««®£¤§¨ª«¬¬¢¤¥¨©ªª¬¢£¥§©ªª«­®¯­®­«ª®­¬­®¬«ª­®®®®«¬««­­­­«¬«ª§§¤£¡žœª©¦¤£ žœª©§¤£ žª©§¤£¢Ÿ™—œž¢¤¨ª™—šž £¦©™——Ÿ£¤¨›˜–œž ¤¦­¯²µ·º¼¿«®°´¶¹»½ª­°²µ·»¼©¬¯±µ¶¹»ÁÂÄÇÈÉÌÍÀÂÃÆÇÈÊÌ¿ÁÂÅÇÈÉ˽ÀÂÃÆÇÈÊÎÏÐÒÓÓÔÔÍÎÏÐÑÓÓÔÍÎÎÐÑÑÓÓÌÍÍÎÐÑÑÓÕÔÖÖÕ××ØÔÔÔÕÖÖÕÕÔÓÔÕÔÔÖÖÓÔÔÔÔÕÕÔØØ×××××Ø×××ÖØ×××ÖÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖØØ×ÖÕÖÖÔ×ÕÕÖÖÕÔÕÖÖÖÕÔÔÕÔÕÔÕÔÕÔÓÔÕÔÔÓÓÑÐÏÔÔÔÒÒÑÏÎÔÔÓÓÑÐÏÎÔÓÓÑÐÐÎÍÎÍÌÊÈÇÄÂÍÍÌÉÈÆÅÂÍÌËÉÇÆÃÂÍÌÉÈÇÅÃÁÁ¿¼º¶´°®À½»¸¶³°­À½»·µ²¯­¾¼º·µ±¯«ª§¤ œ™•‘ª¦£Ÿœ˜•‘©¥£Ÿœ˜”©¥¢ž›—“‹‰Ž‘“–—‹ˆŽ‘“–˜Š‰‘“•˜ŒˆŒ‘“—˜™œž ¡££¥™›Ÿ¡££¥›œžŸ¢£¤¥›œžŸ¢£¤¦¥§©©ªªªª¥§©©ªªªª§§©©ªªªª¦¨©©ªªªªªªªªª¨©§ªªªªª©©§ªªªªª©©§ªªªªª©©§§¥¥££¢ Ÿ§¥¥££¢¡Ÿ§¥¥££¢¡Ÿ§¥¥££¢¡Ÿž›™˜—•“ž›™˜—•“ž›™˜—•“ž›™˜—•“‘‘ŒŠ‡†’ŒŠ‡†’‘ŽŒ‰ˆ†’‘ŽŽŒ‰‰†…ƒ~{zw…ƒ~{zx…‚€~{zy…‚‚€~{zyutsqnmjhwtsqnmjjwtsqomljwtsqomligfdcb`_^gfdcb`_]hfdbb`_]hfdca`_^\[YYWVUT][ZYWVVS][ZYXVVT][ZYXVVTRQPOMLKKSQPOMMKKSQPOOMKJSRPOOLLKIGGEDCCAIHGEEDBAIHGEEDCAIHGGEDCAOPQSTVVXOPRSTVWXOQRSUUWXPQRSUVWYZZ\^^`acZ[\^_`bcY[\]_abcZ[]^_abcdfhiknqsdfhkmnqseghjmoqsegilmorttwyz|ƒtvy{~„uxz{~€„uxz|~€ƒ……‡Š‹‘“†‡ŠŒ’“†ˆŠŒ‘’•†‰‹Œ‘’•–—™œŸ £–˜™œžŸ¢£—˜šœžŸ¢£—˜›ž¡£¤¤¦©ª«®¯°¥¦©ª¬­°²¥¨©ª¬¯°±¥¨ª«¬¯°±³µµ¸¹»¼¾³µ¶·º»¼½´µ¶·º»¼½´µ·¹º¼½¾¾ÀÂÂÄÆÇÈ¿ÁÁÃÅÅÇÈÀÁÂÃÄÇÈÈÀÁÂÃÅÇÇÉÈÊÌÌÎÎÏÐÊÊËÍÍÏÏÐÉÊÌÍÍÎÐÒÉÌÍÍÎÎÐÒÑÓÓÓÔÔÖÕÒÒÔÓÕÔÖÖÒÓÔÔÕÖÕÖÓÓÔÔÕÖÕØØØ×ØÙÙÙÙØ×ØØÙÙÙÙØ×ÙÙÙÙÙÙ××ÙÙÙÙÙÙ×Ø×ÕÕÔÔÓÙ×ØÖÖÔÔÓÙØ××ÖÔÔÔÙÙ×ØÖÕÕÓÒÏÎÍÌÉÇÅÒÑÎÎÌÉÈÆÒÑÏÎÍËÈÆÓÒÏÎÍÊÈÇÂÁ½»¹µ²°ÃÁ¿¼º¶´°ÃÂÀ¼º·µ±ÅÂÀ½»·µ±­ª¦£¢ž£¥®ª¨¤¡ž¢¤¯«¨¤¢Ÿ ¤¯«©¥¢ Ÿ£©¬°³¶¸»¾¨«¯±µ·»¼§ª®°´¶º¼¥©­¯²µ¸»ÁÂÆÈÉÌÍÏÀÂÅÇÈËÍοÁÃÆÈÊÌͽÁÂÄÇÉËÍÑÓÓÕÕ×ØÙÐÒÓÔÕÖ×ÙÏÐÒÔÔÕÖØÎÏÒÓÔÔÖÖÚÙÚÛÚÛÜÜÙÚÙÚÛÚÚÚÙÙÚÚÙÚÛÛØÙØÙÚÚÙÚÛÛÛÛÜÜÛÚÛÜÜÛÚÚÛÚÛÛÛÛÛÛÚÚÚÚÚÚÚÚÙÚÚÛÚÚÚØÙ×ÚÙÚÚÙØØ×ÙÚÚÙØØ×ÖÚÚÙØÙ××ÖÕÕÔÔÒÐÐÎÖÔÔÓÒÑÎÎÕÕÓÓÒÑÏÎÔÔÔÒÒÐÎÎÍËÈÇÅÂÀ½ÍËÈÇÅÂÁ½ÍÊÈÇÅÂÁ¾ËËÈÇÅÂÁ¾»¸¶´°®ª¨»¸¶´°®«©»¹¶´±¯«©¼º¶´±¯«©¥¢Ÿ˜™œž¥£Ÿ™™œž¥£ š˜š¦£¡žš—™œ¡£¤¦¨©ªªŸ¢¤¥§©ªªŸ¡£¤¦¨©ªž ¢¤¥¨¨ª¬«­­«««««¬¬¬¬¬ª«««¬««¬ªªª««­­««ªª©¦¦¤¢Ÿ©©§¥¤¢Ÿª©§¥¤¡Ÿžª©§¥¤£¡žš˜–šŸ£¥š˜–—Ÿ¡¤œ™—•›ž £œ™—•™Ÿ¢©ª®°³µ·»§ª¬¯²µ¶¹¥©«®°³¶¸¤§ª­¯²´·¼¿ÁÂÅÆÈÉ»½ÀÂÃÅÇȺ¼¿ÁÂÄÆǹ»½ÀÁÃÅÇÊÌÍÎÎÐÑÑÉËÍÎÎÏÐÑÈÊÌÍÎÎÏÐÈÉËÌÍÍÎÏÓÓÔÓÓÔÔÕÑÓÒÓÔÔÓÓÑÒÒÒÓÓÔÓÐÑÑÒÓÒÒÓÔÕÕÕÕÕÕÕÔÔÕÕÕÕÕÔÔÔÓÓÓÓÓÓÔÔÔÔÔÔÔÔÕÕÕÔÓÔÓÓÔÔÓÔÔÔÓÒÔÔÓÔÓÓÒÒÔÓÓÒÒÓÒÑÒÓÑÑÐÎÎÍÓÑÑÐÏÎÎÍÑÑÐÏÎÍÍÌÑÐÏÎÍÍÌËÌËÉÈÆÄÂÀÌÉÈÇÆÃÁÀÊÉÈÆÅÂÁ¿ÉÈÇÆÃÂÀ½½¼º¶´°®ª½»¸¶²°­ª¼º·µ³¯­©»¹¶´±¯«©¨¤¡š—’§£ ™•’Ž¥£Ÿœ˜•‘¥¢ž›—“‘Œ‹‰Œ’•—˜‹…Ž’”—˜Š†’”—˜‰‡‘’”—š›žŸ¢£¤¦›ž ¢£¤¥šž¡¡¤¤¥œž¡¡¤¤¥¦¨©©ªªªª¦¨©©ªªªª§§©©ªªªª§§©©ªªªªªªªªª¨©§ªªªªª¨©§ªªªª©¨¨¨ªªª©©¨§¨§¥¥££¢ŸŸ¦¦¤¤¢¢ ž¥¥¤¤£¡ ž¦¤¤¤¢¢Ÿžž›™˜—•“žš™˜—•“šš—–””œ›˜˜—•’’ŒŒŠˆ†’‘ŒŠˆ†’‘ŒŠ‡†’Œ‹Š‡†…‚‚€~{zy…‚€~{zy…ƒ~{zy„ƒ~{ywwtspomliwtspomliwtsqomliwtsqomljhfdcaa_^hfdcaa_^hfdcaa_^hfdcaa_^][ZYXWUT][ZZWWVT][ZZWWVT][ZYWWVTSRPOOMLKSRQOOMLKSRQOOMLKSRQOOMLKIHGGEDCAIHGGEDCAIHGGEDCAIHGGEDCAPQRTUVXYPQSTVVXZPQSTVVXZPQSTUWXZZ\]^_abdZ\^^`acdZ\^_`bcd[\]_`acefgilmortfhiknqstfhkmnqstghkmnpsvvyz}€‚…wyz|ƒ…vy{~„†xy{~€„††ˆ‹‘“•‡Š‹’“–‡ŠŒ’“–ˆŠŒ‘’•——™šž¡£¤˜™œŸ¡£¤˜™œŸ¢£¥˜šœžŸ¢¤¥¦¨ª«®¯°³§©ª«®¯°³¦©ª¬­°²³¨©ª¬¯°±´´¶¶¹»¼¼¿´µ·¹»¼¾¾µ¶·º»¼½¿µ¶·º»¼½ÀÀÂÂÃÆÇÇÈÁÂÂÄÆÇÇÉÀÂÂÅÆÇÈÉÁÂÄÄÆÇÈÊÊËÍÎÎÏÏÑÉÌÍÎÎÐÑÑËÌÍÍÏÏÐÒËËÍÍÏÏÑÑÓÓÔÔÔÖÕØÓÓÓÕÔÖ×ØÒÔÓÕÔÖ×ØÒÔÓÕÖÕÖ××ÙÙÙÙÙÙÙ×ÙÙÙÙÙÙØ×ÙÙÙÙÚÙÙØÙÙØÚÚÚÙÙÙØ×ÖÖÔÔÙÙÙ×ØÕÕÔØÙÙØØÖÕÔÙØÙÙ×ÖÖÕÓÒÐÎÍÌÉÇÔÓÐÏÎÌÉÈÔÓÑÏÎÍËÈÓÓÒÏÎÍÊÈÅÃÁ½»¹µ³ÆÃÁ¿¼º¶´ÆÃÂÀ¼º¶´ÇÅÂÀ½»·µ°­©§£¡ž¢°®ª§¤¡ž ±®ª¨¤¡ŸŸ±¯«©¥¢ ¤¨ª¯±µ¶º¤§ª¬°³¶¹£¥©«¯±µ·¢¤¨ª®°´¶¼¿ÁÃÆÈÊÌ»½ÀÂÅÇÉ˺½ÀÂÄÆÈɺ¼¾ÁÃÅÇÉÍÏÐÒÓÔÔÖÍÎÏÑÓÓÔÔÌÍÎÐÒÓÔÔÊÍÎÏÐÒÓÓ×ØØØÙÚÙÚÕÖ×ØÙØÙÙÔÕÖØ×ÙØØÔÔÖÖØ×ØÙÚÚÚÚÚÚÚÙÚÚÚÚÚÚÙÙØÙÙÙÙØØÙÙØÙÙÙÙÙÙÚÙÙÙ×ØÖÖØÙÙ×ØÖÖÔØØ×Ø×ÖÕÕ××ØÖÕÖÔÔÔÔÔÓÑÏÎÎÔÓÓÒÑÏÎÍÔÔÓÒÐÐÎÍÓÓÓÑÐÎÍÍËËÈÇÅÂÁ¿ÌÊÈÇÅÂÁ¿ÌÉÈÇÅÂÁ¾ÌÉÈÇÅÂÁ¿¼º·µ±¯¬©¼º¸µ±¯­ª¼º·µ²¯¬ª¼º·µ³°¬ª§£ ž›˜˜›¦¤¡ž›™˜š§¤¢žœš—™¨¤¢žœ™˜˜Ÿ¢£¥§¨©ž¡£¤¥¨¨œžŸ¢£¥¦¨šŸ¡£¤¥¨©ª«ªª««ªªª««««ªª©ªª««««©¨ªªª«ªª©ª¨¨¥¤£ žª¨¨¥¤£¡žª¨¨¦¤£ žª¨¨¦¤£¢Ÿœ™—”˜œž¡›˜–•š ›˜–“™œžš˜–“˜›¤¦©«¯±´¶¢¤¨ª­°²µ¢¤§©¬¯°´ £¥©«­°²¸º¼¿ÁÂÄƶ¹»½ÀÁÃŶ¸º¼¿ÀÂõ¶¹»½¿ÁÂÇÈÊËÌÍÍÎÆÈÈÉÌÍÍÍÆÇÈÉÊÌÍÍÄÆÇÈÉÊËÍÏÏÐÒÑÑÓÒÎÎÐÏÑÒÑÒÍÎÎÏÐÏÑÒÍÍÎÏÎÐÐÏÒÒÓÓÓÓÓÓÒÓÓÓÓÓÓÓÒÑÑÑÒÒÑÑÐÑÐÑÒÒÑÑÒÒÒÓÑÑÒÐÓÒÒÑÒÑÏÐÑÒÑÑÏÐÏÎÑÏÐÐÏÎÏÎÐÏÎÍÍÍÌÉÎÎÍÍÍËÊÉÎÍÍÍËÊÉÈÎÍÍËÊÉÈÇÈÈÆÄÂÁ¾¼ÈÇÅÃÂÀ¾¼ÇÆÄÂÁ¿½»ÆÅÃÁÀ½¼º»¸¶²°®ª¨º¶µ±¯­©§¸¶³±¯«©¤·µ²°­ª¦¤¤¡š—’Œ£Ÿ˜–’Ž‹¢žœ˜”‘Š¡š—“Œ‰‰‡‘“–—™ˆˆŽ‘“–˜™†‹‘“–˜™…Ž’“•˜™œŸ £¤¤¥œžŸ¡£¤¤¥œžŸ¡£¤¤¥›žŸ £¤¤¦¦¨©©ªªªª§¨¨©ªªªª¦§©¨©©ªª¦§©©¨©ªªªªªª¨©§¦ªªª©©¨¨¦ªª©©©§§¦ª©©©§¨¥¦¦¥££¢ Ÿž¦¤¤£¢ ž¤¤¤£¡Ÿžž¤££¢¡Ÿžœš™˜–•“œ™˜—–“’›™˜—–“’œš˜˜—”“‘’Œ‹Š‡…‘Œ‹ˆ‡†‘‹‹ˆ†…Œ‹Šˆ†……‚€~{zx„‚€|{yx„€|zyxƒ‚€~|zyvutsqnmjiutsqnmkiutronmjhtsronlkhgfdcb`_^gfdcb`_]gecbb`^]gecbb`_]][ZYXVVT][ZYXVVT\[ZYXVVT\[YYWVUSSRQOOMLKSRPOOMLKSRPOOLLKSQPONMLJIHGGEDCAIHGGECCAIHGGEDCAIHGGDDCAQRSUVWYZQRSUVWYZQRSUVXYZQSTVVWZZ[]^_abce[]^_abdf\]^_abdf\^^`acdfghkmortugilnortuhilnortwhilnqstwxz{}€ƒ…†xz}€‚…†yz}€‚…‡yz|„…‡‰‹ŒŽ‘’”—ˆ‹ŒŽ‘’”—‰‹Ž‘”–—ŠŒ’“–˜˜šž¡¢¤¥˜šž £¤¥š›ž £¤§™œ ¡£¤§¨©«¬¯°±´¨ª«®¯°³´©ª«®¯°³´©ª«®¯±³µµ¶¸º»¼¾À¶·¹º¼½¿À¶¶¹»¼¼¿Àµ¸¸º»¾¾ÁÁÂÃÄÇÈÈÉÁÂÃÅÇÈÈÉÂÂÃÅÇÈÉÉÁÂÄÆÇÇÈÊËËÍÍÎÐÑÑËÍÍÍÎÐÒÒÌÍÍÎÎÐÒÓËÍÎÎÎÏÒÓÒÔÓÕÖÕØ×ÓÔÔÔÖÕØ×ÓÔÔÕÖÕØ×ÓÔÔÕÕÕØ×ÙÙÙÙÙÚÚÚÙÙØÙÚÚÚÚÙÙØÚÚÚÚÚÙÙØÚÚÚÚÚÚÙÙØØØÖÔÚÚØÙØØÕÖÚÚÙÙÙ××ÕÚÚÙØÙ××ÖÔÓÑÑÎÍÌÉÔÔÓÐÏÎÌÉÕÔÓÑÏÎÌËÔÓÓÒÏÎÍËÇÅÂÀ½»¹µÈÆÃÁ¿¼¸¶ÈÆÃÁ¾¼º¶ÈÇÅÂÀ½»·²°­©¦£Ÿ³°­ª§£¡´°®ª¨¤¡žµ±¯«¨¤¢žŸ£¦ª­°²µž£¥©«¯±µž ¤¨ª®°³œŸ£§©­¯±¸»½ÀÂÄÆȶº¼¾ÁÃÅǶ¹»½ÀÂÄƵ·»¼¿ÁÃÅÉÌÍÎÐÑÒÓÈËÌÎÎÏÑÓÈÉÌÍÎÏÐÑÇÈÊÌÍÎÏÑÓÔÔÖÕ×Ø×ÓÓÔÔÕÖÕ×ÓÓÓÔÕÔÕÖÑÓÓÔÔÔÕÔ×××××××××ØØØØØØ×ÕÕÖ××ÖÕÕÖÖÖÖÖÖÖÖØ×ÖÕÖÔÕÓÖÕÖÖÔÕÔÔÖÖÕÔÕÔÔÔÕÔÔÕÔÔÔÓÔÓÒÒÐÎÍÍÓÒÒÐÏÎÎÌÓÓÑÐÏÎÎÍÒÒÑÐÎÎÍËËÉÈÆÅÂÁ¿ËÉÇÇÅÂÁ¿ÊÊÈÇÅÂÁ¿ËÈÈÇÄÂÁ¿¼º·µ³°­ª¼¹·µ²°®ª¼»·µ²°®ª¼»·¶³°®«¨¤¢Ÿ˜˜—¨¥£Ÿ™˜—¨¥£Ÿ›˜—©¥£ ›—–™œž ¢¤¥¦™›Ÿ¢£¤¥˜šž¡£¤¥—™œžŸ¢£¤¨©ªªªª©ª§©©©ªªªª§¨¨ªªªªª¥§©©ªªªªª¨¨¥¥£¢Ÿª¨¨§¥¤¢Ÿ©¨¨§¥¤¡ ©©¨§¥¤£¡œ™—“•™žœ™—•”˜›žœ™—”’—šž™˜–’–™ž¢¤§ª¬¯°ž £¦©ª®°Ÿ£¤§ª¬¯›ž¡£¦©«®´¶¸º¼¾À²µ¶¹»½¿Á±´¶¸º¼¾À°³µ·¹»¼¿ÃÅÆÈÈÉÊËÂÃÆÇÈÈÊÊÁÂÄÆÇÇÈÊÁÂÃÄÆÇÈÈÍÍÎÍÎÏÎÐËÍÍÎÍÎÎÏÊÌÌÌÍÎÎÍÊÊÌÌÍÌÍÎÏÐÐÐÏÏÐÐÏÎÎÎÎÎÎÎÎÎÎÎÏÎÎÎÎÍÎÎÍÍÎÎÏÐÎÎÏÎÍÎÏÏÎÎÍÎÍÌÎÍÍÎÍÍÍÌÎÍÍÌÍÌËÊÍÍËÊÊÈÈÇÌËÊÉÈÈÇÆËÊÉÈÈÇÅÄÉÉÈÈÇÅÄÂÅÃÂÁ¿¼»¸ÃÂÁ¿½»¹¶ÂÁÀ¾¼»¸¶ÂÀ¾¼»¹·µ¶´°®¬©¥£µ²°­ª§¥¡´°®¬©¦£ ²°­ª§¤¢ŸŸ˜•’Ž‹‡žš˜”‘ŽŠ‡š—’Œ‰†›˜”’Ž‹‡„†’•—˜›ˆ’”—˜›‰‘’•—˜›Ž‘’”—˜››ž  £¤¤¥œž  ¢¤¤¤žž¡¢£¤¤žŸ¡¡££¥¥¨§¨©¨¨¨¦§§¨¨©©©¦¦¨§§©©©¥¦¦¨¨§§§¨©©¨§¦¦¤¨©§§¦¦¤¤§§¨¦¦¥¤£¨§¥¦¤¤££¤££¢ ž¤£¢¡Ÿžœ£¢¡ žž›£¢ žžœšœ™˜—–”’‘š™——•“’‘™˜—–”’‘˜˜—•“’‘Œ‹Š‡†„ŒŠ‰†…„ŽŒ‹Š‡†…ƒŒ‹ˆ‡…„‚ƒ€~{zxw€|{yxu~|zywu€}{zxvttsqomlihtrqnmkigsronlkhgsqomlihffecba`^^fdcaa_^]fdcb`_]]ecba`_^\\ZYXWVUT\ZZXWUUS[ZYXWVTS[ZYWVVTSRQPOMMKKRQPOMLKKRPPNMLKJRPOOMLKIIHGEEDCAIHGEEDBAHHGEDCCAIGGEDCCAQRTVWXY[RSTVWXZ[QSUUWXY[RSUVWYZ[\^^`bcdf\^_`acdg]]_abceg]^_abceghkmnpstvhjmnpsuxhjmorsuxikmortuxy{~„…‡y{~„†‡y{~€„†‰z{~€ƒ…†ˆŠŒ’“–˜‰ŒŽ’•–˜‹Œ‘’”—˜‹Œ‘’•—˜™œžŸ¢£¥¦š›žŸ¢¤¥¨›žŸ¡£¥¨›ž¡£¤¥¨©ª­­°±²µ©ª¬¯¯±³µ©«­®°±´µªª­¯°±´µ¶·¹»¼½¾Á¶·º»¼½¿Á¶·º»¼½¿Á¶¸º»¼½ÀÁÂÂÄÆÇÇÈÊÂÃÅÆÇÇÉÉÁÃÅÆÇÈÈÉÁÃÅÅÇÈÈËËÍÎÎÎÏÑÓËÍÎÎÏÏÑÓÌÌÎÎÐÏÑÓÌÌÎÎÐÐÑÓÓÔÔÔÖÕØØÓÔÔÔÖÕØ×ÓÔÔÔÖÕØ×ÓÔÔÔÖÕØ×ÙÙÙÚÚÚÚÚÙÙÙÚÚÚÚÚÙÙÙÚÚÚÚÚÙÙÙÚÚÚÚÚÚÚÚØÙ×ØÕÚÚÙÙÙÙØÖÚÚÚÙÙÙ×ÖÚÚÚÚØÙ×ÖÔÔÓÒÐÎÍËÖÔÔÒÑÎÍÌÕÔÔÒÐÐÍËÖÕÓÓÑÏÎÍÉÇÄÂÀ½»·ÉÇÆÃÁ½»¹ÊÈÆÃÁ¿¼ºËÈÇÃÂÀ¼ºµ²¯¬©¥£Ÿ¶²°­ª¦£Ÿ¶´°®ª§¤¡·´±®ª¨¤¢›Ÿ¢¤¨ª®°œž¡£§©­°Ÿ£¥©¬®ž›ž¢¤¨ª®´¶¹»½ÀÂIJµ·º¼¿Áñµ·¹¼¾Á°³µ¸»½¿ÁÆÈÉËÍÎÎÐÅÇÈÉÌÍÎÎÄÆÇÉËÌÍÎÃÅÇÈÉËÍÎÑÑÓÓÔÓÔÕÏÑÑÓÓÔÔÓÎÐÑÑÓÓÓÔÎÏÐÑÑÒÒÓÕÔÔÔÔÔÔÕÔÔÕÕÕÕÕÕÔÔÓÓÓÓÓÓÓÔÓÔÔÔÔÓÔÕÔÓÔÓÓÒÔÓÓÔÔÓÒÓÔÔÓÔÓÓÓÑÔÔÓÒÒÓÑÒÒÑÐÏÏÍÍÌÑÑÐÎÎÎÍËÒÏÏÏÍÍÍÌÐÐÎÎÎÍËÊÊÉÈÅÅÂÁ¿ÊÈÇÆÄÂÁ¿ÉÈÇÆÃÂÁ¿ÉÈÇÆÃÂÁ¿¼»¸µ´°®«¼»¸¶´°¯«¼»¹¶´±¯«¼»¹¶´²¯¬©¥£¡š˜–©¦£ ž›˜—©§¤ žœ˜—©¦¤¡žœ™––˜šž £¤•˜™œž ¢£–—™›Ÿ¡£•–˜›ž ¢¥§§©©ªªª¤¥§¨¨©©©¤¥¦§©©©©¤¤¦§§©©©©©§§¥¤£¡©©§§¤££¡©©§¦¦¤£ ©©§¦¦¤£¢ž›˜–“”˜žš˜•“’—Ÿ›˜—“‘–Ÿžœ™—•’”šŸ£¤§ª¬˜œž¡¤¦©«˜š £¤¨ª—™ž¡¤¦©¯±´¶¸º¼½®°²µ¶¸»¼­¯±´¶·º»«®°²´¶¸º¿ÁÂÃÅÆÇǾÀÁÂÄÅÆǽ¿ÀÂÂÃÅƼ½¿ÁÂÂÃÅÈÉÊËËÌÍÌÇÈÈÊÊÊËËÇÈÈÉÉÊÉÊÆÇÇÇÈÉÈÊÌÍÍÍÍÍÍÍÌËÍÍÍÍÌËËËÌÌÌÌËËÉÊÊÊÊÊÉÉÌÍÌÌËËÊÉÌËËËÊÉÈÈÊÊÉÊÈÈÈÇÊÈÉÈÇÈÇÆÈÈÇÆÅÄÃÂÇÇÆÅÄÂÁÁÇÆÅÄÂÂÁ¿ÆÄÃÂÁÀ¿½Á¿½»¹·µ³¿½¼º¸¶´±½¼º¸¶´²°¼º¹·µ³±®±¯¬©¦¤ ¯­ª§¥¢žœ®ª¨¦£ š¬ª¨¤¡Ÿ›™š—”‘Œ‰††™–’Œˆ„‰—“Ž‹†‚Œ–’‹‰††‹ŒŽ‘’”—˜›Œ‘””—˜›Ž‘”–—˜›’”–—˜šžŸ ¢£¤¤œž ¡£££›žŸ¡¢£¤œžŸ ¡££¥¥¦¥§§§§¤¥¥¦¦¦¦¦£¤¥¤¤¤¤¤¤£¤¤¤¤¤¤¥¦¥¤¤£££¦¤¥¤¤££¢¥¤£¤£¢¢ £¤££¢¡ŸŸ¢ Ÿžœš™ Ÿžœ›š˜Ÿžœ›š˜—ž›™˜—–˜—–“’‘Ž—–”’’–•“’‘Œ•“’‘Œ‹Œ‹Š‡†…ƒ‹Šˆ†…„‚€‹‰‡†„ƒ€Šˆ†…ƒ€~€~|zywut}{zxvts~|zywusr}zyxvtsprpnmkigfqomljhgepnmkigfdomljhgecdcaa_^]\cbb`_]][cba_^^\[bb`_^][Z[ZXWVUTRZYXWUUSRYYWVUTSQZXWUUSRQQPONLLKIQPOMLKKIPONMLKJHPONMLJIHHGGEDCB@HGFDCCAAHGEDCCA@GGEDCCA@RSUVWYZ[RTUVWYZ[RSUVWYZ[STVVWZZ\]^_abdfg]^`abdfh]^_bbdfg^_`acdfhilnortuxilnoqtwyilnpstvyilnqstwyz}€ƒ…†ˆz|€‚…†‰z|€ƒ…ˆŠz|‚„…‡Š‹ŒŽ‘’”—˜‹‘”–—™‹’“–—™Œ’“–˜™šž¡£¤¥¨šž¡£¤§¨œž £¤¦©œ ¡£¤§¨ª¬¬¯°±´µª«®¯°³´¶ª«®¯°³³¶ª«®¯±²µ¶¶¹º»¼¾ÀÁ·¹¹»¼¾ÀÁ·¸»¼½¾ÀÁ¶¹»¼½¿¿ÁÂÄÅÅÇÈÉËÂÄÄÇÇÈÊÊÂÃÄÆÈÈÊÊÂÃÄÇÈÈÊÊÌÌÎÎÐÐÑÓÌÌÎÎÐÐÑÓÌÍÎÎÐÐÑÓÌÍÎÎÐÐÑÓÓÔÔÔÖÕØ×ÓÔÔÔÕÕØ×ÓÔÔÔÖÕØ×ÓÔÔÕÕÕØ×ÙÙÙÚÚÚÚÚÙÙÙÙÚÚÚÚÙÙØÚÚÚÚÚÙÙØÚÚÚÚÚÚÚÚÚØÙ×ØÚÚÚÚÙÙ×ØÚÚÚÚÙÙÙØÚÚÚÚÙÙÙ×ÖÔÓÓÒÏÎÍÕÔÔÓÒÐÎÍÕÖÔÔÒÑÎÍ×ÖÔÔÒÐÐÎÊÈÇÅÂÀ½»ÌÊÇÄÂÀ½»ÌÉÈÆÃÁ¿»ËÉÈÆÃÁ¾¼·µ±¯«©¥¢¹µ³¯­©¥£¸¶²°¬ª§£º¶´°®ª¨¤Ÿ›¡¤¦ª­Ÿ›œž£¥©ª œšž ¤¦ª¡ž™Ÿ£¥©¯±´¶º¼¾Á®°´¶¸»½¿­¯²µ·º¼¾¬®°´¶¸»½ÂÄÆÇÈÊÌÍÁÃÄÇÈÉÊÌÀÂÃÆÇÈÉË¿ÁÂÅÆÈÈÉÎÎÏÐÐÑÒÓÍÎÎÎÐÐÒÑÌÍÍÎÎÐÏÑËÌÍÍÎÏÏÐÒÒÓÓÓÓÓÓÑÓÓÓÓÓÓÓÒÑÑÑÑÑÑÑÏÑÑÒÒÒÒÒÒÒÓÓÒÑÒÐÒÓÒÑÑÒÐÐÑÑÑÒÑÏÐÏÒÒÐÐÏÐÏÏÐÏÏÍÎÍÌÊÏÏÎÎÍÍÌÊÏÎÍÎÌÌÊÉÎÍÎÍÍËÊÉÈÈÇÆÃÂÁ¿ÈÈÇÅÃÂÁ¿ÈÈÆÄÄÂÁ¿ÈÇÆÅÃÂÀ¿¼»¹¶´±¯­¼»¹¶´±¯­¼»¹¶´±¯­¼»¸¶´±¯¬ª¦¤¢žœ™–ª§¤¢Ÿ™—ª¨¤¢Ÿ™—ª¨¤¢Ÿš—–”—™œžŸ¢•”–˜šž¡•”–˜šœžŸ””•—™›Ÿ£¤¥¥¨§©©¢¤¤¦¦§§©¢£¤¤¦§§§ ¢¤¤¥¥§¨¨§¨¥¦¤£¢©§¨¥¦¤£¢¦§¨¥¦¤£¢¨§§¥¦¤¤¡Ÿžœ™—”’’Ÿžœ™˜–“‘¡ž›˜–“‘¡žš˜—“’–˜› £¤¨•—™Ÿ¡¤¦“–˜› £¤‘”—šŸ¡¤ª­¯°³µ·¹©«®°²´¶¸¨ª¬¯°²µ¶¦©ª­¯±³µ»¼½ÀÁÂÂĺ»¼¾¿Á¸º»¼¾¿Á·¹º»½¾¿ÁÅÆÇÇÈÇÈÈÃÄÅÆÇÇÇÈÂÃÃÄÅÆÆÇÁÂÂÃÃÅÄÅÉÉÈÈÈÈÉÈÇÇÇÇÇÇÇÈÇÇÇÇÇÇÇÇÅÆÆÆÆÆÅÄÈÇÈÇÇÇÆÄÇÇÇÆÆÅÄÃÅÆÅÄÃÃÂÂÅÄÃÃÂÂÁÁÃÃÂÁÀ¿½¼ÂÂÁÀ¾½¼»ÁÀ¿¾¼»º¹À¿½¼»º¸·»¹¶µ³°¯­¹¶µ²±°­ª¶µ´³¯®ª©µ´²°¯¬ª§ª¨¤£Ÿœš–¨¦¤¡œ˜•§¤¢ž˜—’¥£ š˜”’”Ž‹†„ˆŒ‘‹‰…„Š‹‘Œ‹††…‰ŒŽŒˆ…‰‰Œ’”•—˜™’””—˜™’“”——™’“”—˜˜œŸ ¡¡£›žžŸ ¡¡›œžŸ ¡š›žžŸ££¤¤¤¤¤£¢£¢¢¢£££¡¡¢¢¢¢¡    ¡Ÿ ŸŸ££¢¢ ŸŸž¢¡ ŸŸžž ŸŸžžœžžžœ›™œ›š˜—–•œ›™˜—–•“š™˜—–•“’˜˜—–”“’‘“’‘ŽŒ‹Š’‘ŽŒ‹Šˆ‘ŽŒ‹Šˆ†ŽŒ‹Šˆ†…ˆ†…„€}†…„‚€}{…„‚€}|z„‚€}|zy{zxvtsqozywusrpnywutrpnmwutrqomlnlkhgfdcmkigfdcbkihgecbbjhgfdca`a`_^]\[Ya`_]][ZY`_^][ZYY_^]\[ZYWXWVVTSRQXWUTSRQPWVUTSRPOVVTSRQPOOOMLKKIHONMLKIHGOMLKKIHGNMLJIHGGGFDDCAA@GEDCCA@?FEDCB@??EDCCA@??STVWXY[\RTVWXZZ\STVWXZ[\STUWXZ[\^_`bcdfh^_`bcdfh^_`acegh]_`bceghkmnqstvyjmnpstwykmnpsvxyjmorsuxz|~„†‡Š{~€„…‡‰{~„†‡Š{~€ƒ†‰Š‹’“–—™Œ’“–˜™Œ‘’•–˜™Œ‘’•–˜›œžŸ¢£¥§©œžŸ¢£¤¦©œžŸ¢¤¦¦©œžŸ¢¤¦§©ª«®°±³µ¶ª¬®°±³µ¶ª­­°±²µµª­®°²²´¶¸¸»¼½¿¿Á¸¸»¼½¿¿Á¸¸»¼½¿¿Â·¹»¼¼¿ÀÂÂÃÅÇÈÈÊÊÂÃÆÇÈÈÊÊÂÃÆÇÈÈÊÊÂÃÆÇÈÈÊÊÌÍÎÎÐÏÑÓÌÍÍÎÐÏÑÓÌÌÎÎÐÏÑÓÌÌÎÎÎÏÒÓÓÔÔÕÖÕØ×ÓÔÔÕÖÕØ×ÓÔÔÔÖÕÖ×ÓÔÓÕÕÕ×ØÙÙØÚÚÚÚÚÙÙØÙÚÚÚÚØÙÙÙÚÚÚÚ×ÙÙÙÚÚÚÚÚÚÚÚÙÙÙ×ÚÚÚÚÚØÙ×ÚÚÚÚÚØØØÚÚÚÚÚØÙ××ÕÕÔÓÑÏÎ×ÖÕÓÓÒÏÎ×ÖÔÓÓÒÐÎØÖÔÔÓÒÑÎÍËÈÆÃÂÀ¼ÍËÈÇÅÂÀ½ÍÊÉÇÄÂÀ½ÍÌÉÇÆÃÁ½º·´±®«¨¤»·µ±¯«©¥»¹µ³¯­©¦»¸¶²°¬ª§¢ž™œž¢¥¨¢ž›šž ¤¦£Ÿœ˜Ÿ£¥£ ž—œž¡¤ª®°³µ·º¼©¬¯±´¶¹»©ª®°³µ·º¦ª¬¯±µ¶¸¾ÀÂÃÅÇÈɽ¿ÁÂÄÆÇȼ¾ÀÁÃÅÆÇ»½¾ÁÂÃÅÇÊÌÍÍÎÎÏÎÉÊÌÍÍÎÍÎÈÉÊËÍÍÎÍÈÈÊÊÌÌÌÍÐÐÏÏÐÑÑÑÏÎÏÏÐÐÐÐÎÎÏÏÎÎÎÎÎÍÎÎÎÏÏÏÏÏÏÐÐÎÎÎÐÐÏÎÏÏÎÍÎÏÎÏÎÎÍÍÏÎÎÍÍÎÎÍÍÍÍÌÌËÊÈÍÍÌÌËÊÉÉÍÌÍËËÊÈÈÌÍËÌÉÉÉÇÇÇÆÅÿ¿ÇÇÆÄÂÁÀ½ÈÇÅÃÂÁÀ½ÇÆÄÃÂÁÀ½¼»¹¶´±¯¬¼º¹¶´±¯­¼»¹¶´±°­¼»¹¶´±°®ª¨¦£Ÿ›˜ª¨¥£Ÿ›˜ª§¥£ š˜ª©¥£¡ž›˜””“–˜›ž–”“•—™œ–’“”—˜š–“““–˜šœŸ¢£¤¤¦¦¨Ÿ¡£¤¤¥¦¥ž ¢£¤¥¦¥žŸ¡£¤¤¤¦§§§¦¤¤¤£§§¥¦¤¤¤£¥¥¦¦¤¤¤£¥¦¦¦¤¤¤£ Ÿ›™—•’ Ÿžœ™—•’¡Ÿ›™˜–“¢Ÿž›˜–“‘“—˜› ¢’•—™Ÿ¡‘“–˜› ‘’”—™œž¤§ª¬¯°²´£¦©ª­¯°³£¤§©ª­¯°¡£¥¨©¬®°¶·¹»»¼¾¿´¶·¹»¼¼½³µ¶·¹º»¼±³µ¶·¹º»ÀÁÂÂÂÂÃÿÀÀÁÁÁ½½¾ÀÀÀÁÁ¼¼½½¿¾ÀÀÃÄÄÄÄÃÃÄÂÂÂÂÂÂÂÂÁÁÂÁÁÁÁÁÀÀÀÀÀÀ¾¿ÂÂÂÂÁÁÀ¿ÂÁÁÀÀ¾½½ÀÀ¿¿½½¼»¿½½¼¼»»º½¼¼»º¸¶µ¼»º¹·¶µ³»¹¸·¶´³°¹·¶µ´²°¯³³°¯¬©§¤±¯¯¬©¨¥£°®¬©©¦¤¡­«©©¦£¡ž£ žœ˜•“ ž›˜—’‘ŽŸ™—”’‹š˜”‘ŠŠ‡ƒ…‰‹Œ‹ˆ…ƒ†‰‹Œ‰……€†ˆ‹‹†„††‰‰Œ‘’”–—˜‘’“–——Ž‘’“•–—Ž‘’““–—™š›žžž˜šš›ž˜˜šš›œœœ—˜˜™™š›šžžŸŸŸžžžžžžžžžœ›œ›››šššš™™žœ›š™˜œœ›š™˜——›™™˜˜—–•˜˜——–•”“—–•”’‘–•“’‘“’‘‘ŽŒ‹’‘Œ‹ŠŒ‹‰ˆ†…„Œ‹‰ˆ†…ƒ‚Š‰‡†…ƒ€ˆ†…„ƒ€€‚€}|zyw€}}zywu}{zywut|zzywttrutrqnmljtrqnmljhspomljhgpomljhgfhgfdcb`_gfdcba_^fdcba`_]dcba`_^\^]\[ZYXW]\[ZYXWV\[ZYXWVU[ZYXWVUTUTSRQPOOUTSQPOOMTSRQPOMLSRQPONMLMLKJIHGFLKKIHGGEKKIHGGEDKJIGGFEDEDCAA??>DCCA@??=CCA@@?===<;:9SUVWYZ[]TUVWYZ\]TUVXYZ\]SUVXYZ[^^`abcfgi^_abcfhi^_bbdfhi^_bbdfhilnortvyzlmortwyzlnoqtwyzlnostwyz}€ƒ…†ˆ‹}€ƒ…‡ˆ‹}€‚…‡ˆ‹}€‚…†‰‹Ž‘“”—˜›Ž‘“”—™›‘’”—™›Ž‘””—™šž £¤¥¨©ž¡£¤¥¨ªž¡£¤¥¨ªž¡£¤¥¨ª«­¯°±³µ¶«­¯°±³µ¶«­¯°±³µ¶«­¯°±³µ¶·¹»»¾¾Á·¹»»¾¿¿Â·¹»»¼¿¿Á·¹»¼½¿¿ÁÂÃÄÇÇÈÈÉÂÃÄÇÇÈÈÉÂÃÅÆÇÈÈÉÂÄÄÅÇÇÈÊËÍÎÎÎÐÐÒËÍÎÍÏÏÑÑËÍÍÍÏÏÑÑÌÍÍÍÏÐÏÒÒÓÔÔÕÖÕ×ÓÓÔÔÕÔÖÖÓÓÔÓÕÔÖÕÓÒÔÓÔÕÖÕØ×ÙÙÙÙÙÚØ×ÙÙÙØÙÙØ××ÙÙÙØÙÖØ×ÙÙÙÙÙÚÚÚÚÙÙÙ×ÚÚÚÚÙÙÙ×ÚÚÙÙØÙÙ×ÙÚÙØÙÙÙ×ØÕÖÕÓÓÒÏØÖÕÕÓÓÒÐØ×ÕÕÓÓÒÐØÖÕÕÓÓÑÑÎÍÊÉÇÄÂÁÎÍÌÉÈÆÃÁÏÍÌÉÇÆÃÁÏÎÌÉÈÅÃÁ½»¹¶²°¬ª¿¼¸¶´°®ª¾¼º¶´°®ªÀ¼º·µ±¯«§£ —˜œž§¤¡™–š¨¤¢žš–˜œ©¥¢žœ•˜›¡¤§©¬®±³Ÿ£¥©«®°²Ÿ¡¤§ª¬¯° £¦©ª®°µ·º»½¿Á´¶¹»¼½ÀÁ³µ·º»¼¿À²´¶¹º¼½¿ÃÄÅÇÈÈÉÉÂÃÄÅÇÇÇÈÁÂÄÅÆÆÇÇÁÂÂÄÅÆÆÇÊÉËÌËËËÌÈÊÊÉÊËÊÌÈÉÈÊÊÊÊÉÈÇÈÉÈÈÈÊÌËËËÌËËÉÌÌÊËÊÉÊÉÉÉÉÊÊÊÉÉÊÊÊÈÈÉÉÈÊÉÉÈÇÈÇÆÈÉÈÇÇÇÇÅÉÈÇÇÇÆÆÆÈÇÇÇÆÇÅÄÅÄÂÂÁÀ¾½ÅÄÃÁÁÀ¾¼ÃÃÂÂÁ¿½¼ÄÂÂÁÀ¾½¼»º·¶´±°®»º·¶´±°®»º·¶´±°®»¹·¶´±°®«©§¤¢žœ™«©§¤¢Ÿ™«©¦¤¢Ÿ™«©¦¤¢Ÿš—•’‘“–˜—•’‘’•——”’‘’”–˜”’‘“–šœŸ ¢£¤™›žŸ¢¢¤˜šœžŸ¡¢£—™œžŸ¢¢¤¤¥¥¥¥£¤£¤¤¥¥¥£¤££¥¥¥¥£¤¤¤¤¥¥¤¤££¡Ÿžš˜—£¢ žœ™—¢¢¡žžœš˜£¢  žš˜”’’”—–“‹Ž‘“•–”’‹‘“—”’‹‘˜›žŸ¢¤¥§—™œ ¢¤¥–—šž ¢¤”—˜šž ¢©ª¬®¯°±²§©ª¬­®¯°¥§¨ªª¬®¯£¥¦¨©ª«¬³´µµµ¶¶¶±²²´´´µµ¯°°±±±³³­®¯¯¯°°°¶¶¶¶¶¶¶µµµµµ´´´²³³³³±±²°°°°°¯¯¯®µ´´³±±°¯³±±°¯¯®¬°¯¯®­¬ªª®¬­«ªª©§®¬ªª¨¨¤¤«ª©§¦¤£¡©§¦¥£¢ ž¦¤££¡žž›¢ š˜•“žž›˜˜•’œ›˜—”“‘Žš˜—”‘‘Ž‹Œ‰†…‚~Œ‰†…ƒ|~‹‰‡…‚}}‰†…‚|z}}€‚…††ˆŠ€ƒ„…†‡ˆ€€„…††ˆ€ƒ„…†‡‹ŒŒŽ‘‘Š‹ŒŒŽ‰Š‹ŒŒŒˆ‰Š‹‹ŒŒŒ’‘’’’“““‘‘‘‘‘‘‘ŽŽŽŽ’’’’’‘‘‘‘‘ŽŽŒŒ‹ŒŒŒŒ‹‹ŠŠŽŒŒ‹Š‰Œ‹‹Š‰‡†‹Š‰ˆ‡†……‰‡††…„ƒ‡†……ƒ€……ƒ€}ƒ‚€~}{z€~}|{zy~|zzywut{zywvtsryxwtsrqowutsrpomrqonmkihpomljigfnmkjhgedljhhgeccffdcba`_dcbaa_^]cba`_^]\ba__^][[^]\ZZYWW][ZZXWVU[ZYXWVUTZYXWVUTSVUSSRQPOTSRQPOOMSRQPOOMLRQPOOMLKNMLKJIHGMLKJIHGFKKIIHGFEKIHGGFEDGEDCCAA@EDCCA@@?DCCA@@?>CCA@??>=?>=<;:99>=<;::88=<;::987<;::9876SVVWZZ[^SVVWZZ[^SVVWZZ[^TVVWZZ\^^`bcdfhi^`bcdfhi_`bcdfhi_`bcdfhilnqstwyzlnqrtwyzlnqstwyzlnqstwyz}‚…ˆŠ‹}‚…ˆŠ‹|‚…ˆŠ‹|ƒ…ˆŠ‹Ž‘”–—™šŽ‘”–—™šŽ‘”–—™šŽ‘”–—™šž¡£¤¥¨ªž¡£¤¥¨ªž¡£¤¥¨ªž¡£¤¥¨©«­¯°±³µ¶«­¯¯±³µ¶«­¯°±³µ¶«­¯°²²µµ·¹»¼½¿¿Á·ºº¼½¿ÀÁ·¸»¼½¿ÀÁ¸¸»¼½½ÀÁÂÄÅÅÇÇÈÊÂÃÅÆÇÇÉÊÂÂÅÆÇÇÉÉÁÃÄÆÆÈÈÉÌÍÍÍÎÏÏÒËËÍÍÎÎÐÑËÌÌÎÎÎÐÑÊÌÌÎÎÏÏÑÑÒÔÔÔÕÕÖÒÓÓÔÔÕÔÖÑÓÓÓÓÕÕÖÑÓÒÔÔÔÕÕÖØ×ØÙÙÙÙÕØØ×ÙÙÙÙÕ×××ØÙÙÙÖÕØØ×ÙÙÙØØØÙÙÙÙ×ÙÙÙÙÙÙØ×ÙÙÙÙÙÙÙ×ÙÙÙÙÙÙØ×Ø×ÕÕÓÓÑÑØÕÕÕÓÓÒÑØÕÕÕÓÓÓÐØÕÖÕÓÔÒÐÏÎÌËÈÇÅÂÏÎÍÊÈÇÄÂÐÎÌËÈÇÄÂÏÎÍËÈÇÄÂÀ½»·µ²¯¬À½»¸µ³°­À½»¹¶²°­Á¿¼¸¶´°®©¥£Ÿœ–—™©§£Ÿ˜•˜ª¦¤ š“—ª¨¤¡ž›”–ž¢¤§ª¬¯›ž¡£¦©«®™Ÿ¢¤¨ª¬™œž¡¤¦©«°³µ·¹»¼¾°²´¶¸º¼½¯°³µ·¹»¼®°²´¶¸º»¿ÁÂÃÃÅÆÇ¿ÀÁÂÃÃÅŽ¿ÁÁÂÃÃż½ÀÁÂÂÃÄÇÈÇÈÈÉÉÉÇÇÇÈÈÇÇÈÅÆÇÇÇÈÈÈÄÆÅÇÆÆÇÇÉÉÈÉÉÈÈÇÈÈÈÇÇÈÈÇÈÈÈÈÇÈÇÇÇÇÇÇÇÆÆÆÈÈÇÆÇÅÅÄÈÇÆÇÅÆÃÃÆÆÆÅÆÄÄÂÇÅÅÆÄÃÂÃÃÂÂÁÀ¿½»ÃÂÂÁÀ¾¼¼ÂÁÁÀ¿½¼¼ÁÂÀÀ¿¾¼»»¸¸¶´±°®»¹¶¶´±°®º¹·µ´±°®º¹¶µ´±°®«©¦¤¡Ÿ›«©§¤¡Ÿš«©§¤£Ÿš«©§¤£Ÿš˜•’’•˜–’‘‘“˜–“‘‘“˜–“‘Ž’—˜šžŸ ¢–˜™œž ¢•—™›žŸ¡”—˜šœžž ££¤¤¥¤¤¤££¤¤££¤¤¢£¤¤¤¤¤¤¢££¤¤¤¤¤££¡Ÿžœ™££¢ žžœš¤¢¢¡Ÿžš¤£¢¡Ÿžœ—–“ŽŠŒŽ‘˜—•‘‡‹ŒŽ™—•“ˆˆŠŒ™˜–”‹‡‰‹’”—˜šžŸ‘’”—˜šœž’”—˜š›Œ’”—˜˜¡£¤¥§©©ªž¡£¤¤¥§¨ž ¡¢¤¤¥›Ÿ ¡££««­¬®®®®©©ªªª¬««§§¨¨©©©©¤¤¥¥¥¦¦§®®®®®¬­«««««ªªª©©©©©¨¨¨§§¦¦¥¥¤¤¤«ªª©¨¦¥¥©¨§§¥¤££¥¥¤££¢ Ÿ££¢¡ŸŸœ££¡Ÿž›˜¡Ÿž›š——žœ™˜—•“›š˜—•”’‘—•’’Œ‹Š”“‘ŒŠˆ†’Ž‹‹ˆ…„Œ‹‰††„‡…ƒ}y{|~…‚}xy{{}‚zvyzz{}yvwyyzz|€‚ƒ……†€‚„……~€€‚ƒ„}~€€‚†‡ˆ‰Š‹‹‹…††‡‰ˆ‰Š………†††ˆ‡„„…………††‹ŒŒŒŒŒ‹‹ŠŠŠŠŠŠŠ‰‡‡‡‡‡‡ˆ††††††………‹‹ŠŠ‰‰‡‡ˆ‰‡‡††……†††……„ƒƒ…„„‚‚€†……„ƒ€€„ƒ‚€~}€€~}|{~|{zzy~}|{zywv|zzyxvuszyxvttsrxvutsoqktssqonlkrqonmljiponljifgmhiggggfihgedcbahgecca``cdcbbbbafeeddccb`_^^\[ZY_^]]][[[a`__^]]\bba``_^^XWVUUTRQZZYXWVVU[[ZZYXWV]][[ZZYWQPOOMLKKSSRQPOOMVUSSRQPOWVUTSRQPJHGGEDCCLKLIHGFENMLKJIGGOOMLKJIGBA@??>=<<;EDCBA@>=GEDCBA??;:988765:9987655;9776544=<;:8642TUWWZZ\^TVWXZ[\^TVWXZ[\^TVWXZ[\^_`bcdfhi_`bcdfhi_`bcdfhi_`bcdfhilnqstwyzlnqstwyzlnqstwyzknqstwyz|ƒ…ˆŠ‹|ƒ…ˆŠ‹|ƒ…ˆŠ‹|‚…ˆŠ‹Ž‘”–—™šŽ‘”–—™›Ž‘””—™›Ž‘“”—™›ž¡£¤¥¨©ž¡£¤¥¨©ž £¤¥¨©ž¡¢¤¥¨©«­¯°²²µ¶«­¯°²²µ¶ª­®°°³µ¶ª­­°±³µ¶¸¸»¼¼¾ÀÁ¶¹»»¼¾ÀÀ·¹º¼¼½¿Á·¹¹»¼½ÀÀÁÂÄÅÇÈÈÊÂÂÄÅÇÈÈÈÁÃÃÆÇÇÈÈÂÂÃÅÇÇÇÈÊËÍÍÍÏÐÏÉËÍÍÍÎÎÏÊÌÍÍÍÎÎÐÊËËÌÎÎÏÏÒÒÒÓÔÔÕÔÒÒÒÓÓÓÕÕÐÑÓÒÔÔÔÔÐÑÒÒÓÔÓÕÖÕ××××ÙÙÖÖÕØØ×ØØÔÖÕ××Ø×ØÕÖÖÕ××Ø×ÙÙÙÙÙØØ×ÙÙÙÙÙÙÖØÙÙÙÙÙ××××ØÙØ××ØØØÕÖÕÓÔÓÑÖÕÖÕÓÔÓÒ×ÕÖÕÓÔÓÒÖÖÔÕÓÓÓÒÏÎÍÊÊÇÆÄÏÎÍÌÉÈÆÃÏÎÍÌÉÈÆÃÏÎÍÌÉÈÅÃÁ¿¼º¶´±®Á¾¼º·µ±¯Á¿¼º·µ±¯ÂÀ¼»·µ²¯ª¨¤¢ž›•”«©¥¢žœ—“«©¥£Ÿœ™’¬©¦£Ÿ™“˜šŸ£¥¨ª—™Ÿ¡¤§©–˜›ž £¥©”—šœž¢¤§­¯±³µ¶¹º«®°²´¶·¹ª­¯±³µ¶¸©«®°²´µ·¼½¾¿Á»¼½¿ÀÁº»¼½¿ÀÁ¹º¼¼¾¿ÀÁÄÃÅÅÆÆÇÇÃÃÄÄÅÆÅÅÂÃÂÃÄÃÅÅÂÁÂÃÂÃÄÄÇÇÇÇÆÇÆÅÅÅÅÅÆÅÅÆÆÆÆÆÆÅÅÃÃÃÃÃÃÃÄÄÅÆÅÃÄÃÃÂÅÄÃÄÂÃÂÂÃÄÃÂÃÂÂÂÄÂÃÃÂÂÂÁÂÁÁ¿¾¼¼»ÁÀÀ¿½½»»ÀÀ¿¾½¼¼ºÁ¿¿¾¼¼»ºº¸¶µ´±°®º·¶µ³±°®¹·¶µ²²°®¹·µ´³°¯®«ª¨¤£ ž›«ª¨¤£¡žœ«ª¨¤£¡žœ«ª¨¥£¡žœ˜–“‘Œ‘˜•“‘Œ˜—“‘ŽŒ™—“‘ŽŒŒ“–˜™œž ’”—˜›žŸ’“–˜™œž‘“•—™›ž¡££¤¤¤¤¤¡¢¢£¤¤¤¤Ÿ¡££¤¤¤¤Ÿ¡¢¢¤¤¤¤¤££¡ žžœ¤£¢¢¡Ÿž¤¤££¢Ÿžž¤¤££¢ Ÿž›˜—•…‡Šœ™˜–”„…‡œš˜—–…ƒ…›™˜–‹€ƒ‹ŒŽ‘’”•—ŠŠŒŽ’’•†‡‹Œ‘’…†ˆŠ‹Ž˜š›œžžŸ¡——™š›ž“•——˜™šœ‘’”•–—˜˜¢¢££££¤£žŸŸ ¡   œžžžž™™š›š›››¤££££¢¢   ¡ ŸŸžžžžœ››š››™™˜˜¡Ÿžœ›™œš™˜——š™˜˜—–•“——–•“’‘‘˜—•”“‘Ž–““‘Ž‹’‘Ž‹‰‡‹‰ˆ‡…‹‹‡†…ƒ€t‰††ƒ‚|ss†…‚‚wrstƒ‚|qqssttvwxyzz{uuvwyyyzttvwxxyytuuuwxyy|}~€€€{|}~€zz||}~~zzz{{|}}‚ƒƒ„„„ƒ€€€€€€€€€~~~}„„„„„„‚ƒ‚€€€€€€}~~~|}}ƒ€€~€~}}{~~||{uvuyuttsutt}|{zyywwzyxrspooqrrsrrrrtttttsttprolmmlmponnnnnmrrppqqpotsssssqrkjkkiihhmmmmlljkoonnnnmmrqqqooonhgggfeddjiihhggfllkkiihhnnmmlkkjccbbba`_fddccbaaggfedccbihhgffed_^^][[ZY`__^]][[aa`__^]\cbba`_^^YWWVUTRRZYXWVUTS[ZYYWWVU]\[ZYXWVPOONLKKIRQPONLKKSRQPONMKUTRRPOOMHGFDDBA?IHGFDCBAKIHGFDDBLKIHGFDC?=<:9876??=<;987@?>=;:98BA?>=;:9TVWXZ[\^TVWXZ[\^TUWWZZ\]TVVWZZ[^_`bcdfhi_`bcdfhi_`bcdfhi_`bcdfgilnqstwyzlnqstwyzlnqstwyzlnqstwyz}‚…‡Š‹}‚…‡ˆ‹}€‚…‡ˆ‹}€‚…‡ˆ‹Ž‘“”—˜›ŒŽ‘“”—˜›Ž‘“•—˜›Ž‘’•—˜šž¡¡¤¥¨©ž ¢¤¥§©œžŸ¢¤¦¦©žŸ¢¤¥¦©ª­­°±³´¶ª¬®°±³³¶ª«®¯°²´µª«®¯°²´µ·¸º»¼½¿À¶¸º»¼¾¾À¶¸º»¼½¿¿¶·¹»»½¿ÀÂÂÃÅÅÇÇÉÁÂÄÄÆÇÈÈÁÂÂÄÆÇÈÈÁÁÂÄÅÇÈÈÉËÌÌÎÍÏÐÊÊËÍÍÍÎÎÈÉËÍÍÍÎÎÈÊÌËÌÎÍÏÏÒÑÒÓÓÓÔÐÑÑÓÒÔÔÔÐÑÑÒÓÓÔÓÐÏÒÒÒÓÔÔÕÔÖÕÕØØØÕÕÕÖÖÖØØÔÔÔÖÖÖÖØÓÕÕÔÖÕÖÕ×ÖÖÖ×ØØ××ØØØ×ØØÖ×ØØØØ××Õ×ØØ×Ø×ÕÕÕÖÔÕÓÓÓÒÕÖÔÔÓÓÓÒÖÖÕÔÔÓÓÐÖÔÕÔÓÓÑÑÏÎÍÌÉÈÆÃÏÎÍÌÉÈÆÅÏÎÍÌÉÈÇÅÏÎÍÌÉÈÇÅÂÀ¾»¸µ³¯ÂÀ½»¹µ²°ÂÀ½»¹¶³°ÂÀ½»¸¶´°­©§£ ™•­ª¦¤¡š—­ª§¤ ž›—®ª¨¤¡žš—’–˜œž¡£¥‘”˜šŸ£¤‘“—˜œž¡£’’•˜š £©ª­¯°²µ¶§©«®°±´µ¥©ª­¯°³´¤§©«®¯±³¸º»»½½¿À¶¸º»¼½½¿¶·¹º»¼½½µ¶·¹»»¼½ÀÁÁÂÂÃÂÂÀÁÁÂÁÂÂÿ¿ÁÁÁÂÂÁ½¿ÀÀÁÁÁÂÄÄÄÄÄÄÂÂÃÂÃÃÃÃÃÂÁÂÂÂÂÂÁÁÂÂÂÂÂÂÁÂÂÃÂÁÂÂÁÀÂÁÂÁÂÁÀÀÂÁÂÁÀÁÀ¿ÂÁÀÀÁ¿À¿ÀÀ½½¼¼»º¿¾¾¼¼¼»¹¿¾¼¼»»º¹¾½½¼¼º¹¹¸·¶µ³±¯®¸¶¶´³°¯®·¶µ´²°¯®·¶µ´±°¯¬«ª¨¦£ žœ¬©¨¦£¡žœ«©¨¦£¡žœ¬©¨¦£¡žœš—”’Œ‹™—•’ŒŠŒ™—•’ŒŠ‹™—”’Ž‹‰’•—˜šœž‘“–˜™œŽ‘’•—˜š’”–˜™œž ¡£££¤¤žŸ¡¢¢¤¤¤Ÿ ¢£££¤ž ¡¢¢¤¤¤¤¤¢¡¡ ž¤¤¤££¡ ž¤¤¤£¢¢ Ÿ¤¤¤¤¢£¡ œš˜—’~€ž›™˜—žœš˜˜„}ž›™˜Œzƒ…†‡‰ŠŒ€‚„…‡ˆŠ‹~€ƒ„††ˆ|~€‚ƒ…†‘‘’“•”–ŒŽ‘’’“Š‹Œ†ˆ‰‹‹ŒŒ———˜˜˜˜˜“”•”••••‘‘‘’’’’’ŽŽ˜˜˜———–••”•”““’’’’‘‘‘ŽŽŽŒŒ•“’‘‘‘‘ŒŒ‹ŽŒ‹‹Šˆ‡‹ŠŠˆ‡†……Œ‹‰ˆ‡…ƒƒ‰‡‡…ƒ‚€u†…„‚€tno‚ƒ{ulnmotoqqrrsnnpprqssonpoqrqsooopoqrqttuuvwwxtttuuvvwsstttuuusrsststtyyzzzzz|xwyyyyzyvwwxxwyytuuuvwvv{{|}}}}}zzzzzzzzxyyxyxxwwtuwxyyy}{{wvvuuywuwxvxxxxyyyyyyzzzzzzz|uuuuuuwwxxxwxxwwzzzzzzzz||{{{{{{vvuuuuuuxxwxxxxxzzzzzyyy||z{{zzzvtttttttvwwwwuuvyyyxxxxvzyzyyyyxssssrrqqtttttssswvuuutttyxxwwvuuoonnnmmlrrppoonntssrrppottttssrqkkihhggfmmljjihgnnmmlkjiqoonmmljddcbaa`_gfeccbaahgfedcbaihhgfdcc^]][ZZYW_^]][[ZYa`_^]\[Zba`_^]\[VUTSRQOOWVVTSRQOYWVUUSRQZYWVUTSRMLKIHGFDOMLKIHGEONMKKIHGPONLKJIGCB@?><;:DCA@?=<;EDCA??=;FECB@?>IGFDCB@?IHGEDBA?TUVXYZ\]TUVWYZ[]TUVWYZ[]SUVWYZ[]^_abcfgi^`abcfgj^_abdegj^_abceghlnortuwzlnortuxzlmortuxykmprsuxz|~€ƒ„†‰Š{~€‚„†ˆŠ{~€ƒ†‡‰{~„…‡ŠŒ‘’“•—™Œ’“–˜™Œ‘“–˜š‹’“–—˜œž £¤¥¨œŸ¡£¤¥¨œž¡£¤¥¨šž¡¢¤¥¦ª«¬¯°°³µ©ª­­°±³³©ª¬®¯°²´©ª«®¯°±´µ·¸º»¼½¿µ¶·º»»½¾µ¶·¹º¼¼¾µ¶·¸»¼¼½ÀÁÁÂÄÅÇÇÀÁÁÃÃÅÅÇ¿ÁÂÂÄÄÆÆ¿ÁÁÂÂÃÅÇÇÉÉËËÍÍÍÇÈÉÉÌÌÌÎÈÈÈÊËÌÌÍÇÇÉÉÊËÍÍÎÏÐÏÑÑÓÓÍÏÎÐÐÒÑÓÎÎÏÐÏÑÑÒÎÍÏÎÐÏÒÑÓÔÔÔÔÕÕÕÒÓÓÔÔÔÕÔÒÒÓÓÔÔÓÔÓÓÒÓÓÔÔÔÕÕÔÔÕÕÕÔÕÕÕÕÕÕÔÔÕÕÔÕÕÕÔÓÓÓÔÔÔÓÔÔÔÓÔÓÒÑÑÏÓÔÔÓÓÑÐÐÔÓÓÒÒÒÐÎÓÓÒÓÑÐÐÏÏÍÌÊÊÈÅÄÎÎÌËÈÈÆÃÎÍÌÊÈÇÆÃÍÍÌÉÈÇÅÄÂÀ½»¸¶´°ÂÀ½»¸¶´°ÂÀ½»¸¶´°ÁÀ½»¹¶³°®«¨¤¢Ÿœ˜®«¨¥¢Ÿœ˜®«¨¥¢žœ˜®ª¨¤¢žœ˜•‘’•—šœ•’Ž‘“—˜›•’Ž’•—š•’Ž‘”–™Ÿ¢£¦¨ª¬®ž £¤§©«­ž¢¤¥¨ª«›ž £¤¦©ª°±³µ¶¶¸¹¯°±´µµ··®¯°²´µ¶·­®°±³´µ¶º»»»¼½¼¾¹º»»¼»¼½·¹¹»»¼¼»··¹¹»º»¼¾¾½½½½½¾¼¼½¾¾¾¾¼¼¼½½½½½½»»»»¼»»»¾¾¾¼½½¼»¼¼¼½¼»¼¼½¼¼»¼»¼»»»¼»¼»º»¼»ººº··¶»ºº¹¸¸¶¶ºº¹¹¸¶¶¶º¹¹¸··µµ¶´´²°°­­µµ³±°¯®«µ´³²°¯®«µ´²°¯¯­«ª©¦¥£¡žª©§¤£¡žª©§¤£¡žª¨§¤£¡ž™˜–’‘‹ˆš˜–’‘‹‰š˜–’‘ŽŒ‰š˜–”‘ŽŒŠ†Œ’”–˜†‰Œ‘“–—†‡Œ’•—†…‹‘“–™œžŸ¡¢¢™šž ¡¢˜šœžŸ ¡—™›ž ¡£¤¤¤¤£££¢££¤¤£¢££¢£¤£££¢¡¢¢££¢££¡ŸŸžœš—¡¡Ÿžž››¢  Ÿœš¡¢ žžœ›qstuvwyyxpqssttvŠ‰‡†‡‡†˜˜–•’‘Žzz{}|~~wxxyzzz{…„……„ƒ‚Œ‹Š‡†…„€€€}|}}y|wx€~{zzyw€~}{zyx{}yrsqqpvtttssqrwuustrrrwvtttssqppooomnnopnoomnnqpnoomnnqpnonnnnnnnmnnnmnmnmllllnmlmmlmmmlmmllkkmnnnnnnnlllllllqlkkkmswxkknvxxyzmppxyyzzsyzyz{{}yzz{||~~z{}}~€{{}}~~}~€€€€€€ƒ€‚‚„„„€€€‚‚ƒ‚ƒƒ„ƒ„„ƒ…„……„………†††…‚ƒƒƒƒƒƒƒ„„ƒƒƒƒƒƒ…………………„………†††††‚‚ƒ‚‚‚„„ƒƒ„ƒƒ„„……ƒƒ„„†…„…„…ƒƒ€€€€€‚‚€€ƒ‚‚€€ƒƒ‚€~~}}€€~€€€€€€€€€€~~}|{||z{}}~}|{||~~|~~}{{~|~}}{zzyzyxywz{zzzzyy|{{{zyyy{|{{zzyywvuuttsrxwwuuttsxywwvutszyywwvutqoonmljirqoonmljsrqoommlssrqpnnlhgfdcba`iggedcbajhgfedbakjhgfdcb_^][ZYXV_^^\[ZXWa_^][ZYXa`^]\[ZXVTRQPOMLVUSRPONLVVTRQPOMWVUSRPOMJIGFDCA@KIHFECBAKKIGFDCALKIHFECBSUVWYZ[]SUVWYZ[]STUWYY[]STUWXZ[\^_abcegh^_abcegh]_`bcegh^_`acdfhjmorsvxykmnpsuxykmnqstvykmnqstwy{~€„†‡Š|~„…‡Š{}„…‡‰z|‚…‡ˆŒ‘”–—˜‹Ž‘’”—˜‹ŒŽ‘’•—˜‹Œ‘’”–˜›žŸ¢¤¥¦šœžŸ¢£¥¦›œŸ¢£¤§™œž  £¤¥©ª«®¯°±³©©¬­¯°²²§ªª­¯°°³¨©«­­°±²µµ·¹¹»¼¾´¶¶¸º»¼¼´¶¶·º»»¼´µ¶·¹º¼¼¿¿ÁÁÂÄÆƾÀÁÂÂÃÄƾ¿ÁÂÂÃÄŽ¿ÁÁÂÂÄÆÇÇÈÉÉÌËÌÆÈÈÈÊËËÍÇÇÇÉÊÉÌÌÆÇÈÈÈÊÊËÍÎÎÎÏÐÐÒÍÎÍÏÎÐÏÑÌÍÎÎÏÎÐÏÍÍÎÍÎÎÏÐÑÓÓÒÓÔÔÔÒÑÓÓÒÓÓÔÑÒÑÓÒÓÒÓÏÑÒÑÒÓÒÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓÓÓÓÓÓÒÓÓÓÓÓÓÓÓÒÓÒÓÑÑÐÏÎÒÓÑÒÐÏÏÍÓÑÒÐÐÎÎÎÑÒÐÏÎÎÎÍÎÍËÉÈÇÅÂÍÌÊÈÈÆÄÂÍËÉÈÇÆÃÂÌËÉÈÇÄÃÁÁ¾¼»·µ²°Á¿¼º·µ³°À½¼º·µ±¯À½»¹¶´±¯®ª¨¤¢žœ˜­ª¨¤¢ž›˜­ª¦¤¡žš˜¬©§¤¡›—•’Œ’•˜”’Œ‘”—•‘Ž‘“•”‘ŽŒŒ’”šž¢£¥¨ª˜œž £¤§©˜šž¡£¥¨—˜œž ¢¤¦«­¯°±³´µª¬®¯°±´µ©«¬®°°²³¨ª«®¯°±²¶¶¸¸¹º»ºµ¶¶¸¸¹¹ºµµ¶··¸¸º³µµ¶¶¶¸·»»¼¼¼¼¼»»ºº»»»»»¹ºº»»»»»¹¹º¹¹¹¹¹¼¼»»ºº»¹ºººº»¹¹º»»¹º¹º¹¸¹¹ºº¸¸·¸¹¹¸··¶¶µ¹¸··¶µµµ¸··¶µ¶´´··¶µ¶µµ³´³±°°®¬¬´²²°¯®­ª´²°¯¯®¬«²±°°®®«ªª©¦¤£¡žª§§¤£¡žª¨¥¤£¡ž©¨¥¤¢ ž›˜–”‘ŒŠ›˜–”‘ŒŠ›˜–“‘ŽŒŠ›˜–“‘ŒŠ†„ŠŒŽ‘’”ˆ„‡‹’“ˆ…„ŠŒ‘’‡…ƒ‰‹’—˜šœžŸ –—™›žž ”—˜™œžž“–—™›œž¡¢¢£££££ ¡¢£££££Ÿ ¡¡¢£¢¡žŸ ¢¡¡¡¢¡¢Ÿžžš¡¢Ÿžžž›¢¡ žžž›¡Ÿ žžžœœš˜—•“’‘Ž™˜—–“’‘™˜—–”’‘™˜—–”’‘ŒŠ‰†…„‚Œ‹ˆ‡†…‚Œ‹‰‡†…ƒŒ‹Š‡†…ƒ€}{zzy~|zyx€~|zyy€~{{zxwutttssqxwvtsssqxvvttrqrxvtttrqqqpnonnnmppnnmnmmooommmllpnnnmllkmmlkkljmmkkkjltvkljotxwylnuvxxyzpwyxyz{{xyyz{||~yz{|}~{|}~€|~~€€€€ƒ„€€‚ƒ„„…ƒƒ„……††‚‚„„………†„………†…††…†††‡†ˆ‡††‡‡ˆˆˆˆ†…††††‡‡‡†††ˆˆˆˆˆˆ‡‡‡‡‡‡ˆŠŠŠŠŠ‰‰‡‡‡†††…†‡††‡‡‡†…ˆˆˆ‡‡‡††‡ˆ‡ˆ†‡‡††…†…………‚†††…„…„„†††…„……ƒ†††………ƒ„„„ƒ€„„‚€ƒƒƒ€€ƒ‚€€€€€€€~€€€€~€€€€~€€~~~}~}}~~}~~~~~}~~~~}}}~~}~|{||{{zzy||{|{{zz|||||z{z{||{}z{{zzyywwvuyzzxywwvzzyyxxxv{yzzyywwttsrqonmtttsrpnmuussrponvtttsqpnlkihfedbmlihgfdcmljhhfdcmmjjhgeca`_^][ZYba`^^\[Ybb`_]\[Zca`_^][ZWVUSRQOOXWUTSQPNYWVUSRPPYWVUSRQOLKJHGEDBMKKIGEDBMLJIGGDDNLKIHFECSTVWXZ[\STVWXZ[\STVWXY[\STVVWZZ[^_`bcdfh^_`bbdfh]_`acdfg^^_bbdfhkmnqstvyiknpstwyilnoqtuxilnorsuxz}€ƒ…†‰z}€‚…†‰z|~€ƒ…†ˆz{~€„†‡‹ŒŽ‘’•–˜‹Œ’“–˜ŠŒ‘“–—Š‹’“–—™œž¡£¤¥™œž ££¥™šž¡¢¤¥˜›žŸ¢£¥¨©ª¬®¯°±§©ª«®¯°±¦©ª«­¯°²§¨ª«¬¯°°´µ¶¸¸º»¼³µ¶¶¸º»¼²µ¶¶¸ºº¼³´µ¶·¹»¼¾¾ÀÁÁÃÃļ¾¿ÀÂÂÃĽ½ÀÁÁÂÂļ½¾ÀÁÁÂÃÆÆÈÈÉÉÉÌÅÇÇÇÈÈÊËÅÅÆÈÈÉÊÉÅÅÇÇÇÈÈÊËÌÍÍÍÎÏÏËÍÌÍÎÍÏÏÌËÍÍÎÎÎÏÊËÌÌÍÎÎÍÐÏÑÒÑÑÑÓÏÐÏÐÑÒÒÑÎÎÐÐÏÏÑÐÎÏÏÎÐÐÐÐÓÓÓÓÒÑÑÑÑÑÑÑÑÒÑÐÒÒÒÐÑÏÏÐÏÏÏÐÐÏÏÎÑÐÐÎÎÍÍÌÐÐÎÎÍÍÍÌÏÎÎÍÍÍËÊÎÎÎÍÍËÊÉËÉÈÇÆÄÂÁÊÈÇÇÅÃÂÀÉÈÇÆÄÂÁ¿ÈÇÆÅÃÁÀ¾¾¼»¹¶´±®¾¼º·µ²°®½»¹¶´±¯­¼»¸¶´°¯««©¥£Ÿ™—«¨¥£Ÿ™—ª¨¤¢žœ˜–©¦¤¡žš˜”“‘Œ‹‘’“‹‹’’Œ‰ŠŒŽ‘’ŽŒˆ‰‹Œ–˜šž¡£¥”—™œž ¢¤“–˜›Ÿ¡£’•—™œž ¢§©ª¬®¯°±¦¨©«­®¯°¥§©ª«­¯°¤¥¨©ª¬®¯²³µµµ¶··±³³µµ¶¶¶°²³³µµ¶µ°°²²´´´µ¸¸·¹¹¹¹¹¶¶¸¸¸¸¸¸¶¶·¶¶¶¶¶¶µµ¶¶¶··¹¹¸·¸¸·¶¸¸¸¸¶¶·¶¶¶¶¶·¶¶µ·¶¶¶µµ¶¶·¶µµµµ³³¶¶¶µ´´³²µ¶µ´´³²²µ´´´³³²±²°°¯¯­«ª±±¯¯­­«ª°°°®®¬ªª°¯¯¯­¬ªª©¨¥¤£¡žœ©§¥£¢¡ž¨¦¦¤¡Ÿž©§¤¤¢Ÿžœ›˜–“‘ŒŠ›˜–“‘ŽŒŠ›˜–“‘ŽŒŠ™˜–“‘ŽŒ‰‡…‚‡‹Œ‘‡…ƒ„‰‹‡…‚ˆ‹Œ‡…‚€†‰‹’”—˜™›œž’“–—˜šœ‘’”–—™š›‘“•—˜™šžž Ÿ¡¡¢¡žžž  ŸŸ žžžžžžž›žžžžžŸ ŸŸœš ŸŸžžœ›žŸžž›šžž›š™™˜—–”’‘™˜—–“’‘™——•“’‘˜—–•“‘‘ŽŽŒ‹Š‡†…ƒŒ‹Š‡†…ƒŒ‹‰‡…„‚‹‹‰††„ƒ€~|zzy€~{zzy~}{zyx€~}{yyxwvtsssqowuttsrqpwutsrqpnuttsrpononmmllkrommlnquunmortuvxostuvwxyuwwxyz{{wxyzz{|~yyz{}~z{|}~€€}~€ƒ€ƒ„„€€ƒ„„……‚ƒ„……††„„………†††……†††ˆˆˆ†††‡ˆˆ‰‰†‡ˆˆ‰‰Š‹‡ˆˆˆ‰Š‰‰ˆŠ‰Š‰‹‹‹ŠŠ‹Š‹‹‹‹ŠŠŠŠ‹‹‹‹‰‰Š‰‰Š‰‰‹‹‹‹ŠˆŠŠ‹‹‹‹‹ˆŠ‰‹‹‹‹‹‰Š‰‰ˆ‡ˆ†‡‡†Š‡‡ˆ†††…‰‡‰†††……‡ˆ‡‡†…†…†……„…ƒ„ƒ……„…ƒ„‚‚…„„ƒƒ‚‚€…„ƒ‚‚€‚€€€€€€€€€€~~€~~}}~~}~}~~~}~~}~}~|}{{|}|||{|{z~~~~}}{|}}{{{{{{||||||||zzzzzz{{||{||z{{||}|{{{{||zz{{{{{{z{{{{{{yzzyyxxzzzzzxyx{yzzyyyxzzzzyywxuuttrrpouvussrqouvussqqpuvussqqpmmkihgfdnmljhgfdnmljhgfdnmlkihfecaa_^][Zcba`^^\[cba__^\[cbb`_^\[ZXVVSRQOZXVUTSQOZXWVTSQPZXWVTSQPOLKJHGECNMKJHGECNMKKHHEDNMKKHHEDRSVVXYZ\RTUVWYZ[RSUVWYZ[RSUVWYY[]^`abcfg]^_abceg]^_abceg]]_abcegjlmortuxhjmoqsvxhkmnpstvhjmnpstwz{~€„†‡y{~„…ˆyz|€‚…†yz}€ƒ…†ŠŒ‘’”—Š‹ŒŽ‘’”—ˆ‹Œ‘’•–ˆ‹Œ‘’“–˜›œŸ¢£¤˜™œžŸ £¤˜™œž ££˜ššž¡¢¤§¨©«­­¯°¥¨©ª«®¯°¥§©ª«­¯°¤§©©«¬¯¯²´µ¶·¹¹»±³µ¶¶¸º»²²´¶¶·¹»°²´µ¶·¸º¼¼¾¿À»½¾¿ÁÁÁü¼½¿ÀÁ»¼¼¾¿ÁÁÁÄÆÆÇÈÇÉÉÃÄÅÇÇÈÈÉÃÄÆÆÆÈÇÈÃÄÄÅÇÇÈÇÊËËÌÌÍÎÎÉÉËËÌÌÍÍÈÊÉËËÌÍÌÉÈÊÉËËËÍÍÎÏÎÏÎÎÏÍÎÍÎÎÏÏÏÍÎÍÎÎÍÍÍÌÌÍÍÎÎÎÎÐÐÏÎÎÏÎÎÏÏÏÎÎÎÍÎÍÍÍÍÎÎÍÌÎÎÍÍÍÍÍÌÍÎÍÍËÊÊÈÍÌÌËÊÉÈÈÍËËÊÉÈÈÇËÊÊÈÈÇÇÅÈÇÅÃÂÁ¿½ÇÆÃÂÁÀ½¼ÅÄÂÁÀ¾¼»ÄÂÂÀ¿½»¹»¹·µ²°®«º¸¶´±¯¬ª¹·µ²°®ª©·µ³°¯¬ª§¨¥£Ÿš—”¨¤¢žœ™—“¦£¡š˜–’¥£Ÿ™—”‘‘Ž‹ˆ‡‰ŒŽ‘‹‡…‰‹ŒŠ†„ˆ‰ŒŒˆ†ƒ„ˆ‹‘“–˜›Ÿ¡’•—™œžŸ‘“–˜›ž‘’•—™œž£¤¦¨ª«¬®¢¤¥§©ª«­ £¤¦¨©ª¬Ÿ¢£¥§¨ªª¯¯°²²³´µ®¯°±±²³³­®¯¯°±²²«­¯¯¯°°²µµ¶µ¶µµµ´µ´µµ¶¶¶´³´µµ´´´±³´³³³³´µµ¶¶µ¶µµ¶¶¶µµ´µµ´´´µµµ³³´´³³³³´³´µ´³³²±±´³´²²±±°´³²²±±°¯²±²±±°¯°°°®®­«ª©°¯¯­¬ªª©¯®®­««ª©¯®­««ª©©§§¥£¢Ÿžœ¨¦¤£¢Ÿžœ§¥¤£¢Ÿž›§¥¤£  žœ™˜–“‘ŽŒ‹™˜–“‘Œ‹™˜–“‘Œ‹™˜–“‘Œ‹‡…ƒ€ƒ‡ŠŒ‡†ƒ€†‰‹ˆ†„€†‡‰ˆ†„€‚†ˆŽ’“•—˜™ŒŽ‘’”•—˜‹‘’”•—‹ŒŽ‘’”–šœœžžž™™›œœœ˜˜™šš›œœ——˜˜š™ššž››š˜›œ›š™˜››šš™˜˜—š™™˜˜——–——–“’‘Ž—–•“’‘–•“’‘ŽŒ•”’‘ŒŒ‹Š‡†…„Œ‹‰‡†„‚‹Šˆ†…„€Š‰‡†„ƒ€€~{zyxv€~}{yywv~{zyxvt~|zyxwututsrpoortsrqoqttssqqssturprsttvwttuwxyzzuvwxyz{|wxyzz{}~xyz{|~{|~€€‚~~€€ƒ„€€‚„„…€€ƒ„………ƒ„………††‡………†‡‡ˆˆ††‡‡‡ˆŠ‰††ˆˆ‰‰Š‹ˆ‰‰ŠŠ‹Š‹‰Š‹ŠŠ‹‹ŒŠŠŠ‹Œ‹ŒŒŠ‹Œ‹ŒŒŒŒ‹‹ŒŒ‹ŒŒ‹ŒŒŒŒŒŒŒ‹ŒŒŒŒŒ‹‹ŠŒŒŒŒ‹‹Š‹‹‹‹‹‰‰‰‡‹‹‹‰‰‰‡ˆ‹‹‰‰‰‡ˆ†‹‰Šˆˆ‡‡†ˆ‡‡†…†……†‡††…„„ƒ†…†……ƒƒ‚……„„ƒ‚€ƒƒ‚€€€ƒ€€€€€€~}€€~}|{~~~}}{|~~||{{z{||{zzzzy{zzyz{zt{{z{{{zzzzzz|zsnzzqj^\ZZia^^^\\[{}|trnkieZXUUSSRYYXVVTSRYYXWVTSRikmu|{zzQONKO^zyPPNMLKJtQOOMLJIOyzyyxywxzyyxyxwwyyxyywxu{yyywxwvuutssqqpvtttsrppvtttrrqouusssqoonmkkihfenmlkihfenmljihfdmmljhgfdcbb`_^\[cbb`_^\[cbb`_^\[cba`_]\ZYYWVTSQPYYWVTSQPZXWVTRQPZXWVTSQPNMKKHHEDNMKKHHEDNMKKHHECNMKJHGECRSUUWXZ[RSTVWXZZQRTVWXY[QSTVVWYZ\^_`bcdf\^^`bbdf\^^`bbdf[]^_abcfhjmnqstwhilnoqtuhilnorsugjlmorsuyz}€ƒ…†xz|~€ƒ†xy{~„†xy{~‚„…‰ŠŒ‘“–‡Š‹‘“”‡Š‹‘’”‡ˆ‹Œ‘’•—˜›žŸ¢£—˜›œŸ £—˜™œž¡¢–—™œž ¢¤¦§ª«­­¯¤¥¨©ª«®¯¤¥§©ª«­¯¤¤§©©«­®°±´µµ¶¸º°±³µ¶¶·¹¯°³´µ¶·¹°°±´µµ·¸»»½½¿¿Á»»¼½¾ÀÁÁº»»½¾¿ÀÁºº¼¼½¾ÀÁÂÂÄÅÆÆÇÈÁÃÃÄÅÆÆÇÂÂÂÄÅÅÆÆÁÁÂÃÄÅÅÇÈÉÈÊÉËÌËÈÈÉÈÊÊÉÊÇÈÇÈÉÈÉÊÆÇÈÇÈÉÉÈËÍÍÌÌÌÌÌÌËËÌËËËËÉÊËÊÊËËËÉÉÉÊÊÊÊÉÌÌÍÍËÌËËÌÌËÌÊÊÊÉËËÉÉÉÈÈÈÉÊÈÉÈÈÈÇÉÉÈÈÇÆÅÄÉÈÈÇÆÅÃÂÈÇÇÆÄÃÂÁÇÆÅÃÃÂÁÀÂÁÀ¿½¼º¸ÁÀ¿½¼»¸¶À¿½¼º¸·µ¾½¼º¹·µ³¶µ²¯®ª©¦µ³°¯¬ª§¥³°¯­ª©¦£±¯­ª©¥¤¡£¡ž›™–’‘£Ÿš—”’ ž›™–’‘žš—”’ŒŠ‡…‡ŠŒ‰†ƒ~†‰‹‡…‚€}„‡‰‡„{†Œ‘“–˜š‹Ž‘’•—™›‹Œ‘“–˜š‰‹’•—˜ž ¢¤¥§©ªŸ¡£¤¦¨©œž ¢£¥¦¨›Ÿ £¤¥§ª¬®¯¯¯°±ª«¬®¯¯°°©ª«¬­®¯°¨©ª«¬­®®±²±³²´´´°°±²²±±±¯°±°°±²²¯°¯°°±±±´´´´´³±±±±±±±²²²±±²²±°°±±±±±±±°°²²°±°¯°¯°±°°°°¯¯±°¯¯°¯®®¯°°¯®¯­­¯­­¬«©©§®­¬«ªª¨¨®¬««©©©§¬¬ªªª©¨¦§¥£¢ Ÿžœ¦¥££ Ÿœ¥¤£¡¡žœ¦¤£¢ žœ™˜–“’Œ‹™˜–“’Œ‹™˜–“’Œ‹™˜–“‘Œ‹‰†„€…†‰†„‚~ƒ…‰†„‚}„‰†„|‚‰‹ŒŽ‘’“†‰‹ŒŽ‘’†‡‰‹ŒŽ‘…†ˆ‰‹ŒŽ•–—˜˜˜˜˜“”––————’’“””–––‘’’““““˜˜˜˜——–•————–•”“––”•”“’’“““’’’‘“’‘Œ‹’‘Œ‹Š‘Œ‹ŠˆŽŒ‹‰‡†‰‡†…ƒ€‡†…ƒ‚€}†…ƒ‚€~|…ƒ‚€}|z}{zywurp{zywupqqzyxqnprsyrnoqrstrrstuvxysttvwxyzttvwyyz{uvwyzz|}zz|}~€€{|}~€|~€ƒ~€€‚„„‚„„…††‡ƒƒ………††ˆ„……††‡‡ˆ…††‡‡ˆ‰‰‡ˆˆ‰Š‹‹‹ˆ‰‰ŠŠŠ‹ŒŠ‰‹‹‹‹‹Œ‰‹‹‹ŒŒŒŒŒ‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹ŒŒŒŒŒŒŒ‹ŒŒŒŒ‹ŠŠŠŒ‹‹‹‹‹Š‰Œ‹Š‹Š‰‰ˆŠŠ‹‰Šˆ‡‡‰‰ˆˆ††††ˆˆ‡‡†………ˆ††………„ƒ‡††…„„‚…„„ƒ€„ƒ€€‚€€~}€€€~}|{~}|{zz~}|{zzyy|{zzzywszzyzwnhfzyzztfba{vjdbcbbfedddbbagfedcccaa__^^]\[a`__]]\[b``^]]\[b``_]]\[YYXWUTSRYYXVVTSQYYWVUSRQYYWVUTRQPONMKKIFPPMLKJHFPOMLKIHJONMLJIH]uyxwxwuvuwwxwuwt{xxvuvuuwvuvvuuttttssrooustrrponttssqponstrrqpomnmkihgfdnmjihgfdmkkhgfedmljhhfdccba`^^\[caa_^][Zca`_^][Zbb`_]][ZYXWUTRQOZXVUSRQOYWVUSRPOYWVUSRPOOMKIHFECNLKIHGDCMLJIGGDCMLKHGEDBQRSUVXYZQRSUVWYZPRSUVWYYQRSTUWXZ[]^_abce[]^_abce[\]_`acd[\^^`bbdghjmnpstghjmnpstfhjlnprtfhilnortvyz|€‚…wyz|€‚…vxz|~€‚ƒuxz{~„†‰‹Œ’“†‰ŠŒ’“†‡ŠŒ‘’†‡Š‹Ž‘’–—™šžŸ¢•—˜›œŸ •—˜™œž¡•–—™œž £¤¦¨©ª¬®£¤¥¨©ª«­££¥¦¨©«¬¢£¤§¨ªª¬¯°±³µ¶¶·¯¯°²´µ¶¶®°°±³µ¶¶®¯°±²´µ¶¹º»»½¾¿À¸ºº¼¼½½¿¸¹º»»½½¾·¸ºº¼¼¼¾ÀÂÁÃÃÄÅÅÀÁÂÂÃÃÄÅ¿ÁÁÂÂÃÃÄ¿¿ÁÁÂÂÃÂÆÆÇÈÈÇÈÈÅÆÇÆÇÈÈÈÄÅÅÅÇÆÆÇÄÄÅÅÅÅÅÅÉÉÉÈÈÈÉÉÇÇÇÇÇÇÇÈÇÇÇÇÇÇÇÆÇÇÇÇÅÆÆÆÈÈÈÈÇÇÇÆÈÇÇÇÆÆÅÄÇÆÆÅÄÃÃÂÅÅÄÃÃÂÂÁÅÄÃÂÁÁÀ¾ÃÂÂÁÀ¿½¼ÂÁÀ¿¾½¼»ÁÀ¿½¼»»¹½»»¸·µ³±»º¸¶µ³±°¹¸¶µ³±°®·¶´³°°­¬°­«©§¥£ ®¬ª§¤£Ÿž¬©§¥£¢Ÿ©¨¦¤¡žœš›˜•’‘‹œ˜—”‘‹‰š—•’Œ‹ˆ—•’‘‹‰†ˆ…ƒ€}{y††…€|xc…‚€~qbas„}hccch‡Š‘“–˜‡‰ŒŽ’”—†ˆŠ‘“–‡‡Š‹Ž’”šœžŸ¢£¤¥™›ž ¢¤¤˜šœžŸ¡£¤—˜šžŸ¢£¨©ªª«¬­®¦§©ªª«¬­¥¦¨©ªªª¬¤¥¦¨©ªªª¯¯¯°°¯¯°­®¯¯¯°°¯¬®­®¯®®¯««­®­­¯¯°°°°¯¯°°°°°°¯°°¯¯¯¯¯¯®®®¯¯¯¯¯¯®­°¯¯®¯­®¬¯®¯®­®¬¬¯®­­­¬¬«­­®¬«¬ª«¬««©©©¨¥««ªª©¨§¦«ªª©©§¦¥ªª©¨¨§¦¥¤££¢Ÿžš¤¤¢¡Ÿž›¤£¢ Ÿ›££¢¡Ÿžšš˜–“‘Œ‹˜—–“‘Œ‹™—–”‘Œ‹˜—–“‘Œ‹ˆ†„}}€‰†„|z‰†„|z}‰†„|zz‚„†ˆ‰‹Œ‚„†‡‰Š‹‚…†‡ˆŠ}€‚„…†‡Ž‘‘‘’’ŒŽŽ‘‹‹ŒŒ‰ŠŠ‹‹‹ŒŒ’’’‘‘‘ŽŽŒŒŒ‹‹ŒŒŒ‹‹ŠŠ‰Œ‹Š‰‡†…Œ‹Šˆ††…ƒŠˆ‡†…„ƒ‡††…ƒ‚€ƒ‚€}|{u€}|xnm€~zqmnn~|slmnopnopqrstunpqsstvwprsttvwxqsttuwxywxyzz{}~xyz{|}~yz{|~€z{|}€€€‚‚ƒ……€€‚ƒƒ………ƒƒ………†ƒƒ………†‡††‡‡‡‰‰Š††ˆ‡‰‰‰Š†ˆ‡‰Š‰‹‹‡‡‰Šˆ‹‹‹‹‹Š‹ŒŒŒŒ‹Š‹‹ŒŒŒŒ‹ŠŒŒŒŒŒŒ‹‹‹‹‹‹‹ŠŒŒŒŒŒ‹‹ŠŒ‹Œ‹‹Š‹‰‹‹ŠŠ‹‰‰‰ŠŠ‹Š‰‰ˆˆ‹Š‰‰ˆ‡‡†‰‰ˆˆ††……ˆˆ‡†††…„‡†††…„„ƒ………„ƒ€…„ƒ‚€„‚€€~€€~|{€~}|{zz~~}{zzyz}{zzyyui{zyyxoklzyujhgggrlhiihghiijiiiihlkkijihhfgeeddbbgfffddcbgggfeccbghffeccbaa`_]]\[ba`_]]\Zba`_]][Zaa`_^\[ZZXWVUSRPZXWUTSRPZXWUTSQPYXVVTRQPOOMKKIGyONLKJGeuOMLKIXvuNMLJOwuuuvvvtttsvttuttssuuuutstsuttttttssssqppnnsrrqpnnmrsqponnlsqqpnnmlmkihgfdclkiggedclihgfecbkihgfdcbba__]\[Zaa_^][ZZb`_^][ZYa`^]\[YXXWVTSQPNXVUSRQONWVUSRPOMWUTSQPNMMKJHGECCLKIHFDCALJIGFDBAKJHGECC@PRSTVVXYPQSTVVWYPQRSUVWYOQRSUVWY[\^^`bbdZ\]^`abdZ[]^_abcZ[]]_`acfgilmorseghjmnpseghkmnqsdfhjlnpruxy{~ƒtvyz|€ƒtvyz}€‚tvxz{~€…†ˆ‹Œ‘’…†‰‹Œ’„†‡ŠŒ‘„†‡Š‹ŒŽ‘“–—™šžŸ“•—˜šœžŸ’•—˜™œž’”–˜™›ž¢£¤¥¨©ª« £¤¥§©©« ¢¤¤§¨©ªŸ¢£¤¥¨©ª­¯¯°²´µ¶­®¯°±³´µ«®¯¯°²´µ«¬®¯°±³´¶¸¹º»¼¼½¶·¸¹»»»¼¶¶·¹¹»»¼µ¶¶·¹º»¼¾¿¿ÁÁÂÁ½¾¿¿ÁÁÂÁ½½¾¿¿ÀÀÁ¼½½¾¾¿¿ÀÂÃÃÄÃÅÅÅÂÂÃÂÃÄÃÃÂÂÁÂÂÂÂÂÁÁÁÁÂÂÂÂÅÆÄÄÅÅÄÃÃÃÃÃÄÂÃÂÂÂÂÂÂÁÂÁÂÂÁÁÁÀÀÀÃÃÂÂÂÁÁÀÂÁÁÁÀÀ¿½ÁÁÀ¿¾½¼¼¿¿½½¼¼»º¿½¼¼»º¸·¼¼»º¸·¶µ»º¹¸¶µµ³¹¸·¶µ³²°µ´²±¯­«ª³²°¯­ª©§°°¯««©§¤¯­¬ª©§¥£§¥¤¡ž™˜¥¤¡ž›˜—£¡žœ™—”¢žœ›˜—”’—’‘‹‰†…”’Œ‹ˆ†€’Œ‹ˆ†xgŒ‹ˆ„oii‚ueddccblfffeedbhhggffedhhhhgffeƒ†ˆ‹‘“{…†ŠŒŽ’p…†ˆ‹‘hƒ…†ŠŒŽ–˜™œž ¢•—˜šœžŸ¡“–—™›žŸ’”–˜šœž£¤¦§¨©ªª£¤¤¦§¨©ª¢££¥¥§¨¨ ¢£¤¥¥§§««¬«­­®­©ªª«¬¬«­©©ªªªª¬«©©ª©ªª««­­­­­­®®­­­­­­««¬¬¬¬¬¬«¬ªªªªªª«ª¬¬«¬«ª«ª¬¬¬ª«ªªªªª««ª©©©«ªª©ªª©¨ªª¨¨§¦¥¤ª©©§§¦¤¤¨©§§¦¥¤¤©§¨¥¥¥¤£¤¢¢ ž›š££¡Ÿžœ™£¢¡Ÿžœ™£¡ žžœ›™˜—”“‘Œ‹˜—”“‘‹˜—•“‘Ž‹˜–•’‘Ž‹‰†„}zz‰†„€}zy‰†„€~zy‰†…€~{y|}€‚ƒ„…z{}€€‚„xzz}~€wxyz|}~†‡ˆˆŠŠŠ‰……††‡‡‡‡‚ƒ„…………†€‚ƒ‚ƒƒŠŠŠ‰‰‡‡†‡‡‡†††…„…………„„ƒ‚ƒ‚ƒƒ€€……„ƒ€}„ƒ€{n€~rjj~~wjhjlwmlmnopqjlmnopqskmnnprstmnnprsttsttuwxyzttuwxyz{tuwxyz{|vwxyz{|~{|}€|}€€ƒ~€€‚‚ƒ‚ƒ„ƒƒ……††‡‡ƒ………†‡†ˆ……†…†‡ˆ‡„†††††ˆ‡ˆˆŠ‰ŠŠ‹‹ˆˆŠ‰ŠŠ‹‹‡ŠŠ‰ˆŠ‹‹‡ŠŠ‰‰‰‰‰‹‹‹‹‹‹Š‹‹‹‹Š‹Š‰‰‹‹‰Š‰‰‰‰‰‰Š‰‰‡ˆ‡ŠŠ‰‰ˆˆ‡†Šˆˆˆ‡†††ˆ‡‡†††……††††……„ƒ††……„‚……„ƒ€€„ƒ‚€€~‚€€~~|€~}{{z~}|{zyy}|{zzyxx{zzyxxvmyyyslkkkxwnlllllrlmmnnnmnnmnnnnnkkkljijhmmmkljjhmlmmklihmnlmklihhggfeccbhhgfeccbhhffeccahhgedccab`_^^\[Yb`_^][[Za`_]][ZYa`^^\[ZYYWVUSRQOXWUTSRPOXVVTSQPNWVUSRQONOMKOssssMLOrstttMOrrststUsrsrrssssttstsrtttssrrrtttsrrrqssrsrrqqrrponnmlqppommlkqpnnnlljponmmlkijhhfedcaihgfecbbhhgedcaahgfecbb`a_^][ZYX`_]\[ZYW_^]\ZZXV_^][ZYWVVUSRQONLVUSQPOMKVTRQOOLKUSRPOMLJKIHFDCA@JIGEDBA?IHGECB@>IGFDBA?>OPRSUUWXOPQSTVVXOPQRTVVWOPQRSUVWY[\^_`bbY[\^^`bbYZ[]^_abYZ[]^_abdfgilnordfgilmoqceghjmnqceghkmnqtuxz{~suwy{|€stwyz}€rtvxz{~€ƒ…†ˆ‹Œƒ…†‰ŠŒ‚„†‡ŠŒ„…‡‰‹Œ’“–—˜›œ‘“”—˜™œ‘’•–—™›‘’“–—˜›œŸ £¤¥¦©ªž ¢£¤¦¨©žŸ¢£¤¥§©Ÿ ¢¤¤¦¨ª¬®¯°°²´ª«­¯¯°±³©ª¬­¯¯°±©ª«­®¯°±µ¶¶·¸¹º»´µ¶¶·¸¹º³´µµ¶·¸¹²´µµµ¶·¸¼»¼¼½¾¾Àº»»¼½¼½¾º»»¼»¼¼¼¹¹ºº»»¼»¿À¿ÁÀÁÁÁ¾¾¿¾ÀÀÀ¾¼¾½½½½½½¼¼¼¼¼¼¼¼ÁÀ¿ÀÀ¿¿½¾¿¿¾½½¼¼¾¼½¼¼¼»»»¼»»»ºº¸½¼¼»»º¹¸¼»»º¸¸·¶º¹¹·¶¶µ´¸·¶¶µ´²±·¶µ´²°°¯µ´³±°¯­«²±°¯®¬«ª°¯¯­«ª¨§­ªª¨¦¤£Ÿª©§¤¤¢ ¨¦¤£¡žž›¤¤£ žœœ˜ž™˜—”’š——”’Œš˜•’’ŒŒ—–’‘ˆtŒ‹Š{jkjkŒ‡qlmmmk~mnmmnnmnpppoonnjiihhhgflkkiihhgmmlkjihgmnmmkkjhd€„†ˆ‹ew‚…‡ŠŒŽgn‚„†‰‹hh€ƒ…‡ŠŒ‘“•—™šž‘’”–˜™›‘“•—˜šœŽ’”–—™›Ÿ ¢£¤¥¥§žŸ¡¢£¤¤¦ž ¡££¤¤œžž ¢££¤§©©©ª©©ª¦§¨©©©ªª¦¦§§¨©¨©¥¥¦¦¨§§©ªªª«ªªªªªª©©ªªªª©©ªªª©©©©¨¨¨¨¨©©©©ªª©©¨©ªª©©¨©§§©¨¨©¨§¨¦©¨¨§¨§¦¦§¨¦¦¤¤¤£§¥¦¤¤£££¥¦¤¤£¤£¢¥¤¤£¤££¡¢¡Ÿžžš™¢ Ÿž››™¡ Ÿœš˜ Ÿžž›™˜˜—”’‘ŽŒ‹˜••’‘Œ‹—–“’‘Œ‹—–“’‘Œ‹‰†…€~|y‰†„‚€~|y‰†…‚€~|y‰†…‚€~{yvvwyz{|}vtuwxyzzwsstuvxywrqrstuv~€€€€€{}|~~~yzz|{{{{wxyyyyzz€€€€~~~~~|}{|{{{{zzvhyyyyxmdf}zmghilmrgghjklmfghiklmngghjkmmnnnpqrttvnpqrstuvoqrstuvwprsstuwywxyzz{}~xyyz|}~yzz{|}yzz|~~€€‚ƒ„„€€€‚ƒƒ…„‚„ƒ„…€€‚ƒ„„……………†‡†‰‡††…‡‡‡‡ˆ††…‡‡‡†‡††††‡‡‡‡ˆˆ‰ŠŠŠŠŠ‡ˆ‡‡‡‡‡ˆˆˆˆˆ‡‡ˆ†‡†††‡‡††ˆ‰‡ˆ‡‡‡†ˆ‡‡†††……†‡†††……„†…†……„„ƒ††……„ƒ‚……„ƒ‚€€„ƒ‚€€€€~|€€~}{z~|{zzy~|{{zyyx{{zyyxwuzyxwwqmnxxwunnnnvvqmnonouonnoopomnnnnnnmonooooonppponoonoopppoonnmmmkljhnnmlljjhnmmmkkihnnlmkihhhggedcbbggfedbbahffdcbbagfeccba``_^]\ZZX`_]][ZYW_^]\[YXW_]\[ZYWVWUTSQPN[VUTRQOdrVTSRQlpoUTQ[onpptqssssssrqqsssssrrqrrsssprrprssssssrrqqossrrqrppssqqrppnrqqrppoooonmmljhnnnmlkihnmmmkihhnnlkjihghgedcba_gfecbb`_fedcaa_^fdcbb`_^^^\[YXWV^][ZYWVU^\[YXWVT\[ZYWVUSTRQONMKJSRPOMLKIRQONMKJHRPOMLJIGHFECB@?=GFDCA?><:NOQRSUVWOOQRSTUWOOPRSTUWMOPQSTVVYZ[\]_`bXZ[\]_`aXZZ[]^_aXYZ[]^_acdfhilnocdfgilmobceghjmnbceghklnrtuxz{~qsuwyz|qstwyz|~prtuxz{~ƒ…†‰‹Œ€ƒ…†ˆŠŒ€„†‡Š‹Œ€„…†ˆ‹Œ’“•—˜™œ‘’”–˜™š‘’“–—˜š‘“”—˜™žŸ¢£¤¥§žŸ¡££¥¦œž ¢£¤¥›žŸ¡££¤©©ª¬®¯°°¨©ª«¬®¯°§©ªª¬­®¯¦¨©©««­®±²´µµµ¶¶°±²´µµ¶¶¯°±²³´µµ¯¯°±²³´´¸¸¹ºº»»»¶··¸¹¹¹º¶¶¶¶···¸µµ¶µ¶¶¶¶»»»»»»»»ººººººº¹¸¸¸¸···¸¶¶¶¶¶¶¶¶ººº¹¹¸·¶¹¹··¶¶µµ¶¶¶µµ´´²µµ´´²²±°¶µµ´³±°¯´³²±°¯¯­±±°¯¯­¬ª°¯®­«ª©©¯­«ª©§¦¤¬ª©¨¦¥£¢©©¦¤¤£¡ž§¥¤¢¡ ž£¡Ÿš˜— ž›˜˜•“žœš˜–•’‘›˜˜•”’‘Ž“’‘€pq‘‘ŽŠvrrr€rssst‹xstttttppppqppossssrrrqttttssssuuttttssnnnmmlkjppnnnmlkrqponnmksrrponnmhf|„†‰‹ihs€ƒ…‡Šjil€…†‰ljh~€ƒ…‡Œ‘’”—˜™Œ’“–—˜‹ŒŽ‘’”–˜Š‹‘“•—›žŸ ¢££šœžŸ ¢£™›œžŸ ¢˜™›žžŸ £¤¤¦¦¦¨§££¤¥¥¥¦¥££¤¤¤¥¤¦¢¢£££¤¤¥§¨§§§§¨§§¦§¨¨¨§§¦¦¥¥¥¥¦¦¤¤¤¤¦¦¤¤§¨¨¦¦¦¦¥§¦¥¦¦¥¤¥¦¦¦¤¤¥¤£¤¤¥¥¤¤££¥¤£¤££¡¡¤£¤£¢¢¢Ÿ¤¤£¢¢¡  ££¢¢¡ Ÿž žžœš™˜Ÿžžœš˜—žž›™™—žž›š™˜——–“’‘ŽŒ‹—•”’Œ‹—•’’ŽŒ‹••“’Œ‹‰†…ƒ€~{y‰†…‚€~{yˆ†…‚€~{y‰†…‚€~{yvsoprsstvtmnopqrvtmlmnoowtojklmmtuuwvwwwssttttttpprrrrssnnoooonfvvwrecegttibcefgnbbcdeghabccefghhhikmnnohijlmnoqhilmmooriklmnoqrqsstuvxyrsttvwyzsttuvxyysttvwyyzyz{|~~€zz|~~€€z{|}€€z||~~€€€‚ƒƒ………‚ƒƒ„…„‚ƒ„ƒ……‚‚„ƒƒ…††††††‡‡…†††††……„……†††††………„„„„…‡††††…††……††………………………ƒ„ƒ…„„„ƒƒ‚………„ƒƒ„„‚‚€€ƒ€€€~€€~~}€€~|{{~~|{{zy~|{{zyyx{{zyyxwvzyyxvuuqyxvuuunnwuuuqnoputsnopoqnnopooooopoqprrroqrqrrrrrrrqqqrroppppoonrppopoonrqppponmrqppnonnnmllkjhhmmmkjihgmllkihhfmlkiiggfgfdcbba_fedbba`^edcba`_^dcbaa_^]^]\[YXWV]][ZYWVU][ZYXWUa\[YYW[jmUScpnnppYknoonppomnoopppnnnonpooqrqqpqrqqrrrqqqqqrrrrrrrqrrrrrrqqrrppoonrrpopnnmrpopnomnqopoonnmnmlkihgfmmkiiggflkjihgfelkjhhfededca`_^]dcba`_]]cbba_^][cba_^^\[\ZZXVUTR[ZXWVUSQZYWVUSRQYXWUTSQOQONLKIHGPOMKJHGEONLKIGFDNMKJHGECECB@?=;:DBA?><:9CA?>=;98B@?=;:97MOPQRSUVMNPPRSUUMOOPQSTVMMOPQSTVWYZ[]]_`WXZ[\]_`WXZZ[]^`VXYZ[]^_acdfhilnbbdfgikmabceghkmabcdfhjlorsuxy{}oqstvyz}nqstvxz{nortuxy{€‚…†ˆŠŒ€‚„†‡Š‹~€„…†‰‹}€ƒ…†‡Š‘’”–—˜Œ’“•—˜Œ‘’”–˜‹Ž‘’“–—›œž ¢£¤™œžŸ¡£¤™›œžŸ¢£˜™›žŸ ¢¥§¨©ª«¬­¤¦§©©ª«¬¤¤¦¨©©ªª£¤¥¦¨©©ª®¯°°°²²³­®¯°°°±±«­®¯¯°°°««¬­®¯¯¯´³µµµµµµ²³²³´´´´°±±±±±²²¯°°°°°°°µµµµµµ´´´´´´²²³±±±±±±°°°°°°°¯¯¯®´²²±°°¯®±°°¯¯®­¬¯¯®­­«ªª­­««ª©¨§®¬«ª©©§¥ªª©¨§¥¤£©¨¦¥¤£¡ ¦¤¤£¡ ž¤£¡ ž›š¡ ž›š™—Ÿžœš˜˜–”›˜˜—•’’˜—•’‘‚•”‘‘Ž‹ys’‘Ž‚ttuŽŠytuwwrtttvuuvtuuwvwxxvwxwyyyyxyyyyyyzuuvvuuttxxxwwwvuyyyyyxwvzyyzyyywsssqponmutssqponvttssqonwuttsrqolkhx„†mljp€ƒ…nmkk€…nmkh{€ƒˆ‹Œ‘’”–‡‰‹‘’•†ˆŠŒŽ’“…‡‰‹‘’—˜™œžžŸ–˜˜š›žž•—˜™šœž”–—˜™›œ ¡¢££¤¤£Ÿ ¡¡£¢£¤žŸ ¡¡¢£¢žžž  ¡¡¢¤¤¤¥¥¥¥¥¤¤£££££££££¤¤¤¤¤¢£¢¢¢¢¢¢¤¤¤£¤£¤£¤¤£¤££¢££££¢¢£¢¡¢¢££¡¡¡¡¢£¢¡  Ÿž¢¡¢  ŸŸž¡¡  ŸŸžž   žŸžž›š˜˜—ž››š™˜—›š™˜——››š™——––”’‘Œ‹•“’‘‹‰”“’‘ŽŒŠ•’’‘ŒŒŠ‰†…‚€~{y‡†…€~{y‡†ƒ€~{z‡†„€~{zwtqhiiklxtsgghhixtshffggxtslcdeelmmmni`aijjjb_`bghe^__abf`]__`aaaccdeghhbbdefghibccefghiccdfggiiikmnnoqsjlmnoprskmnnoprskmnoorssttvvxxzzsuuwxyzzstvxyyy{ttuwyyyzz|~}€€z{~}€z{~~~€€z||}~€€€‚‚„„ƒ€€‚ƒƒ€€€‚‚€€€€ƒƒƒƒƒ„„ƒƒ„„ƒƒ‚ƒ‚‚‚‚‚‚€€€€€€€ƒ‚ƒ‚€€€€€€€~~€~~}|{~}}{z~~}|{zzy|{{zzyyx{zzyxxvuzyyxwvutyxwvutsrvuutsspnutssrooptqnpoprrooppqrqqppprqqrsoqrqqsssqqqrqpqrrssrspqqsssssprrssssqqrprpoponnmqopnnmmmopnommmkpoonnmkkmkjihgfdkjihgfedjihgfedcihgfedcbccaa_^]]cba`_]\[ba`_^][Za`_^]\Z[[ZYWbnlnZYZjmlmmXblllmmmjkllmnnnnnooopppmnonqooqnnnpopqqonpppprrrrrrrrqqrrrrrrrorrrrrrporrrrqqppopoonnmmoponmmmkpnonnmlkoonnmlkikjhggfdcjihgfdcbjhgfedcbiggedcbaba`_]\[Zaa_^][ZYa_^^\[YX`_]\[ZYWYWVTSRPOXVUSRQONWUTSQONLVUSRPOMKMKJIGFDCLKIGFECAKJHGEDB@JIGFDCA?A?><:986@?=;:865?=;:9764><:97643LMOPQRSULMNOPRSULMOOPRSTKLMOPQRSVWYZ[\]_UWXZ[\^^UWXZZ\]^UVWYZ[]^`bcdfhil`bbcfghj_abceghj_`acdfhimoqstvyzmnqstvxzlnortuxylmoqstvy}€„…‡‰{~ƒ…†ˆ{}€ƒ„†‡z|~€„…†‹ŒŽ‘’•–ŠŒ‘’“–Š‹ŒŽ‘’”‰ŠŒ‘’“˜˜šœžŸ¡—˜™›žžŸ–—˜™œŸ•——™š›ž¢£¤¥¦¨©©¡££¤¥¦§¨Ÿ¢¢£¤¤¥¦ŸŸ¡¢££¤¥©ª«¬¬­®®©©ªªª««¬¨¨©©©ªªª¥§¨¨©©©©®¯¯¯¯¯¯¯­­¬¬­¬¬­«ª¬¬¬¬ªªªªªªª©©©¯¯­®­­¬«­­«««ªª©ªªª©©©¨§©©¨¨¦¦¥¤«ª©©¨§¥¥©¨§¦¥¤££¦¥¤¤£¢ Ÿ¤££¡ žž¤£¡ Ÿ›¡ ž›™˜žœ›™˜–•œš˜——•”’™——•“‘‘Ž–•”’Š”’‘Žt‘ŒˆyuvŽtuvwxyyuvwxyyzuwxyyzz{wxyzz{{|yyzzz{{zzz{{||}}{||}~~~~}~~~z{zzzzyy}{|{zzyy~}}}|{{z~~}}{{zxwvttsroywwutsrqyyxvtssqyyxvutsrnmljt~€ommkm~€onmki{~€onmlhw}„†ˆŠŒŽ‘ƒ…‡‰‹Œ‘„†ˆŠŒ€ƒ…‡‰‹ŒŽ“”–—˜š›œ’“•—˜˜š›‘’“–——™™‘’”–—˜™žžŸŸ  ¡œžžžž  ›œœžŸž™››žž¢¡¢¡¡¡¡¡Ÿ¡ ¡¢¢¢¢ŸŸ  ŸŸŸŸžŸžžžžŸŸ¡¢¡¡¢  Ÿ¢ ¡ Ÿ  ŸŸ  Ÿ žžŸžžžŸŸžž ŸžžžžœžŸžœœžžžžœœ›žžœ›šœœš™˜˜––›š™™——–•šš˜˜˜––”š˜˜———•””’’‹Š“’‘Œ‹Š“’‘Œ‹ˆ“’Œ‹‰‡†ƒ€~{z‡†„€~{zˆ†„€~{z†…„€~{zxvsobccbxvsqca^[xvsqc[[[xvsrcZ[[\^]_``ba]^^^``bb]^^^`aab]^^__abbcddfggijbdefghikccefghjkccefghjklmmnpqstlmmooqstkmnnorrtkmnnoqstttuwyyzzttuxyyzzttvxwxzyttvwwyyzz||~}~{{||~}~z{{||}}~yz{{|{|}€€€€€~€€€}~}~~}}~}|€€}~}}~~}|}{{}||{|zzz~~}}{{zz}{{zzyyyzzzyyxxvzyyxwwuuyyxxwuttxwvuttssvuttssrrttsrrqomssrpnopprpnnpoqrnnopprqqoopprqrsrqqsrsssqrsssssssssssssssssssssrssrrqrppsrrqrpporrqrppoorqrpponnoonnmlkjonnmlkjhnnmkjihgmmkjihgfhgfedcbagfedcba`fedcba`_edcba`_^`_^]\[cm_^][]ijk^][bjjkl]\hijkllkllmnnnolmmnmnonlmnmnonpmnmnooponppoqrrrppoqqrrroprqrqqpqrrqqppqrrrrroopqrrqqoqnqrrropooqrqqopnnonmmmljiomnllkihnnmlkjhhmmmljhhghgfecbaagfedcaa_gedcba`^fdcbb`_^_^][ZYWV^]\[ZXWV]\[ZYWVT][ZYWVUSUSRQONLKTRQPNMKJSQPOMKJHQPNMKKHGIHFECA@?HGECB@?=GECBA?><;=;:87542;:975421;98643109865420/KLMOOQRSKLMNOQRSKLMNOPQSKKLMOPQRUVWXY[\]TUWXZZ[]TVVXYZ[]SUVWYY[\_`bbdfgh^_abcegh^_`acdfh^_`bbcfgjmnqstvxjlnortuwilmoqstwhjmnprtuz{~€‚…†yz|€„…yz{~‚…xy{|€„‡Š‹ŒŽ‘’†‰ŠŒ’†‡Š‹Œ‘…†ˆŠ‹ŒŽ“–—˜™šœ“”–—˜™šœ’“•–—˜™š‘’“•–—˜™žŸ ¡¢££¤žŸ ¢¢£›žŸŸ¡¡šœœžžžŸ¤¥¥¦§§¨¨££¤¤¤¦¥¥¢££££¤¤¤  ¡¢¢¢¡¢¨¨¨¨¨¨§¦¥¥¥¥¥¥¥¤¤¤¤¤¤£££¢¡¢¢¢ ¡¡§¦¥¥¤¤£¢¤¤££¢¢¡Ÿ¢¢  ŸŸžŸŸžžœœ›¢¡ŸžœšŸžœ›š˜—œœš™˜—–•™˜˜—–”’‘˜˜–•”’‘—•”’‘Ž“’‘Ž‹‹‹Š‡wŽ‹tuwx‹‰xtvwxy€tuvwyzztuwxyzz{yzz{{}~~zz{|~~{|}~€|~€€€€€€€€€€€€€€€‚‚€€‚‚‚€~}|{€€~~}|€€}|€€~|zzywutsr{yyxvusr{zywwtts{zzyvvtspnmliq{~qonkjk{}qonkkgy{qonkkguz€„†‡Š‹€‚…†‰‹Œ~„…‡‰‹}€ƒ…†ˆŠ‘’“•–—˜‘’“•–—ŒŽ‘’”•–Œ‘’’“–™š›œœœž˜˜šš›œ—˜™™š›››———˜™šš›žžžŸŸŸžžžœžž›œœœœœŸžžžžžžžžžœœœœœ›››œ›œššœ›››šš™››œ›™š˜™œ›™š™˜˜—™™———••“™˜˜—–•““˜˜——•”“’˜——••”“‘’‘‹‹ˆ‘‘ŽŒŒ‰‰’‘Œ‹Š‡‘Œ‹Š‡‡…„€~{y†…„‚~{y†…‚€~|y†…ƒ~|yxvspjY[[xvspnZ[[xvspo^[[xtspod[[]^^__abb]^^__abb]^^__abb]^^__abbccegghjkccegghjkccefghikccefggiikmmnpqsskmmnpqrslmnnoqqslmnnopqrsuvuxxxytttvvwxxsstuvvwxsttuuvvwzyz{z{|{yzzyzzz{yxyyzzzzwxxyyyxx|||||{{{zzzzzzzzzzzzyyyyyyyxyxxx{{zzzzyyyzyyyxxvyyxxvvuuwwvuutttxxvvuttsvuuttssrttssrrqossrqponnsrqppmmnpponmooponmmnoppmlnnpoqrpoqrqrrsprqqssssrqrsssssprrsssssssssssrrssssssqqsssssqqqssrrqrqpqrpoonmmqopnnmmloonnnmlkoonmmlkimkjihgfekjihgfdcjhhgfecbhggfdcbadcba`_^]cba`_^^gaa`^]bij`_^^giijbkiklllmjikkmmnmjklmmnmnkllmnnonnnnnppoqnonpoprqnoppqrpqpoqrqqsrrqqrrsspqqsrsssqsrssssspsssssssqqrropnomqqqoponnrropnnmmqqpoommmnlkjihgfmlkihgfelkihhfedljhhgfdcecba`_^]dca`_^]\cba_^^\[ba`_]][Z[ZYWVUSRZYXWUSRQYXWVTSQOYWVUSQPOQONLKIHFONLKIHGDNLKJHGEDMLJHGECCECA@?=;9DB@?=<:9BA?=<:98@@><:986865321/.764310-&64310+&&4410*'''IKLMOPPRIJLMOOPRIKKLMOPQIJKLMOOQSUUWXZZ\STVVWYZ[RTUVWYY[RSUUWXZZ]^_abceg]^_`acdf\^_`bbde\]^_abcdhjlnorsugikmnqstghklnorsfhilmopsvyz|~‚vxy{}€uwyz|~€tvxy{|€…†‡‰‹Œ„…†‡Š‹Œ‚„…†ˆŠ‹Œƒ…†‡‰Š‹‘’”•–—˜‘’“•–—Ž‘’“”–ŒŽ‘’’“˜™›œœžž˜˜™™›œœ–—˜˜™™šš•––——˜˜˜žžŸŸŸŸŸŸžžžžžžšœœœœœ›œ™™™™™™™™ŸŸŸŸ žžžžžœœœœœš›š™™™™™˜˜˜——œ›™™˜š›™™˜——–˜˜——–”“’––”“’’‘—–•“’‘‘•“’‘Œ‘‘Œ‹ŠŠŽŒŒ‹ˆˆ†ŽŒ‹Š‰~st‹‰ˆ„wsuvˆˆ}stuvxƒvstuwxyuwxyz{|}xyzz{}~yzz{}~€z{|~€€~€€‚€€‚‚ƒƒ€€‚ƒƒ„…‚ƒƒƒ…„…ƒƒ„„„„ƒ‚ƒƒƒƒƒƒƒ„……………„…ƒ…………………„‚€€~‚‚}„‚‚€€€}ƒƒ‚€€€}{{yyvvts|zzyvvts|zzyvvts|zyywttrqonkkhmzqonljhhyqomlihevqnmlihfq{~„…‡‰z|€‚„†ˆy{}ƒ…†xz|~€‚„†‹ŒŽ‘’’”Š‹ŒŽ‘’“ˆŠŒŽ‘’‡‰‹Œ‘––——˜˜™š”•–—˜˜˜˜“”•–———˜’“”•–——˜ššœ››œœœššš™››››˜˜˜š™ššš—˜˜™™™˜˜œœ››œœšš››››™™š™šš™™š˜˜™˜˜™™™˜˜˜™šš˜™˜—˜™˜™˜—˜——™˜—˜˜—–——˜˜—–—–•——••”’’’—••”“’‘‘••“““’‘‘•”““’’‘ŽŒŒŠ‰‡Œ‹Š‰†ŽŒ‹Šˆ†ŽŒŒ‹‰‡†……‚€|zy†ƒƒ€}{y…„€}zy…„€|zyvuspniZ[vusqnm[[vtsqnn_[wtsqnmd[]]^^`abb]^^^``ba\^]__`ba\]]^_`abbdefggiicddeghhiccdefghhbccefghhlmmmoppqklmnnnoqjklmmnopijkmmmnnsststtuvqsststtuqrrrsttsppqrrsssuwvxwwxxtvuuvvvvtttuttttsttstttsxwwvvwwuvuuuuuttttttttsssssssqrquttttssrttssrrppsrrpponnqoonnnmmqqoonmmlonnmmmmnnmlmjlnnlljknnnpmoopoqrqoopprqqsopprqqssoprqqssssrsssssssssssssrsssssssqssssrrqqssqqqpporqrqoonnqrpponnmqopnnmmmnmmmkjihnmlkjihgmlkjhggfljihgfedgfedcbbafddcba`_ecbba`^bcbaa__fi_^aiijkk_eiijkkmihjjklmmhjjllmmmlmmmnoopmnmnnppqnnooppqqnnopqqqspqqqsrssrqrsssrrqssrrsstrrsststtssssssqqrsssssqrtrsssrqqsssssqroqooonnmkppnnnmlkponmmlkjoonmmkihjihgfecbihgfdcbahgfedba`hfedcba_b`_^][ZY`_^][ZYW_^][ZYWV^]\ZYXVUWVUSRPOMVUSRPOMLUSRQONLKSRPPNLJIKJIGFDCAKIGFDBA?IHFECB@?GGDDB@?=@><;9865><;:8653=<:87540<:8754.+42/)('('2-)))(''+*)*()('*+**)(('HIKKMOOPHIJKLMOPHIJKLMOOGHIKLMOORSTVVXYZQRTUVWYYQRSTUWXZPQSTVVWY[]^_`acd[\^^_abcZ\]^_`acZ[\]_`bbfghkmnprefhilmoqdfgijmnoceghilmosuwyz{~stuxyz|~rstwxz{}pstuwyz{€„…†‡‰Š€‚„…†‡‰~€‚„…†‡}€‚„…†‹ŒŽ‘‘’Š‹ŒŽ‘ˆŠ‹ŒŒŽ‡ˆ‰Š‹ŒŒ““••––——‘’’““••”‘‘’’’’’‘‘‘——˜˜˜˜˜—–––––––•””“““”“’‘‘‘‘‘‘‘———–––•“”••““’’‘’’’‘‘ŽŒŒ“’’‘ŽŒ‘ŽŽŒ‹‹ŒŒ‹ŠŠˆ‡‹ŠŠˆ‡††„Œ‹Šˆ‡††{‰‡‡†…ƒsr†……ƒzpss„‚€rqrturstvwxyzstvwyzz|tvwyyz{}vwyz{|}{|}€€€‚}~€€‚ƒ~€€‚ƒ„€€‚‚ƒ„„‚ƒ„…„…††ƒ„„…†…††…………†…††…††…†‡‡‡†††††………††††††„„†…††††„…†‡††††„…ƒƒ‚€€€}„„‚€€€~}ƒ‚‚€~}ƒƒ~|{zzwwusr{zyxutsr{zyxutspzzyvutrqonmjjhfjonmkhgfeonkjhgfbnmlihgecxy{}ƒ…wyz|~€„swy{}€ƒmvxz|~€†ˆŠ‹ŒŽ‘…†‰Š‹Œ„†‡‰‹‹ŒŽƒ…†‡Š‹Œ‘’’“•–––‘‘’’””•–‘‘’““”•Ž‘‘‘’’“—˜˜———˜˜—–———˜˜˜••–——–––”••••–••˜˜—————˜˜˜˜˜———–––––———••••–••––——–—–•–”——••–•“”••–•“”“’””””“’’’”““’’‘‘’“’’‘‘Ž’‘’‘‘Ž‘’‘‘ŽŒŽŒ‹Š‰‡†ŒŒ‹Šˆ††ŒŒ‹Š‰‡†…ŒŒŠŠˆ†………ƒ‚€}}zy„ƒ€€~{zx„‚€~{zx„€|{zxwtsqnmhZvtsqnmk\wtspnmk_utsqnmkc[]^^__ab[]^^^``a[\]]^__aZ[]]^^``bbddefggabcceffhabbcdefgaabcddefhjkkmmmnhiikkmmnhhijjlllghhhijklooppqqrrnnnooppqmnmnnnonlmmmnmnmqssssssqqppppppqpppppooomnnnnnnmrrrqqpoopoopnnnnnnnnmmmlmmmlljkinnnmmllkmmlljjiikkjihiimihhggjnmiimnonpoknnoopoqmnoopoqrnnoppqrqqrqrrsssrqrrssssqrrsssssrrssssrqssssqqrpssrqrqoprqqqppooqrqopnnmpoonnmlknnmmmkkinnmlkjihmmljjhhgiihgfddchggfecbbgfedcbaafdccba``ba`_ahiia`_ehiij_aghhjjkehhhjjkljkkmmnnnklmmnnoollmmnnpomnnnopproppqqrsrpqqrsrssqqrrrsttqsrststtsstttttttttttttttttttttstttttttstssrqrpptrsrqqpnsssqqponrrrroonmnnnmljignnmkjihgnmljihgemlkihgfegedcba_^fdcba_^^dcba`_]\cba`^^][]\[ZXWUS\[ZXWVTS[ZYWVTSQZYWVTSQORQPNMKJHQONMKJHGOOLLJHFEOLLJHFECGEDB@>=;EDBA?><;CBA?><:9C@@><:98:9862-,,9870---+84.-.--,2./...,,+*+**))(+++*)*()+,++*))),,+**)*(GHIKKLMOGHIJKLMOGGHIJLMNEGHIKKLMPQRSUVWXOQRSTVVWOPQRSUVWOPQRSUUWYZ\]^_abYZ[]]_`bYY[\^^_aXYZ[]]_`cdfgijmnbceghilmbcdfghjlbbcdfhikoqstvwyznprstvxymoqrtuvxmnoqstuv|}€‚ƒ…z{}€‚ƒyz|}~€xyz{}~€††‡‰ŠŠ‹‹„…††‡‰‰Šƒ„……††‡‡€ƒ„„……†ŒŒŽ‹‹‹ŒŒŒŒŒ‰ˆ‰ŠŠ‰‰‹††‡‡‡‡‡‡ŽŽŽŽŽŽŒŒŒŒŒŒŒ‹‹ŠŠŠŠŠ‰ˆ‡‡‡‡‡†††ŒŒ‹‹ŠŠ‹‹ŠŠ‰‡‡†‰‡‡††……„………„ƒ‚€ˆ‡††…„ƒ†…„‚€€}ƒ€€vn€~{ono€yoqstuvqnqstuvxoqstuvxyqstuvxyzxyz{|~~yz{|}€€z{|}€€{|~€€‚€€ƒƒ………‚ƒƒ……††‚ƒ„……†…†ƒ„„………†‡……†‡†‡‡‡†††‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡††††„„‡†††………ƒ‡‡…††„„ƒ†††………ƒ‚„€€}{‚‚~}{‚€€}{z‚~|zyzyxvtsroyywutspoyxvtsrpnywutsqonnmjihfdcmljhgfdcmkihfecbljhgfdcbfvwyz|€btvxz{~aptvyz|~ajtuxy{}‚„…†ˆŠ‹Œƒ„†‡ˆŠ‹€ƒ…†‡‰Š€‚„…†ˆ‰Ž‘‘’’’ŒŽ‘‘‘‹Œ‘‘Š‹ŒŽ’“”“••••’“’“”“””’‘’’’““’‘‘’‘‘‘’•–”••”“”””””“”“’’’’“““’’’’’‘‘‘’’””’’’’‘’’“’’‘’‘‘’‘’’‘‘‘’‘‘‘‘ŽŒ‘ŽŒ‹ŽŽŒŒ‹‹ŽŽŒŒ‹‹Š‹‹Š‰‡††…‹‹Šˆ††…„‹‰ˆ‡††…ƒŠ‰ˆ†……„ƒ‚€~}zyx‚€€~}zyx€~{zyv€}{zywutrpnmkgutronlkivtronlihtsronlihZ\\^]^__\[[]]^^__Z\\]]^_cZ[[]^]^abacccde`abbcccd``abbccc_``abbccfghhhijjeffghhhhdeffgghhddeefffgjklkmlmmiijkjkkkhhiijiiighhhhhhhmmmmmlllkkjkkkiiiijhihhhghhhgggfljkiiihhiihhhgggggggfffefffeeddhhggglnnnffinnnonflmnnonpmmmnonponppprqqqpoprqqpqoprrrpqpprrrrqpqssssrqqrssqqqrqppqqrrqopqrrqopooqopoonnmponnmmmlonnnmlkjnmmmljihlkjihgffjihhgfddihgffdcbhgfedcbbdcbaa_bgcbba`dhgba`afggha^dggghighhjkkmmhiikkmmmijklmmmnjkllmmnonnoopqqrnnooqqrrnpprqsrsopqrsssssrstttttststtssttttsttuuttttuuuttttttttssttttsssttttssrsttttsrsqrrqppommrqppnnmlrppnnmlkqpnnmlkjlkihgfeckihgfecbjhgfdcbahgfdcba`ba`_^][Za`_^][ZY`_^][ZYW_^][ZYWVYWVURQPOWVUSQPOMVUSRPOMLUSRPOMLJMLJIGECCLJIGFDCAJIGFDCA@IGFDCA@>@@><:970@>=;9500>=;92111<;722211////.--,00//.-.-000....-10//./-.-+,++**),,,+**)),-+,*+)*-,,++***EGGHIKLMEFGHIKKLDEGHIJKLDEGGHIKLOOPQSTUVMOPQRSUUMOOPRSTVMNOPQRSUWYY[\^^_WXZZ[\]_VWYY[\]^UWXYZ[\]`acdfghi`abcdfgh_aabcdfg^`abcdeflmnpqstujlmnoqstijlmnpqshijlmnpqvxyz{|}~uvxyyz{}ttuwxyzzrstuvwxy€€‚‚„„~~€€{||~~€yz{{|}|~„……………††ƒƒ‚‚ƒƒƒ€€€€€€€€~~}~~~~~……………„„„ƒ‚ƒƒ€€€€€~~~~|}}{{‚ƒ€€€~€~~}{{~}}{zzyyzzyyxxuk~}|tmnoqzwmmnoqrpklmoqrtilmoprststuvxyz{suvxyz{|uvxyz{|~vwyz{|}|~€€‚ƒ~€€‚ƒ„€€‚ƒ„„€€‚ƒ„„…„„………††‡„………††‡‡………††‡‡‡…†††‡‡‡‡‡‡‡‡‡‡‡†‡‡‡‡‡‡††‡‡‡‡‡††…‡‡‡‡††……†………„„ƒ‚………„„ƒ‚……„„ƒ‚€…„„ƒ‚€€€€~}{zy€}|zyx€}|zyyw}|{zyxuxvtsrpnmwutrqomlutsqonmktsrpnmlikihgedbajhgfdcbaihfedbaahgfdcbccacttwyz|`assuwy{bapstvxzcakqsuwy~ƒ„…†‡}~€ƒ…††{}€„…†z|~€‚ƒ…‰Š‹ŒŒŽ‡‰Š‹‹ŒŽ‡‡‰Š‹ŒŒ†‡‡‰Š‹‹‹‘‘‘‘’Ž‘‘‘ŽŒŒŽŽ’’’’‘‘‘‘‘‘‘‘ŽŽŽŽ‘ŽŽŽŽŒŽŒŒŽŒŒŒ‹ŒŒŒŒ‹‹ŠŒ‹Œ‹‹‰‰‹Œ‹ŠŠ‰‰ˆ‹‹‹Š‰ˆ‡‡‰ˆ†††…ƒˆ‡††…„ƒ‡†……„ƒ€†………„‚€€€|{zxw€~|zyxu€}{zyxu~}{yyvutsrpnlihtspomlihtrqnmlihtrqnmjigfZ[[\]^^g\ZZ\\]^f_YZ[\\]fcYZ[[\\__``abbb^__``aba^^__``ab]^^^___`bccdeeffbcccddddbabcbcccabbaabbbfgggggggeeeeeeeeddddddddccccccccggffffeeeeedddcdddcccccbcbbbbaaaeddccckmcccbgmmnbbcjmmnmaflmmnmnnmnonpoomnonpooqnnoqopqqnnpoporrqrrrqrrqqrrrrqrqrrrqrqoorrqqooporqoponnnpppnonnmpoonmmmlnnnnmlljnmlkjihgmlkihhgfkjihgffeihhgfedcffecbba`edcbaa_dccba``efbaa_ceffagfghhijgfghhijkghhhjjklhhhjjlmmklmnnnoplmnnoopqmnnnooqqnnnppqqsqqrrstttqrrsttttsrsstttursstttuustuuuuttttuuuuusuuuututtuuuttstsststssqqtttrsqqottssqqoosssrppnnoonmlkjhonmlkjhgnmlkjhgfmlkihgfegfdcba`_fdcba`_^dcba`_^]cba`^^][^][ZYWVU][ZYWVUS[ZYWVUSRZYWVURRPSRPOMLJIRPOMLJIGPOMLJIGFOMLJIGFDGFDCA@>=FDCA?>=9DCA??<64CA??:454;323222134233121334222124434232210/0/...0100///-110/0./-101///..--,,++**.,-+,**).,-+,*+)--,,,*+)DEFGHIKKCDEGGHIKCDEFGHIKCCDEGHIILMOOQRSTLMNOPQRSKLMNPQRSKLMNOPQRVVWYY[\]UUWXYZ[\TUVWXZZ[STUVWXY[^_`abcdf^^_`bbcd\]^_`abc\]]^_`abghijlmnofghijlmndffghiklcdefghijprsstuvwnpprsstumnooprrsllmnnoppxyyyzzz{uwvxxxyysttuuuwwrrsssstt{{{{{{{{yyyyyyyyvwwwwvwvttttttts{{zzzyyyyyxxxvwuuuutttsssssrrrppxxwuvnhjtttrhhikrrlfhikmmgeghklnlmnprstvmnpqstvwnpqstuwyoqstuwxywyz{|}€yyz|~€zz{}€€z|}~€‚ƒ„„……€‚ƒƒ……††‚‚ƒ…„†††‚ƒ„„……††††‡‡‡‡‡‡…†‡‡‡‡‡‡†‡‡‡‡‡‡†††‡‡‡‡‡†‡‡‡‡†………‡†††††……‡†……†……ƒ…††…„„„ƒ„„ƒ‚€€„ƒ‚€€~ƒ‚€€~|€€€}|{~|{zyxvt|{zyxvut{zyxvutszyxvutsqsrqomljhsqonmkihqonmkjhgpnmkjhgfgfdcceddgedfgffeeehhhggfhkjiihggcbgprtvxddcpqstwedcnprtufedjoqsty{}~€‚„xz{}€‚wyz{~€vxyz|~€…†‡ˆ‰‰‹‹„……†‡ˆ‰Šƒ„…††‡ˆ‰ƒ„…†††‡Œ‹ŒŒŒŒŠ‹ŒŒ‹ŒŒŒŠŠ‹‹‹‹ŒŒˆˆ‰ŠŠ‹‹‹ŽŽŽŽŒŒŒŒŒŒŒŒŒ‹‹ŒŒŒŒŒŒ‹‹ŠŠŠŠ‹‹‹‹ŒŒŒ‹ŒŒ‹‹‹ŒŒ‹‹‹‹Š‹Š‹‹Š‰Š‰‰Š‰Šˆˆˆ‡‹‰‰‰ˆˆ††‰‰ˆˆ‡‡††‡ˆ‡‡†…†…‡‡†††…„„………ƒ‚€€……ƒƒ‚€…ƒƒ‚€€„‚‚€€€~}~{zywwt~}{zyxut}{zzyvut|{zyxvttsronmkigsronmjhgsponkkhgrqnmlihgfdYZZ[[\fd[YZZ[[ed^XYZZZedaWXYYY\]^]^__`\\]^^^^_[[[\]^^]Z[[[[\]]_`aaabbb___`_```^^______^^]]^^^^aaaaaaaaaaaaaaaa_``````_^_____^^abbbaaab````__ek____`hkl^^^cjkllimlmmmnnllmmmnnnlmmmnnoommmnnonpnpoppoqqpppppppppoppppopppppopppqpooppnnpoppnonmppnonmnmnonmnmmlnnmmlkiimmlljihhmlkihhgfkjihggfdhgffdccbgfedcbaafdccba``dcbaa_bda`_eefgh`beeffhhcdeffghhdeffghhjhhjjlmmnhjjlmmnnjjlmmnnnjkmmnnnpnnpprqsrnpprqsrspprqsrssprqsrsstsstttuuustttuuuutttuuuuttsuuututuuttstssuutstssrutsttsrrststssrqrrrppnnmrqponmmlqponnmkjponnmljilkihgfecjihgfdcbihgfdcbahffdcba_ba`_^][Za`_^\[ZY_^]\[ZXV^]\[YXWUYWVURQPOWVTRQOOMVTSQOOLLTSQOOLLJMLJIGFDCLJIGFDCAJIGFDCA?HFFDCA>8A??85655@=665665:6766565787766655444332155334232444333325554333321000//.2110/0..2201/0./1201/0./.--,,++)---,,++)---,,++)---,,*+)BCDEGGHIACDDEGHIACCDEGGHAACDEEGHJKLMOOQRIKLMNOPQIKKLMOOPIIKLMMOPSTUVWXYZRSTVVWXYQRSTUVWYQRSTTUVW[\]]__`bZ[\]^^_aZZ[\]]^_XZZ[\]]^bcddfghhabccdefg`aabccde_``bbbccikklmmnnhhijjllmfgghhiikdeffgghhooqqpqrrmmnnnnnpjlllkmmmhhjiiiiirrrrrrqppppnnnnnmmmmlllliiiiiiihqqooonnhnmmmlkdckjkjeacdhhfaabdfdfghjlmodghikmnpfgikmnoqghjlmoqsqrttvxyzrstuxyzzstuwyzz|suwxyz{}{}~€€‚|~€€€‚ƒ}~„~€€€‚‚„ƒƒ…„††††ƒ„……††††ƒ…………†††ƒ……„††††…†‡‡††…††………††…†††††††…„†††……„…„…………„ƒ‚…„„ƒƒ‚€…„ƒ‚‚€€€ƒƒ€€~|{z~}{zzy~}|zyyx~|{zyywuyxvutsroxvutsrpnvutsqonmttsqpnmlnmljhggkmljigjonljihnoopjikqrqqpmllkjiihnnmmlkiinnnnmlljpoonnmmlggfgnorshgfennprihgfkmoqjhhgjlnptwxz{|~tuwyz{}~stuxyz|}rstvxyz|€‚ƒ……††€‚„……†~€‚ƒ„„}~€€‚ƒ„†‡ˆ‰ˆŠ‰Š†††‡‡ˆˆ‡…†…†††††„„…††……†ŠŠŠŠŠ‰‰Šˆˆˆ‰‡‡ˆ‡‡ˆˆ‡†††‡††††††……‰ˆ‡ˆ‡‡†‡‡ˆ††‡††…‡††……†………††…………ƒ†…†………„ƒ†………„ƒƒ‚„…„ƒƒ‚€„„ƒ‚€€€‚‚€€€~}€€~}|€~}|z€~}|{z{zzywutszyyxvtsszyywutsrzywvtssrronmliggqonmjihfqnnlkhgfonmlihgfeccXXXYZdcbZWXXXdcb^VVWXdca`UVVVZYZ[[[\\YZZYZZ[[XXYYZYYZWXWXYYYZ\]]]]^^^[\\[\\\\Z[[Z[[[[ZYYZZZZZ^]]]]]^^\]]]]]\\\\\\\[\gZ[[ZZ`hh]^hjkllmbijlllmnijkkmmnnjkkmlmnnmnnnoooqnnoooonpmooooooonoooooooppppponopponoonnoooonnmnoonnmnmlnnnmmlljmmmmlkiimmlkjihhlkjihhgfihhgfedchggfddcbgfedcbbafeccbba`bba`_ccdaa_acdde``bcddefacbddefgefgghhjjfgghhjjlgggiijlmgghijklmlmmnnnppmmnnnpoqmnnoooqqnnoopqqrrqsrssttqsssttttssstttttrrsttttttsuuutstttttstttttttttssttttstsrtssrsqqotsrrqppossrqponmrqqoonnmnnmmkihgnmlkjhgfmlkihgfdljihgfdcfeccba_^dcbaa_^]cba`_^][ba`^^][Z][[YXWUS[ZYWVUSRZYXVUTRQYWVUSQQORQPNLLJHPPNMKJHGPNLJJHGENLJIGGEDFECCA;88ECC@:898CC=9:989B;:9:99878877766878767658877777698878676645444235555342366453343664443431201/0./2211/0./2211/0..2111/0..---,,*+)--,,,***---+,***---+++**@ACCDEGG@AACDDEG?@ACCDEF?@AACCDEHIJKLMNOGHIKKLMOGHIJKLMMGGHIJKLMPQRSTUUVOPQRSTUUOOPQRSTUNOOPQRSTWXZZ[\\^VWXYZZ[\UVWXYYZ[UUVWXXYZ^^_`abbb]]^__``a\\]]^^__Z[[\]^^^ccddeeffabbccccd`aababbb^___``aafgggggggdedeeeeebbccccccaabbbbbbgggggggfeeededdcccccbb_]bbaa`[^^fb`abceg^_`bcdfg_`bbcfgh_abcefhihilmnprsikmnoqstjlmoqrttkmnorstutuxyyz|}uwxyz{}~vxyyz|}wyzz||}€‚ƒ„~€€‚ƒ„€‚ƒƒ€€‚ƒƒ…………………ƒ…………………ƒƒ……………ƒƒ„ƒƒƒƒƒ„……„„…„ƒƒ„…„„ƒƒ‚„ƒ„‚‚€€‚‚‚€€€‚€€~}€€~|{~}{{z~}|{zzy{zzyxwutzzyxvutsyxwvttsqxwutsrqpsrqonmljrqonmljlponmlkptnmmklsuujosssssrsssssststuuuutttvvwwvvuurqqponmmssrqoonmstsrqoonuttsrqpnkjhhgkmnlkihgllnmkjhgikmnljihiilprtuwxyzoqstuwyznorstvwymnprstuw{}~€€‚z|}~€€€zz|}~€yzz{|}ƒ„„…„………‚‚ƒ„„„…€€‚‚‚„€€€‚†††††…………………„…„ƒ„ƒƒƒ„„‚ƒ‚‚‚‚‚………„„ƒ„‚„„ƒƒ‚‚ƒ‚‚€€€€€€€€‚€€€€€€€€~~~~}|{}}|{zz~}||zzzy}|{zzzyx|zzyzyxwyxwutsrqxwvtssrpwvttsrqovutssqononmkihfenmlkhgfdnmlihgedmlkigfeccbb`WVUVcba_ZTUVbaa_\STUbb`_^STSVWWWXWXXUUVWWWWXUVVUUVVVTTUUVVUUYYYZZZYYWWXXXXYYVWWWXXXWVVVWWVV]YYY[ehijYY_hghiiYdghhhjkegggiiiljklmmmnnlkmlnnnnklmmmnnnkmmmmnnnnooooononoooonnmnmmmmnmnnnnnmnmlnnmnmlllnnmmmkkjmmmlkjihmlkjjhhgkiihggfeihhgfedchgffddcbgfedcbbadcbaa`_acbba__bbaa`_abbca_^babcccbcdefggbcceffggccdefghhcdefghhhghijklmnhijlllnmijkllmmnikkmmnnonoopprqrnnpprqssnpoqqrssopqrqsssssttttttssttttttrtttttttsstttssrttttsrsrstsssrqqsrrsqqpprsrqqponqpoonmlkponmmlkinnmmljihmmlkihhgjhggfdcbhgfdccbagfdcbba_fdcba`_^a__^\[ZY_^]\ZZXW^][ZYXWU][ZYWVUSWVUSRPNNVURRPOMKTSQOOMLJRQPNLLJILKIGGDC?KIHFDC=;HHFEA<;<<=<;;;:9:99;:;::9::;;:;::9:<;;:;;::999877779998776798997866:9998867565543435655434366554343665544332201//..2201///.12000//-12000..-.,,+++)).,,,+*))--,,***(--+++*)(??@ABCDD=??@ACCD=>?@@ACC<=??@ABCEGGHIKKLEFGGIIKKDEGGHIIKDDEGGHIIMNOOPQRSLMNOOPQRKLMNOOPQKKLMMOOPTTVVWWXYSSTUUVWWRRSSUUUVPQRRSTTUZZZ[[\\]XYYYZZ[[WWXXYYZZUVVWWWXX^]^^^___\\\]]^^]ZZ[[[[[\YYZZZZZZ________^^^^^^^^\\\\\\\\ZZZZZZYW___][\]_^][Z\]^_ZYZ[\^_`WYZ\]^_a`bbdfghjabcdfhilacdfghklbcefhikmlnoprttvmnorstuvnoqrttuwnorsstvxxyy{|}}~xyzz|~}~yzzz{~}~yzz|{~}€€€€ƒ€€€‚‚€€€€€€€€ƒƒƒƒƒƒ‚‚‚‚‚‚€€€€€€€€€€€€€€€~€~~}€~~}{{~~}{{zz~}{zzyxw{{zyyxwuzzyxwuttyxwvutssvutsrqontssrponmsrqonmmlrponmmkrmlkpuvvwlktvwxxyovwxyyyzwxyyzyzzxxxxxwwvxyyyxyxwzyyzzyyyz{{zzyzyvtttsrqowvuttsqowwvussrpywvutsrqnmlihhhjnmljhghionlkigghonmkihgglmoqrstvkmnoqsttilmnpqsthjlmnorsxyzz{|}~vxxyzz||tuwxyyz{ttvwxyzz€€€€}~€{}}~~z{{|}}}~€€€€€€€€€€~~~~~~~~}}€€€€~~~~~~~}}}{}|}{|{|z}~~}|{z}||{{zzz{{z{zzzy{zzyzyyyzzzyyxwvzyyywwuuyyxwvvutxwwuutssuttsrpnmttsqponmssqponmlsrponmmkmkihgfdcljhhfedbkihgfdcbihgfedbaba`^^USSaa_^^XQRb`_^][PRa_^]]\QPSTSTTUUVSRSSTSTTQRRSRSSSQRRQRRSSVVVUUWaeTUUU[ddeTSU_cddfRYbbccefffhhiiilfgghhjilgghhhjilgghhhjikllmlnnnnkmmmmmmmkllmmmlmlkkmmmlknmnmmlmlmmlmmlkklmklkkiilkkjjihhkkiihhgfiihhgffdhhggfedcggfedccbedccbba`dcbaa`_^cbb``^_`aa`_^__`_`ababcd`ababbdd`bbbbcceabbcccdfdeffhhhjefgghiijfggghiilfghhhjkkjkmmnnonklmnmnnpllmnnnopmmmmoopoporqqsssoqqqssssorrqrrssorrqprrqsrrrrsrsssssssrqsrsrqqqpqrqrqpporqqponnmqppnnmmlponnmmlkonnmlkjimlkihgfekjihgfdcihggfdcbhgfdccbadcba__^]baa_^]\Za`_^][ZY__^][ZYW[ZYWVUTRZYWVUSQQXVVTRRPNWUSSQOOMPPNMKJHFONLJJHGENLKIGGD?KKIGGA>@FC=<====@=>==<==>=>>>=<=@?=>>==<<<;;:;:9=<<<;;;:==<<;:;:==<;<:;::9998777::898877::898876::8988776654442365553422664534225644333111100...211///..200///--1000...-,,,++))),,,***((-+++*))(,,+*)))'<=>?@@AC<==>??AA;<==??@@:;<==??@CDEEGGHICCDEEGGHACCDEEGGAACCDEEGIKKLMMOOHIKKLLMNHHIJKKLMGHHIIKKKOPQQRRSSOOOPQQRRMNOOOPPQLMMNNOOOTUUVVVVWSSSTTUVUQRRSSSSTPPQQQRRRWWXXXXXXUVVVVVWWTUUUUUVVRSSSSSSTYYYYYWVWWWWVTVVXVUSSTUWXSQRSUVWYXZ[\^_`aYZ\]^_abY[\]_`bbZ[]^_abccdfghjlncdfhikmnceghilmndfghklnnnprstuwwppsttuvxoqstuuxyprsstvwwyzz{{}}yzzz||~}yyz{|{|~xzy{z|||€€€~}}~|~~}}~}|€€~~~||}~}|}{{z}|{{zzzy}|{{zzyx{{zzyxxwzzyxxvutyxxwuutsxwuttsrputtsrqpotsrrponmsrqonnmlonnmlovwnmllrwxylknuvwyykpuvwyyzxyyyz{zzyzz{{{|{yzz||||~{{||~}}}||{z{zyz{{||{{zy~~}{|{{y}}~}{|zzyxwuttspyywvttspzyxuutspzxxuutsppnmkihfgonmkihffpnmkigfepnlkhgfegijlmnprghikmnnpeghjkmnndfghilmnsttvwxyyrsttuvwxprssttvwnpqrsttuzzzz{{{|yyzyzz{zxxyyyzyyuwwxxxyy{|}}{{||{{{{{{zzyyyyyyyzyyyyyyyx{{{{zzzzzzzyyzyyzzyyyyywyxxwxwwwyzyyyxxwyyxxwvvuxwwwuuttvuutttsswuutttsrutttssrqttssrqpossrqpponqponnmljoonmmkjionmmkjihmmmljihghggfdcbbhgfddbbagfedcbbagedccaa`a_^^\\TP`_^]\[XO_^]]\[YO_^^\[ZZPQPPQQRQSOPPQPPV_OPPOQ[__OONU]]__]bacccef`bacccef`bacccef`abbbddegghhhijjggggihjjffhhhihifgghhhhikllkkklkiikkkijjjiiiiihiiiiihhhhkjiihhhgihhhhgffhghgffedggffedccffedcbbaddccbb``ccbaa`_^baa`__]]`_^^^``a^^^^__ab]]__``ab]^^``aaaaaccddefabbddeffbbccefggcccdefghghhhjjkmggiijlllghijkkmmhhjjkllmmnmnnnppmnmoonppnnnnonponnnoonpporrqrqqqoprrrrrpppoooooppooppppnrrppppnnpoponnmmponnnnmlonnnmmljmmmlkihgmlkjihgfljihggfeihhgfedcgfdcbaa_edcba`_^cbba__^]ba`_^]\[^]\[ZYWV][[ZXWVU[ZYWWVTRZYWVUSSQUTRPPNLLSQQONMKJRPNNLJJHOOMKKIHDJHHE??>>IGC?@@??FA??@@@@@AA@@?@@?@@>>>==>??@>>>>?>>?@=>=??>?@?>>===;;;;;<=<<<;;;===<<;;;===<<;;:9:8988679:8988679:898766998977765544333155544222655333216443331111///.--000//---000...,,1///---+,,***(((+++)))'',***((('++*))(''9;;<==??9:;;<=>?99:;<<=>899:;<<=@AACCDDE?@AACCDD??@AABCC=??@@AACFGGHHIJKEEGGGHIIDEEFGGGHCDDEEFGGKKLLMMNNJJKKKLLMHIIKJKKKGHHIIIJKOOOPPPPQMMONOOOOLLLMMMMNJKKKKLLLQQQQQRRPOOPPPPNOOONNMMOPLLLLLMOPPQSTUWXYPRSUVWYZQRTVVXZZRSTVWXY[[\]_`bbc[]^_`acd\]^_abcd\]_`bbceefgjjlnoeghikmmofghilmnnfhhjlmnnprssuuwxqrssuuvwqrrtttvwprrttuuuxyzz{z{{yxyzyzz{wyxyzzyywwwyxxyy||||||{{{zzzzzzzyyyyzyyyyyyyyyxx{{zzzyyxyzyyxxwvyxxwwuutwwuuttsswwuttssruttssrpptssrpoonrrqonnmmqonnmlllnnmlkkntmmljjqtulkinrttvsuvwyzzzuvwyzzz|vwyyzz||xyyz{{{~|{}}}~|~}~~}~}~}~||zz}~}|zz~}~|{{y}~{{zzzyxvtssqzywutsrpyxvutsroyxvttrponnlihgecnmlihfecnmjigfdcmljhgecbdefghjlmddeghhjkccdfghhjbccdfghinnpqrsttmnnpqrsslmnnopqrjllmnnoqtuuvvwwxttttvuvusststttuqrsssttsxxwwxxxxwwwvwwvvutuvttutstttttstwxvvvvuvvuuvttttttttttssttssssrrtttstssrtsssrrqpsrrqppooqqpopnnnrqpponnmponnnnmmnnmnmmlknmmmlkjimlkjihhfljjhhgffjihhggfehhhgffddfedcbb`_ddcbaa`_dcbaa`_^ccaba`^^_]][ZYZS^^\[ZZXV]][[ZZXW^\[ZYYWVNPX\]]^_RZZ[]]^_XYZ\\^^^WYZ[\]]^_abbbcce_abaccdd``abbbcd__ababbcffgghhggeffgfgggdeeefffgdcdeeeeegggghggggggggffeffffeeddeeedddccffeddcbbeddcbbbaccbbba`_bbba`__^b``_]]]^`_^\\]^]_][[\^^^[Z\\]]^_^___abab^_``abbb^_`aaacc__ababbdcddeffggcceegghhddeffhgidefgghhhiiikkmlnhjkllmmniikkmmmnjilkmmmnnnnooononnnooooonnnnnooonnnnmmmmoppnnnonoooonnmnnnnmnmmmmmnmmmlkmnmmlkjimmlkjihhlkjihhgfkiihggfdhgffdcbbgfedcbbafdcbba`_dcbba_^^a`_^][[Z_^^][ZYW^]\ZZYWV][ZYXWVUXWVUSRPPWVTSRPONUSSQPONLSRQOOMKKNLLJIGB@MKJIEABBJJHCABBBIFCBCAABAAAAA@@@AA@AAAA@BBAAAAAABBBBAAA@@??>?@=>@@@??@>>?@@?>@?>@@@?>@?>><=<<;;:><=<<;;:><=<;;;:><=<<:;9:998877599988666:8987766:89777555544222055333111444222105442211000...-,,0//.--,+0/..-,,+//.--,+++**)((''+*))('&&**)((''%*))('&&&7889:;<<77889::;677899:;56778999==???@AA<<=>??@@;<===???:;<<<=>?BBCDDEEEAACBCCDD@@AABBCC??@@AAACGFGGGHHIEEEGFGGGCDDEEEEGBCCCCDDDIIIKKJKKGHHHIIIIGFGHGGFGEEEEEDGGLJKKMOOQHIJLMOPQHIKLNOPRIKKMNOQRRSUVWYZ[STUWXZZ[SUVWXY[\SUVWYZ[\]^_`bbde]^_aacde^^`aabce]__abcdeghijlmmnghijlmmoghhjllnngghjkmmnpqssttuuoqrrsttuooqrrstsoppqrsssvvwwxxxxtuvvuwwwttutuuuuttttttttxxxwwwvuwvuuutttutttttsstssssrrputttssrqsssrrpporrpponnmqoonnmmlponnmmljnnmllkihmlkkihhmkjihhimoijosttvwjprstuwxprstuvwxrssuuwyyxyyz{{}}yzzz|}~}zz{{{~}yzz|}~}~~~~}}~~}}|zzy~}}|{zzy}}|{zyyx}|{zyyxwywutsronxvttrponwutsronmutsrpnmlmkihfdcbljhgfd^TkihfdYTSjhg`VVTTW`bcefghS\bbdefgTVbbcdefTTabbcdeiiklmmnoghjklmmnghhijlmmfghhijkloqqrqsssnoopqqqrnnnnooppmmnmnnnosssssssrrqrrrrrqqqqpppoooooonnnnsrrrqppopqpoooonpnonnnnmnnmmmmlloonnnnmmnmmmmmllmmmllkkjlljkiiihmllkjihhkkiihhggiihhgggghhhggffegggfeddcgffeddcbfeddccbaeddccbabcbb``_^^bba`_^]]ba`__^^\a`__^^][][[ZZXWV\[ZYYWWV\ZZZXWWU[ZZYWWVVUZZ[[]^^UYY[[\]]VWZZ[\]^UUYYZ[[]^_`ababc^_``abab]^_``aab^]^^__`accdccddcbcbcccccaabbbbbbaabbbbbbcddcccbacccbbaaababba``_aa``___^ba`__^\Z`__^]ZYZ_^^\YZY[]]YXZZZZ[[[\^]^_Z\\]]^__[[]^]^_`\\]^^__```aabccc_ababcdd`abbcccdababcddedfffhgihefggghhjfffhghijegghgiijjklllmlmikljmmmlikkkllmmijllkkmmmnnnnnnnmmnmmmmlmmlllmllmmlklkkkmmlmlkkimllkjiihkjjiihhgjihhggffihhgfedchgffdccbffddcbaaedcbba`_bba`_^]\aa_^]]\Z`_^]\[ZY^^][[ZYW[ZYWWUTSZYWVUSSQXVVUSRPPVUTRRPONQQONLLJHPNNLKJGCOMKKIFCDLKJHDDDDDDDDDDDCBBBBCCDCDCCCBCBCDDDDDCBCABBBBAAADBBBBA@ADDBBBBAACDCABBAAA?@@>@?>A?@@>@?>A@@@>@>=A@@@>@=>=<=<<::9===;;;::==<<;;99<<<<::9999886665998776558886665498776554433221004422110/3322100/422110///..-,,+*/.--,++*..-,,+**.--,++*)*)((''%%))('&&&$)((''%%%)(''&&$$556678893456677833455677233455569:;;<<<=99::;;<<8889::;;6788899:=????@@A<==>????<<====>?:;;<<<<=AABCBCDC@@@@AAAB>????@@@==>?>???CCDDDEFHCBACDEGH@@CCEGGI@ABDEFHIIJLMOPQSIKLMOPRSKKMOOQRSJLMNPQRTTVVWYZ[]TUWXZZ\]UVWXZ[\]UVWYY[\^]_`bbcce^_`bbcce^_`bbbde^_`bacddghhikkmnfghijkmmfggijkkmffhhhiklnnpoqqrrnnooopqpmnmnonoollmnmmnnrsssssssqqqqqqppoooooooonnnnnmnmqrrqppooqooonnnmnnnnmmllmmllljjinnmmllkimlljjihhjjihhhgfihhggffeihggjnoqggglnoprfhmmnorsilmnoqrssstuwxxzsttvwyyzttuvxxzyttvxxxzyz{|{}}}~z{|{}}~}{{|{{}~~{{{|{{|}~}}~|~}}}~}{|~~~}{|{{|{||{{zy|{zyyxwvzzzyxwvtzzyxwvtsyyxvutsrtsrpomljsrqonmkirqonmkh\qonmlcXWhgZUVUUUbWVUVVVTVWWVVVUUWVWWUVVVSS]`bbcdTSY``bbcUSU_`abbTTT^_`abeffghhijddefgghiccdefgggbccdeefgklmmmmnmijjkllkmhhiiijkkghghhiihnnnnmmmmmmmmmklljjjjkkkjjjjjhiihmlmlllkklkjkjiiiiijhihhghhhhggggjiihhhghihhghgggggggfffegffeeeddgggffeedffeedddcedddccbbdccbcbbadcbbbbaabbbaba``baba``__baa``_^^___^^]\[__^^]\[[^^^]\[ZZ]^]\\[ZY[YYXWWUUZZYXWVVUZYXWVUUTYXWWVVTTTTYZY[[\TRWYZZ[[SSUXYZZZRRSWXXZY]^]^____[\]^]^^_[\\]]^]]Z[[\\\]]_```````_______^^^^^^^]]]]^^]]]\`___^^^]^^^]]]\Y^]]\\ZVV\[[[WUVV[WXYYY[[WWXZZZZ\WWYZY[[[XXYZZZ\\[]^]^_``\]^^__`a]^]^_``a]^^___abbbbcccdebabbdcdfbbcccdeebbbcddeeffghgiijfgghgiihgfhhghiiggghhhihjjjlllkkjjjikkkkhjjjjjjjiihhhhhhkklkkijjkjjjihhhijhihhhgihhgggffhhgggfedhggfedccgfeddcbbeedcbbb`ccbb`__^baa`_^^]a`__^]\[`_^]][ZZ]\[ZYXWV[ZZYWVUTZYXWVUSSYWVUTSRPUSRQPONLSQQONMKKQPONMLKGOOMLKIEEKJEDCCCCHDEEEEEDDEEEEEEEDDDDEEEEDDDDDCCBDDCDDDCCEEDCDDDDEEDECDDCBCDBBBAACCDCBBAABBDCBBAACBDCBAAAA@@???=>A?????==A?@>?>><@@@>?==<<=;;;::8=<<;;999=<;:::89<<;;999897766543877655447766543377655442322100/.22110//.22100/..2110//--.-,,+**)--,++*)),,,***((-+++)))'(('&%%%#(''&%$$$('&&%%##''&%%$$"222434550122334401122333//0012236677889955667778445556663444555599::;;;<8899::::7788989966777788<<=====?:;;;;?88:;<=?@@ACDEGHI@BCDFGHJABCEGGIKACDEFHIJKLMOPQSTKLMOPRSTKLOOQQSTKMOOQRSTVVWYYZ\^VVXYY[\^VWXYYZ[]VWXYY[\]^_`aaccd^^`aabcc]__abbcc]__`aabcefghhhjjeegghhiidefgghghddeffgggklkmmmmmijkjklllhhiiiiiihghhhhhhmmmmlmllllkjkjjiiiijhhhhhhhhgggfljkiihhhihhhhggfhggfffedffeddcccggffedfifeddcfijdcccghikbbcghiklkmnnprrtlmnoqrssmmnprrttmnoqrssttvvwyyyyuvwwyyyztvvxxxzztuwwyyyzz{{{||||z{z{zzzzzyzzzzzzyzzzyzzy{|z{zyyy{zzyyyxxyzyyxxwuyyxxwuutxwvutsrpvutssrpottsrqonmssrponneonmj]XWXmmeZYYXXj^YZZZYYZYZZZZZYWWVVVUVUXXWWWVVVXXXWWWUVYXXXWVVUUUS[^_`aVUTW^^__VUUT]]^_VVUS[]^^bbbcddeeaaabccdd_`ababcc___`ababffgggghhdeeffgggccddeeeecbcccdcdgggghhhgggggfgggfffffeeeddddddcdgggfgffffffeeeddeeddcdccddcccccbeeddcdccddccccbbcbcbbaabbbabbaaabcbbabbababbaa``baa```__```__^_^a``__^^]`_^_^]^]^^^]^]]\^]^]]\[[^]\[ZZYY\[[[ZYZY\[[ZZZYW[ZZZYXWWXXWVVUTSXWVUUTSRWWUVUSSRWVVUTSSQRRQWWXXYRQPUVWWXRPPSUVWWQPPPUVUVZYZ[[[[\YYZYZZZ[WXXYYZZYVWWWWXXX\[[[\\[[[[[[ZZZZZZZZZYYXXXXXXWUR[ZYUVUWWYVTVVVVXTSTVUVWXSSUUUWWWWYZY[[[\XYZZ[[\]XZYZZ\\]YZY[[[]^^]^^``ab]]___`bb^^^__abb]^^``abbacbdceeeacbdceeebbcdceeebccddddfgggghhghfgfgghhhfggfgghhffgfgfffiiiiihhhggggghhghhhggggffffgffeeghggffedggffeddcfeeddccbeddccbaadccbba`_cbaa`_^^aa`__^^]a__^]]\[^]]\[ZYX]\[ZZYWV[[ZYXWVUZYXWVUTSWVUSSQPOUTSRQOONSSRPONMKRQPONMKJNLKKHEEELKJFEFFFKIEFFFFFFEEEFGGGFFFFEEEDFFFFFFFEFFFFFFFEGFEFFFFFEEEDDDDDDEEEECDDEDEEECDDFEEEECDDCBDCBB@@CBDCBB@ACBDABAA@CCDABAA@@????>=@=><=????>==<@??=><<;<;:::897;;;99987;:::8886;:999877766543327655443166444222555332112000...,11///--,00/..--,00/..-,,,,***(((++*))(''++*))('&+**)(('&&&&%$###'%%%$#""&&$$$##!%%%##""".//00012..///001,-...///,,,-....223344451112233400011122///000115555666634455556243334572222345779:;==?@89:;@A89;<=?@AACDEGHIKCCDFGHIKCCDGGIIKBDEGGIKKLMNPQRSTLMOPQRSULMOPQRSTLMOPQRSTUWXYY[\]UWXYYZ\\VWXYYZ[\VVWXZZ[[^^__abac^^^``abb]]^_``aa]^^___`acdddefffbbcdddeeabcccdccbbabbbbcggggggggefffffeedddddddcccccccbcgfffffeeeeeddcccdcccccbbcbbbaabaddcccbbaccbbabababaaa_bca``_`bbdadfghilmdeghiklmefghikmneghhjlmmmooqsssunoprrtsunoqrrtsuopqqrttttvwwxxyxtvvxwxxytvuvwxxxttvvvuuuyyyyyxyxyyywxxwwwxwvwuuuvvuvttttxwvuutssuuttssrqttssrqpossrpponmrqonmk^Zpnnnd[Z[nmk_[[[[me[[\\\[[ZYZZZZZ[Z[ZYZZZZZ[Z[ZYZ\[[Z[[ZYYYWXWVWVZYXWWWWVZZYXXWVVZZYXWXVWVVUTX[]^VVUTU[\\UVUTTZZ[UVUTSXZZ]^__`aab]^^^__``\\^]^___[\\]^]^^abbbcbccaabaaabb_``aabbb^__`````cccccccbbbbbbbbbbbbbbbbb`aaa````cbbbbaabaaabbbaaaaaa``__`_`_____bbaa``_```___________^^]_^^]]^^]__^_^^]^^^^]^^]]]^^]]\\[]]\\\\[[^]]\[[[[\\\[[[ZY\[Z[ZYZZ[ZZYZZYXZYZYXXWWZZYXXWWVYXWWWVVVXXWVVUVUVVUTSRRQVUTTSRRQUTTSRQQPTTSSQQQPQPOOSTUVPPONRSTTOOOMORSSOONMMQRRVUVVWVWWUUUVUUUUSTTTTTUURRSSSSSSWWWWURRRUUVRQQRSUTPQQQSSQOOQQQSSTTUVVVXXTTVUVWXXSUVUWWWYSUVVWWXYYZZZ\\]^ZYZZ\\^^ZY[[[]^^ZZ[[[]^^]___`abb^^__`abb^^__aabb^^`_aabbbcbdddeebcbcdddebcccddddabcccdcdffefffffeeffffffdedeeedddcccccddffffeedceeddddccdcdccbbbccbbbabacccbaa``bbaa``_^ba``_^^^``__^^]\_^^]\[ZZ^]][[ZYX\[[ZYYWV[ZYYWWVUYWWVUSSRWVUTSRQPVUSSQPPNTSRQPONMPPNMLKHEONMKJHGHMLKIGHGGLKHGGFFFGFHHHHHHHHGGGGGGFFFFFFGGGGGGHGGFHHHGEFFFGHHGGEFFFGGGGGFFGGFHHGFFFEEEECDDFEEEECDCFEEEDCCCFEEDDDDBBCBBA@@?BDBAA@@@CCAB@A??CBAAA@@????===<;??==<<<;??>==<;;@==<<<::;:988866::997765:9887765:888666454442211544322105433111/4422100/0//.--++0...,,,*/.--,++*/.--,++*+)))(''&**(((&&&))('''%%))('&&&$%$$$#"!!%$###"" %$$""!!!$$##!! ++,,----*++++,,,))***+,,(()***++...///00---..///,,,--.-.+,+,,,-.00124567/0134568/0234578002346689:;<=?@A9:;=>?@A9:;?AA@@???>BAA????>>>==;;:9===<;;:9=<<<:::9==;;:999998765548877655488766444876554333322100/43111///22100/..22100/....,,,***--,+++))--,+**)(-,,+**)()(('&%%%)'''&%$$((&&&%$#('&%%%$###"""!!$#"!! ##"" ""!!! ((())))*&'''(())&&'''('(%%&&&'&'*+*++,-/)*)*+,..())*,--/'()+,,.//12355780124467901335679013456799;<=??AC::<=>@@C:;<=?@AC9;<=?@ACCDEGHIKKCDEGHIKKCDEGHIKKCDEGHIIKLMOPQRRSLMOOPQRSLMOOPQRRLMNOOQRRTVVVXXYZTUUVWWYZTTVVWWXYSTUVVVWXZZ[[\]]^YZ[[\[\]ZZZZZ[[\YYYYZZ[Z^]]^^^^^]]^^^^^^[\\\\\\\[[[[[[[[^^^]]]^^^^]]]\\\\\[\\[[[[[Z[[ZZZ]]\\[Z\^\[\ZY[\]ZZWYZ[]^XVXZZ[]^^_aabceg_`abcdef_`bbcdfg_aacdefghhikmmnnhhjlmmnnghjlmmmmhhilmlnnnpoqrqqqnopoqprrooooppppnnoonnnnqqrrrqqpqqqpooonpooonnnmonnnmmlloonnmmljnmmlkkiimlkjihf^jiihha]]ih^]^^^^b]^^^^^^]^^^^^^^^^^^^]^^^^^^^^^^^^^^^^^^^]]^^^^^^_^^^]^^]]\\[\[Z^]]]\\\Z^^^]\[[[^^^]][\[[YZZXWXVZZZYYWXV[ZZZYXXV[ZZZYXXVVVVTTSSVVVVTTRRUVVVTTRRTVVUTTRRRVWWXYZYZVVWWXXYZVUVWWWWXTUVUVWWWZ[[[[\\\ZYZZ[[[ZYYZZYYYZXXXYYYZZ[[\[[[\\[[[[[[Z[ZZZZZZZYZZZZZZZZ[[[[[[[Z[[ZZZYYZYYYZZZYYYYYYXXXXZYYZZZYYZZYYXXXXXXXXXWWVXWWVWWVVXXXXXWWVXWWVVVVVVVVVUUVVUUUVVUUTWVVUVVUUUVVVUUTSUUUTTTSSTSTSSRSRTTTSRSRRTSRSRQQQRSRQRQPPRQRQPQPPQQPPOONNQPPOONNMPPOONNMMOOONNMMLMLKKKJLLLKKKJJJJLKKKIIHILKKIIIHHLLJLLLNOIKJLLLNOJKKLLLNOJKKLLLNONPPQQSSSNPPQQSSSNPPQQSSSOPPQQSSSUUUWWWYZUVUWWWYZUVUWWWYZUVUWWWYYY[[[\]^^Y[Z\\]^^Y[Z\[]^^ZZZ[[\]]^_^__``a]^_^__`_^^__^_``^^^^__^^aabbbbbb``aaaa``_`___```_____^^^aaa``___`_`___^^__^_^^^]^^]]^]\\_^^^]\[[]^]\[[ZY]\[[ZYYX[[ZYYXWWZYYXWVVUYXWVVUTSWWVUTSRQVVUSSRQPSSRQPONMRQPOOMLKQOONLKKJONMLKJHGLKJGGGGHKHGGHHHGGFGGHHHHGHGHGHIIHGHHHIIIHHIIIIIIIIIIIIIIIIIIIIIIIIHGHHHHIIHHGHHHIIIIGHHHIIIIGHHGHGFHHEFEHFGHGFFEGFGHEFEDGFHGFFEDDEDCCCBBEDCDBDAAEDDCCBBADDCCCAAAAA@@??==@@???>===@@??===<=<;;:988<<:::888;;:99977;;:9987777655443666443226654432255533211111//.--100//.--100...,,0//.--,+,+++)))',+**)(((,***)(('++)))'''''&&$$$#&&&%%###'%%%$$""&&$$$##"#!! ""!!!!! " $%$%%&&&#$$$%$%'#"###$&'"""##%&'')*++-./()*+,-./()*+,-.0()*+,-/002245689124456891144578912345789:;<=?@AC:;<=?@@C:;<=?@AA:;<=>@AACDEFHIIKCDEGGHIKCDEGGHIKCCEFGHIJLLMOOPQRKLMOOPPRKLMMOPPQKKMMOOPQRTTUUVVWRSSUVUVWQSSSUVVVQRSSTUUVWXYZYYYZWXXXYYZZWWWXWXXYUVWVWWXWZZ[[[[ZZYZYYYYZZYYYYYYYYWWWWWXXWZZYYYYYVZZYYYWRTXXXXRQSUWWUOPRSUUWXZ[\^^UWYY[\]_VWYZ[]]_VWYZ[]^_`aacdefg`abccegg`bbcdegg`bbcdegghhjlkmmnhhjjkmlmgijjlkmlgiijjlklnmnnnnnmnnnnnnmmllllmmklkkkllkkjnmmmlkkimlljjihhkkiihhgfihhhgffahhge^]]]ggb]\]]^e^\\]]^^[\]]]^^^^^^]^^__^^]^____^^_^____^______^_____^^^_______]______^^^^______^^^^\\\\^^^]]\\\]^^^]\\\]^^^]\\\Z[YZYXXVZ[YZYWXVZZYYYWWWZZZZXWWWVVUTSSQPVVUSSSQPUVUSSRRPUVTTRRQQTTUUVUVVRSTTUUVUQRRSTTUUORRRRSTTVWWWWXXXVVWWWWWWVVUUVVVWTUUVVUUUXXYXXXXXXXWXXXWWVWWWWWWWUUUUUUUUXXXWXWWVWWVWVVVVVVVUUUVVVVVVUUUTVWVVUUVVUUVVVUUTUUUTTSTTTSTTSSRRVUUTTSTTTSTTSSRSSSRRSRRQRRRQQQQQSSRSRRQRSRRQRQQPRRQQPQPPPQQPPOPOQQPQPOOOQPPOPOOOOPOOOONMOOOONMNMOOMMMMLLNNMLLKKKMMMLKKKKLLLLKKKIKKIIHHGIKJIHHGGHIIHHGGGHIIIHHGGFJJKKLLNOIIKKKMMNIILKKMMMHJJJLLMMOPPQQSSSOPPPQSSSOPPPRRSSOOPPRRRTUVUWWWXZUVUWWWXZUVUWWXXYTVVVVXWYZZZ[[[]]ZY[Z[\\]ZZZZ[\\\ZZYZ[[[[]^^]^^__]^^^^^]]\]]^^^^^[\\\]]]]____^^^]]]]]^^^]^^^]]]\\\\\\\[[[]^]]\\[[]\\[[ZZY[[[ZZZYXZZYZYXWWZYYXWWVVYXWWVUUTWWVUUTSRVUUTSRRQUTSRQPOOSRQPOONMRQPONMLKPOOMMKKJNMKKJGGGLKJHGGGHKIFGGFGHHFGHFGGHHHHGHHIIHHHIHIIIHHIIIIIHHIIIIIHIIIIIIIIIIIIIIIIIHIIIIIIIJJJJHIIIIIIIGHHHIIHHHHHGIIIGHHGFIHHHHHGGFGHEEEEDFHFFEDEDGGEFEDDDHEEEEDCCCDBDAA@@DCCBBA@?CCBBAA@?CCAAA@@?@??==<<;??>=<<<:??>==;;:?===<;;9::988766::988766:998766599877555554422114442220043322100333111//0//.--,+/..-,,,*/..-,,+*/---+++*+*)(((&&**)((''%)))'''&&))((&&&%&%%##"""%%$$""!!$$$##"" %##"""!!!!     !!"$%&' !#$%&&!#$%%' "#$$&'')*+,-/0()*+,./0()*+,./0()*+,./012345789123457891234578902345689:;<=??AA9;<=??@A::<=??@A:;<<=?@ACDEEGGIJCCDEGGHICCDEGGHHBCCDEGHHKKLMNOOPKKKMMOOPIKKLMMOOIJKLLMMPPRRSSSTUPQRRSSTTPPQRRSSSOOPQQQRSVVUVVWVVUUVUUUVVSTTUUVVVSSTTTTUUWWWWWVVVVVVVVVVTVVVVVVPIUUUUVMGIWQMOQRSULLNOQRSVKLNOQRSVLLOOQRSVVWZZ\]^_VXZZ[]^_WXZ[[^^_WXZ[[^^_`bbcdefg`bbcceff`bbccefg`bbbddffhhhjjjkjhgihijjjghghihhhfgggghhhljkkjiihjjiihhhghihhhggfgghggfedhhgffd][gffe`Z\\feb\ZZ\\d_Y[[[[[[\]^^^^][]]^^^]^\]^^^^^^]]^^^^_________`^__^_```__^__```____``````_^____```____^```_^___```_____]^^^]\\[^^^]]\\[]^^^\\\[]^^]][[Z[ZZZXXWV[ZZYXXVV[YYYWWWUZZZXXWVUVUTSSQQQUUSSRRPPVTTRRQQOUTSSQQPPOQQRRRRSOPPPQRQRONPPPPQQOMOOPOPQSTTTTUUUSRSSTSTSRRRRRRRSPQQRQRRRUUVVVUUUTTTTTTSSSSSSSSSSRRRRRRRRUUTTTSSTTSTSSSRRRSRSRRRRRQQQRQQPSSRRRRRQRRRQRQQQRQQQQQPPQQPPOPPORQQQPQPPQQPPPOPOOPPOOOOOOOOOOONMPOPPOOOOOOOOONOMPNOMMNMMMNMMLLMLOOMNMMLMNNMLMLLKLLMLLLLKLLKLKKKKLKKKKKIILKKKJIIHKKKIJIHHKIJIHIHGHIHHGGFEHGHGGFFEGHGGFFEEGFGFFEEDHJKKLLLMHIIKKLLNFIIKKKMMDIJKKLLMPOOQQRRTNOOQQQSSOOPPQRRSMOOPPRRRTUVVWWWXSUVUVVXWTTVVVWWXSTUUUVWWYYZYZZZ[XYYZYZ[[XYYZZZYZXWXYYZYZ[\\[[[[\ZZZ[[[[ZZZZZZZZZZZZZZYZZ\[[[ZZZY[[ZZYZZYYYZZYYXWYYXXXWWVZYXXWWVUXWWWVUUTWVVUUTSSVVUTSSRQUTSSRQPOSSRQPOOORQPPONMLQPOOMMLKONMLKJIFMLKKJHEFKKJIFDEFJIHDDEEFEEHGGHHGFGGFHHHHEHGGHHGIFHFGHHHHHIIIIHIIHIIIHIIJIIIIIIJJIIIHJJJJJJJJHIIIJJJIIIIIJJJIIIIHJJIIIIIHIIGHGGFHIHHHGFGGHGHHGGGEGHHGGHEFFFEDECDBEFDEDDCCFEEDDCCBEEDCCCCBDAA@@@??BB@@???>BA@???>=AA@???>====<;;:9=<<;:::8<<<;::98<<;::99888776554886664448766544376554332422110//221000..22100/..110//.--.--,+***.,,,+**)-,+++)))-+++*)((((('&%%%('''&%$$('&&&%$#('&%%%$$$$""!! $##"" #"""!! ""!!   "#$%&'!"##%&' "#$%&' "#$%&'()*+,./0()*+,./0()*+,./0()*+,-/012445678114456781224567812345568:;<==?@A9:;==??@9:;<=??@89:<<=?@ACCDEGGHACCDEEGGAACDDEGGAACCDEEGHJKKLMMNHIJKKLMMGIIJKKLMGHHJKKLLOOOPPQRRNOOPPQQQMNPOPPPQLMMOOOOPRSSSTTSSRRRSRRSSQQRQRRRRPPPQQRRQSSSTMFGISSSNDGGISSRDDGGIQRGCDGGIKLOOQRSVKLNOQRSVKLNOPRSVKLNOQRSUWXZ[[^^_WXY[\]^_VXZZ\]]_VWZZ[]]_`bbbddee`aacccde_abbbdcd`abaccdcgfgghhhgefgfffggefefffeeddeeeeddgggfeedbffeedd^YeddcaYXYccc\WWYZZYY[Z[\\ZZZ[Z\[\ZZZ[[[[]ZZZ[[\\\\^^^^^__]]^^]___]^^^^___^^^^^____^``````___`````__``````__`````````___^^``_^___]______^^_^___^^^^^]]\\[[^^]][\ZZ^^]\\[[Z^]\[[ZZZZYYXWWVVYZXXWVUUYYXWWVVUYXXWVVUTUSSRRPPOTSSQQPPOSSRQQPOOSSQQPOONOMNOOOOONMLNNOOONMKLMNMOMLKLLLMMPPQQQQQQOPPOPPPQOOOOOPPPMMOOOOOORRRRRRQQQQQQQQQQPOOOOPPPNOOOONOOQQQPPQPPPPPPOOPOPPOOOOOOOOPOONMMOPPOOOOOOOOONOMMNOMMNMMLMMMLLMLLNOMMNMMMNMMLLMLLMMLLLKLLKKLKKKKKLMMLLLKLLKKLKKKKKKKKKKJKKKKKIIJJLKKKKKKIKKKKIIJIJIJJIIHIIIHHIHHGJIIIHHHGHIHHGGGGHHGHGGGFGGGGGGEFGHFFEEDCGEFEEDCCEEEEDCCCEDEDDCCCCHIIKKLLCEHJKKKMCDIIJKLLAAHIIKKKNOOOQQQSMNOPPPRRMMOOOQQQMMNOOPQQSTTUUUVWRSSUVVUVRRTTUUUUQSSTSTUVWXWXXYYYWVWXXWWWVVWVWWWWVUUVVVWWYYYYYYXXXXXWXWWWWWWWVWVVVVVVUUUUXXWWVVUUWVVUVUTTUVUUTSSRUTTSSRRQUTSSRQQPSSRQQPONRQQPOONMPPOONMLKOONMLKKINMLKJJIHLKKJIIEAKKIHGBAAIECCEDFFDBDCEDFEDBDCEDFEDBDCEDFEGGFHHGIIGGGHHGIIHGGHHGIIHGGHHGIIIIIHJJJIIIIHIJJIIIIIHHHIIIIIIIIIJIIIIIIHHIIIIIHHIIIIIHHGIIIHHHHGHGGGHFFEGGFHFFEDGFGFFEDEFGFFEDEDDDCCCCAADCCCCAAACDBCAA@@DCCAA@@?A@???===@@??===<@??===<;??==<<;:<;;99987;;:98877;:988776:988866676554432655442215443222054432210110//.--10/...,,00/..-,+//.--,++,+***)(',+*)))''++)))('&+*)((('&''%%$$$#'&&$$###&&%%$#""%%%$$##!#"" ""!! !!! !   \ No newline at end of file diff --git a/Gamecube/menu/resources/cntrlClassic.tx b/Gamecube/menu/resources/cntrlClassic.tx new file mode 100644 index 0000000..27fdf07 Binary files /dev/null and b/Gamecube/menu/resources/cntrlClassic.tx differ diff --git a/Gamecube/menu/resources/cntrlEmpty.tx b/Gamecube/menu/resources/cntrlEmpty.tx new file mode 100644 index 0000000..eae4838 Binary files /dev/null and b/Gamecube/menu/resources/cntrlEmpty.tx differ diff --git a/Gamecube/menu/resources/cntrlGC.tx b/Gamecube/menu/resources/cntrlGC.tx new file mode 100644 index 0000000..75d22f2 Binary files /dev/null and b/Gamecube/menu/resources/cntrlGC.tx differ diff --git a/Gamecube/menu/resources/cntrlWM.tx b/Gamecube/menu/resources/cntrlWM.tx new file mode 100644 index 0000000..e27034d Binary files /dev/null and b/Gamecube/menu/resources/cntrlWM.tx differ diff --git a/Gamecube/menu/resources/cntrlWNC.tx b/Gamecube/menu/resources/cntrlWNC.tx new file mode 100644 index 0000000..26c4fb6 Binary files /dev/null and b/Gamecube/menu/resources/cntrlWNC.tx differ diff --git a/Gamecube/menu/resources/cubeSX.tx b/Gamecube/menu/resources/cubeSX.tx new file mode 100644 index 0000000..05e92b7 Binary files /dev/null and b/Gamecube/menu/resources/cubeSX.tx differ diff --git a/Gamecube/menu/resources/psxCntrl.tx b/Gamecube/menu/resources/psxCntrl.tx new file mode 100644 index 0000000..181b3a3 Binary files /dev/null and b/Gamecube/menu/resources/psxCntrl.tx differ diff --git a/Gamecube/menu/resources/wiiSX.tx b/Gamecube/menu/resources/wiiSX.tx new file mode 100644 index 0000000..ec84311 Binary files /dev/null and b/Gamecube/menu/resources/wiiSX.tx differ diff --git a/Gamecube/plugins.c b/Gamecube/plugins.c new file mode 100644 index 0000000..87cbbc1 --- /dev/null +++ b/Gamecube/plugins.c @@ -0,0 +1,523 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#define EXT +#include "../psxcommon.h" +#include "GamecubePlugins.h" +#define CheckErr(func) \ + err = SysLibError(); \ + if (err != NULL) { SysPrintf("Error loading %s: %s\n", func, err); return -1; } + +#define LoadSym(dest, src, name, checkerr) \ + dest = (src) SysLoadSym(drv, name); if (checkerr == 1) CheckErr(name); \ + if (checkerr == 2) { err = SysLibError(); if (err != NULL) errval = 1; } + +static const char *err; +static int errval; +void *hGPUDriver; + +void ConfigurePlugins(); + +#if 0 // These are actually in the GPU plugin (and probably work in there ) +void CALLBACK GPU__readDataMem(unsigned long *pMem, int iSize) { + while (iSize > 0) { + *pMem = GPU_readData(); + *pMem = SWAP32(*pMem); + iSize--; + pMem++; + } +} + +void CALLBACK GPU__writeDataMem(unsigned long *pMem, int iSize) { + while (iSize > 0) { + GPU_writeData(SWAP32(*pMem)); + iSize--; + pMem++; + } +} + +void CALLBACK GPU__displayText(char *pText) { + SysPrintf("%s\n", pText); +} +#endif + +long CALLBACK GPU__configure(void) { return 0; } +long CALLBACK GPU__test(void) { return 0; } +void CALLBACK GPU__about(void) {} +void CALLBACK GPU__makeSnapshot(void) {} +void CALLBACK GPU__keypressed(int key) {} +long CALLBACK GPU__getScreenPic(unsigned char *pMem) { return -1; } +long CALLBACK GPU__showScreenPic(unsigned char *pMem) { return -1; } +void CALLBACK GPU__clearDynarec(void (CALLBACK *callback)(void)) { } + +#define LoadGpuSym1(dest, name) \ + LoadSym(GPU_##dest, GPU##dest, name, 1); + +#define LoadGpuSym0(dest, name) \ + LoadSym(GPU_##dest, GPU##dest, name, 0); \ + if (GPU_##dest == NULL) GPU_##dest = (GPU##dest) GPU__##dest; + +#define LoadGpuSymN(dest, name) \ + LoadSym(GPU_##dest, GPU##dest, name, 0); + +int LoadGPUplugin(char *GPUdll) { + void *drv; + + hGPUDriver = SysLoadLibrary(GPUdll); + if (hGPUDriver == NULL) { + GPU_configure = NULL; + SysPrintf ("Could Not Load GPU Plugin %s\n", GPUdll); return -1; + } +// SysPrintf ("hGPUDriver = %d\n", hGPUDriver); + drv = hGPUDriver; + LoadGpuSym1(init, "GPUinit"); + LoadGpuSym1(shutdown, "GPUshutdown"); + LoadGpuSym1(open, "GPUopen"); + LoadGpuSym1(close, "GPUclose"); + LoadGpuSym1(readData, "GPUreadData"); + LoadGpuSym1(readDataMem, "GPUreadDataMem"); + LoadGpuSym1(readStatus, "GPUreadStatus"); + LoadGpuSym1(writeData, "GPUwriteData"); + LoadGpuSym1(writeDataMem, "GPUwriteDataMem"); + LoadGpuSym1(writeStatus, "GPUwriteStatus"); + LoadGpuSym1(dmaChain, "GPUdmaChain"); + LoadGpuSym1(updateLace, "GPUupdateLace"); + LoadGpuSym0(keypressed, "GPUkeypressed"); + LoadGpuSym1(displayText, "GPUdisplayText"); + LoadGpuSym0(makeSnapshot, "GPUmakeSnapshot"); + LoadGpuSym1(freeze, "GPUfreeze"); + LoadGpuSym0(getScreenPic, "GPUgetScreenPic"); + LoadGpuSym0(showScreenPic, "GPUshowScreenPic"); + LoadGpuSym0(clearDynarec, "GPUclearDynarec"); + LoadGpuSym0(configure, "GPUconfigure"); + LoadGpuSym0(test, "GPUtest"); + LoadGpuSym0(about, "GPUabout"); + + return 0; +} + +void *hCDRDriver; +long CALLBACK CDR__play(unsigned char *sector); +long CALLBACK CDR__stop(void); +long CALLBACK CDR__getStatus(struct CdrStat *stat); +char* CALLBACK CDR__getDriveLetter(void) { return NULL; } +//unsigned char* CALLBACK CDR__getBufferSub(void) { return NULL; } +long CALLBACK CDR__configure(void) { return 0; } +long CALLBACK CDR__test(void) { return 0; } +void CALLBACK CDR__about(void) {} + +#define LoadCdrSym1(dest, name) \ + LoadSym(CDR_##dest, CDR##dest, name, 1); + +#define LoadCdrSym0(dest, name) \ + LoadSym(CDR_##dest, CDR##dest, name, 0); \ + if (CDR_##dest == NULL) CDR_##dest = (CDR##dest) CDR__##dest; + +#define LoadCdrSymN(dest, name) \ + LoadSym(CDR_##dest, CDR##dest, name, 0); + +int LoadCDRplugin(char *CDRdll) { + void *drv; + + hCDRDriver = SysLoadLibrary(CDRdll); + if (hCDRDriver == NULL) { + CDR_configure = NULL; + SysPrintf ("Could Not load CDR plugin %s\n", CDRdll); return -1; + } + drv = hCDRDriver; + LoadCdrSym1(init, "CDRinit"); + LoadCdrSym1(shutdown, "CDRshutdown"); + LoadCdrSym1(open, "CDRopen"); + LoadCdrSym1(close, "CDRclose"); + LoadCdrSym1(getTN, "CDRgetTN"); + LoadCdrSym1(getTD, "CDRgetTD"); + LoadCdrSym1(readTrack, "CDRreadTrack"); + LoadCdrSym1(getBuffer, "CDRgetBuffer"); + LoadCdrSym1(play, "CDRplay"); + LoadCdrSym1(stop, "CDRstop"); + LoadCdrSym1(getStatus, "CDRgetStatus"); + LoadCdrSym0(getDriveLetter, "CDRgetDriveLetter"); + LoadCdrSym1(getBufferSub, "CDRgetBufferSub"); + LoadCdrSym0(configure, "CDRconfigure"); + LoadCdrSym0(test, "CDRtest"); + LoadCdrSym0(about, "CDRabout"); + + return 0; +} + +void *hSPUDriver; + +long CALLBACK SPU__configure(void) { return 0; } +void CALLBACK SPU__about(void) {} +long CALLBACK SPU__test(void) { return 0; } + +#define LoadSpuSym1(dest, name) \ + LoadSym(SPU_##dest, SPU##dest, name, 1); + +#define LoadSpuSym2(dest, name) \ + LoadSym(SPU_##dest, SPU##dest, name, 2); + +#define LoadSpuSym0(dest, name) \ + LoadSym(SPU_##dest, SPU##dest, name, 0); \ + if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest; + +#define LoadSpuSymE(dest, name) \ + LoadSym(SPU_##dest, SPU##dest, name, errval); \ + if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest; + +#define LoadSpuSymN(dest, name) \ + LoadSym(SPU_##dest, SPU##dest, name, 0); \ + +int LoadSPUplugin(char *SPUdll) { + void *drv; + + hSPUDriver = SysLoadLibrary(SPUdll); + if (hSPUDriver == NULL) { + SPU_configure = NULL; + SysPrintf ("Could not open SPU plugin %s\n", SPUdll); return -1; + } + drv = hSPUDriver; + LoadSpuSym1(init, "SPUinit"); + LoadSpuSym1(shutdown, "SPUshutdown"); + LoadSpuSym1(open, "SPUopen"); + LoadSpuSym1(close, "SPUclose"); + LoadSpuSym0(configure, "SPUconfigure"); + LoadSpuSym0(about, "SPUabout"); + LoadSpuSym0(test, "SPUtest"); + errval = 0; + LoadSpuSym1(writeRegister, "SPUwriteRegister"); + LoadSpuSym1(readRegister, "SPUreadRegister"); + LoadSpuSym1(writeDMA, "SPUwriteDMA"); + LoadSpuSym1(readDMA, "SPUreadDMA"); + LoadSpuSym1(writeDMAMem, "SPUwriteDMAMem"); + LoadSpuSym1(readDMAMem, "SPUreadDMAMem"); + LoadSpuSym1(playADPCMchannel, "SPUplayADPCMchannel"); + LoadSpuSym1(freeze, "SPUfreeze"); + LoadSpuSym1(async, "SPUasync"); + LoadSpuSym1(registerCallback, "SPUregisterCallback"); + LoadSpuSym1(registerCDDAVolume, "SPUregisterCDDAVolume"); + + return 0; +} + + +void *hPAD1Driver; +void *hPAD2Driver; +/* +static unsigned char buf[256]; +unsigned char stdpar[10] = { 0x00, 0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; +unsigned char mousepar[8] = { 0x00, 0x12, 0x5a, 0xff, 0xff, 0xff, 0xff }; +unsigned char analogpar[9] = { 0x00, 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +static int bufcount, bufc; + +PadDataS padd1, padd2; + +unsigned char _PADstartPoll(PadDataS *pad) { + bufc = 0; + + switch (pad->controllerType) { + case PSE_PAD_TYPE_MOUSE: + mousepar[3] = pad->buttonStatus & 0xff; + mousepar[4] = pad->buttonStatus >> 8; + mousepar[5] = pad->moveX; + mousepar[6] = pad->moveY; + + memcpy(buf, mousepar, 7); + bufcount = 6; + break; + case PSE_PAD_TYPE_NEGCON: // npc101/npc104(slph00001/slph00069) + analogpar[1] = 0x23; + analogpar[3] = pad->buttonStatus & 0xff; + analogpar[4] = pad->buttonStatus >> 8; + analogpar[5] = pad->rightJoyX; + analogpar[6] = pad->rightJoyY; + analogpar[7] = pad->leftJoyX; + analogpar[8] = pad->leftJoyY; + + memcpy(buf, analogpar, 9); + bufcount = 8; + break; + case PSE_PAD_TYPE_ANALOGPAD: // scph1150 + analogpar[1] = 0x73; + analogpar[3] = pad->buttonStatus & 0xff; + analogpar[4] = pad->buttonStatus >> 8; + analogpar[5] = pad->rightJoyX; + analogpar[6] = pad->rightJoyY; + analogpar[7] = pad->leftJoyX; + analogpar[8] = pad->leftJoyY; + + memcpy(buf, analogpar, 9); + bufcount = 8; + break; + case PSE_PAD_TYPE_ANALOGJOY: // scph1110 + analogpar[1] = 0x53; + analogpar[3] = pad->buttonStatus & 0xff; + analogpar[4] = pad->buttonStatus >> 8; + analogpar[5] = pad->rightJoyX; + analogpar[6] = pad->rightJoyY; + analogpar[7] = pad->leftJoyX; + analogpar[8] = pad->leftJoyY; + + memcpy(buf, analogpar, 9); + bufcount = 8; + break; + case PSE_PAD_TYPE_STANDARD: + default: + stdpar[3] = pad->buttonStatus & 0xff; + stdpar[4] = pad->buttonStatus >> 8; + + memcpy(buf, stdpar, 5); + bufcount = 4; + break; + } + + return buf[bufc++]; +} + +unsigned char _PADpoll(unsigned char value) { + if (bufc > bufcount) return 0; + return buf[bufc++]; +} + +unsigned char CALLBACK PAD1__startPoll(int pad) { + PadDataS padd; + + PAD1_readPort1(&padd); + + return _PADstartPoll(&padd); +} + +unsigned char CALLBACK PAD1__poll(unsigned char value) { + return _PADpoll(value); +}*/ + +long CALLBACK PAD1__configure(void) { return 0; } +void CALLBACK PAD1__about(void) {} +long CALLBACK PAD1__test(void) { return 0; } +long CALLBACK PAD1__query(void) { return 3; } +long CALLBACK PAD1__keypressed() { return 0; } + +#define LoadPad1Sym1(dest, name) \ + LoadSym(PAD1_##dest, PAD##dest, name, 1); + +#define LoadPad1SymN(dest, name) \ + LoadSym(PAD1_##dest, PAD##dest, name, 0); + +#define LoadPad1Sym0(dest, name) \ + LoadSym(PAD1_##dest, PAD##dest, name, 0); \ + if (PAD1_##dest == NULL) PAD1_##dest = (PAD##dest) PAD1__##dest; + +int LoadPAD1plugin(char *PAD1dll) { + void *drv; + + hPAD1Driver = SysLoadLibrary(PAD1dll); + if (hPAD1Driver == NULL) { + PAD1_configure = NULL; + SysPrintf ("Could Not load PAD1 plugin %s\n", PAD1dll); return -1; + } + drv = hPAD1Driver; + LoadPad1Sym1(init, "PADinit"); + LoadPad1Sym1(shutdown, "PADshutdown"); + LoadPad1Sym1(open, "PADopen"); + LoadPad1Sym1(close, "PADclose"); + LoadPad1Sym0(query, "PADquery"); + LoadPad1Sym1(readPort1, "PADreadPort1"); + LoadPad1Sym0(configure, "PADconfigure"); + LoadPad1Sym0(test, "PADtest"); + LoadPad1Sym0(about, "PADabout"); + LoadPad1Sym0(keypressed, "PADkeypressed"); + LoadPad1Sym1(startPoll, "PADstartPoll"); + LoadPad1Sym1(poll, "PADpoll"); + LoadPad1SymN(setSensitive, "PADsetSensitive"); + + return 0; +} +/* +unsigned char CALLBACK PAD2__startPoll(int pad) { + PadDataS padd; + + PAD2_readPort2(&padd); + + return _PADstartPoll(&padd); +} + +unsigned char CALLBACK PAD2__poll(unsigned char value) { + return _PADpoll(value); +} +*/ +long CALLBACK PAD2__configure(void) { return 0; } +void CALLBACK PAD2__about(void) {} +long CALLBACK PAD2__test(void) { return 0; } +long CALLBACK PAD2__query(void) { return 3; } +long CALLBACK PAD2__keypressed() { return 0; } + +#define LoadPad2Sym1(dest, name) \ + LoadSym(PAD2_##dest, PAD##dest, name, 1); + +#define LoadPad2Sym0(dest, name) \ + LoadSym(PAD2_##dest, PAD##dest, name, 0); \ + if (PAD2_##dest == NULL) PAD2_##dest = (PAD##dest) PAD2__##dest; + +#define LoadPad2SymN(dest, name) \ + LoadSym(PAD2_##dest, PAD##dest, name, 0); + +int LoadPAD2plugin(char *PAD2dll) { + void *drv; + + hPAD2Driver = SysLoadLibrary(PAD2dll); + if (hPAD2Driver == NULL) { + PAD2_configure = NULL; + SysPrintf ("Could Not load PAD plugin %s\n", PAD2dll); return -1; + } + drv = hPAD2Driver; + LoadPad2Sym1(init, "PADinit"); + LoadPad2Sym1(shutdown, "PADshutdown"); + LoadPad2Sym1(open, "PADopen"); + LoadPad2Sym1(close, "PADclose"); + LoadPad2Sym0(query, "PADquery"); + LoadPad2Sym1(readPort2, "PADreadPort2"); + LoadPad2Sym0(configure, "PADconfigure"); + LoadPad2Sym0(test, "PADtest"); + LoadPad2Sym0(about, "PADabout"); + LoadPad2Sym0(keypressed, "PADkeypressed"); + LoadPad2Sym1(startPoll, "PADstartPoll"); + LoadPad2Sym1(poll, "PADpoll"); + LoadPad2SymN(setSensitive, "PADsetSensitive"); + + return 0; +} + +void *hNETDriver; + +void CALLBACK NET__setInfo(netInfo *info) {} +void CALLBACK NET__keypressed(int key) {} +long CALLBACK NET__configure(void) { return 0; } +long CALLBACK NET__test(void) { return 0; } +void CALLBACK NET__about(void) {} + +#define LoadNetSym1(dest, name) \ + LoadSym(NET_##dest, NET##dest, name, 1); + +#define LoadNetSymN(dest, name) \ + LoadSym(NET_##dest, NET##dest, name, 0); + +#define LoadNetSym0(dest, name) \ + LoadSym(NET_##dest, NET##dest, name, 0); \ + if (NET_##dest == NULL) NET_##dest = (NET##dest) NET__##dest; + +int LoadNETplugin(char *NETdll) { + void *drv; + + hNETDriver = SysLoadLibrary(NETdll); + if (hNETDriver == NULL) { + SysPrintf ("Could Not load NET plugin %s\n", NETdll); return -1; + } + drv = hNETDriver; + LoadNetSym1(init, "NETinit"); + LoadNetSym1(shutdown, "NETshutdown"); + LoadNetSym1(open, "NETopen"); + LoadNetSym1(close, "NETclose"); + LoadNetSymN(sendData, "NETsendData"); + LoadNetSymN(recvData, "NETrecvData"); + LoadNetSym1(sendPadData, "NETsendPadData"); + LoadNetSym1(recvPadData, "NETrecvPadData"); + LoadNetSym1(queryPlayer, "NETqueryPlayer"); + LoadNetSym1(pause, "NETpause"); + LoadNetSym1(resume, "NETresume"); + LoadNetSym0(setInfo, "NETsetInfo"); + LoadNetSym0(keypressed, "NETkeypressed"); + LoadNetSym0(configure, "NETconfigure"); + LoadNetSym0(test, "NETtest"); + LoadNetSym0(about, "NETabout"); + + return 0; +} + +void CALLBACK clearDynarec(void) { + psxCpu->Reset(); +} + +int LoadPlugins() { + + if (LoadCDRplugin("CDR") == -1) return -1; + if (LoadGPUplugin("GPU") == -1) return -1; + if (LoadSPUplugin("SPU") == -1) return -1; + if (LoadPAD1plugin("PAD1") == -1) return -1; + if (LoadPAD2plugin("PAD2") == -1) return -1; + + if (!strcmp("Disabled", Config.Net)) Config.UseNet = 0; + else { + char Plugin[256]; + Config.UseNet = 1; + sprintf(Plugin, "%s%s", Config.PluginsDir, Config.Net); + if (LoadNETplugin(Plugin) == -1) return -1; + } + +#ifndef __MACOSX__ + int ret = CDR_init(); + if (ret < 0) { SysPrintf ("CDRinit error : %d\n", ret); return -1; } + ret = GPU_init(); + if (ret < 0) { SysPrintf ("GPUinit error: %d\n", ret); return -1; } + ret = SPU_init(); + if (ret < 0) { SysPrintf ("SPUinit error: %d\n", ret); return -1; } + ret = PAD1_init(1); + if (ret < 0) { SysPrintf ("PAD1init error: %d\n", ret); return -1; } + ret = PAD2_init(2); + if (ret < 0) { SysPrintf ("PAD2init error: %d\n", ret); return -1; } + if (Config.UseNet) { + ret = NET_init(); + if (ret < 0) { SysPrintf ("NETinit error: %d\n", ret); return -1; } + } +#endif + + return 0; +} + +void ReleasePlugins() { + if (hCDRDriver == NULL || hGPUDriver == NULL || hSPUDriver == NULL || + hPAD1Driver == NULL || hPAD2Driver == NULL) return; + + if (Config.UseNet) { + int ret = NET_close(); + if (ret < 0) Config.UseNet = 0; + NetOpened = 0; + } + +#ifndef __MACOSX__ + CDR_shutdown(); + GPU_shutdown(); + SPU_shutdown(); + PAD1_shutdown(); + PAD2_shutdown(); + if (Config.UseNet && hNETDriver != NULL) NET_shutdown(); +#endif + + SysCloseLibrary(hCDRDriver); hCDRDriver = NULL; + SysCloseLibrary(hGPUDriver); hGPUDriver = NULL; + SysCloseLibrary(hSPUDriver); hSPUDriver = NULL; + SysCloseLibrary(hPAD1Driver); hPAD1Driver = NULL; + SysCloseLibrary(hPAD2Driver); hPAD2Driver = NULL; + if (Config.UseNet && hNETDriver != NULL) { + SysCloseLibrary(hNETDriver); hNETDriver = NULL; + } +} diff --git a/Gamecube/profile.c b/Gamecube/profile.c new file mode 100644 index 0000000..a09b29c --- /dev/null +++ b/Gamecube/profile.c @@ -0,0 +1,91 @@ +/** + * Mupen64 - profile.c + * Copyright (C) 2002 Hacktarux + * + * Mupen64 homepage: http://mupen64.emulation64.com + * email address: hacktarux@yahoo.fr + * + * If you want to contribute to the project please contact + * me first (maybe someone is already making what you are + * planning to do). + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * + * You should have received a copy of the GNU General Public + * Licence along with this program; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, + * USA. + * +**/ + +#include "sys/time.h" +#include "DEBUG.h" + +#ifdef PROFILE + +extern long long gettime(); +extern unsigned int diff_sec(long long, long long); + +static long long time_in_section[NUM_SECTIONS+1]; +static long long last_start[NUM_SECTIONS+1]; +static long long last_refresh; + +void start_section(int section_type) +{ + last_start[section_type] = gettime(); +} + +void end_section(int section_type) +{ + long long end = gettime(); + time_in_section[section_type] += end - last_start[section_type]; +} + +void refresh_stat() +{ + long long this_tick = gettime(); + if(diff_sec(last_refresh, this_tick) >= 1) + { + time_in_section[0] = this_tick - last_start[0]; + + sprintf(txtbuffer, "idle=%f%%", 100.0f * (float)time_in_section[IDLE_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_IDLE); + + sprintf(txtbuffer, "gfx=%f%%", 100.0f * (float)time_in_section[GFX_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_GFX); + + sprintf(txtbuffer, "audio=%f%%", 100.0f * (float)time_in_section[AUDIO_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_AUDIO); + + sprintf(txtbuffer, "tlb=%f%%", 100.0f * (float)time_in_section[TLB_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_TLB); + + sprintf(txtbuffer, "fp=%f%%", 100.0f * (float)time_in_section[FP_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_FP); + + sprintf(txtbuffer, "comp=%f%%", 100.0f * (float)time_in_section[COMPILER_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_COMP); + + sprintf(txtbuffer, "interp=%f%%", 100.0f * (float)time_in_section[INTERP_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_INTERP); + + sprintf(txtbuffer, "tramp=%f%%", 100.0f * (float)time_in_section[TRAMP_SECTION] / (float)time_in_section[0]); + DEBUG_print(txtbuffer, DBG_PROFILE_TRAMP); + + int i; + for(i=1; i<=NUM_SECTIONS; ++i) time_in_section[i] = 0; + last_start[0] = this_tick; + last_refresh = this_tick; + } +} + +#endif diff --git a/Gamecube/release/apps/Makefile b/Gamecube/release/apps/Makefile new file mode 100644 index 0000000..e455a4e --- /dev/null +++ b/Gamecube/release/apps/Makefile @@ -0,0 +1,23 @@ +#Creates a WiiSXR Redistributable +ifndef ECHO +ECHO = echo +endif + +VERSION = beta2.2 + +.PHONY: all + +all: dist + +dist: ../WiiSXRX.dol clean + @$(ECHO) "Making Redistributable..." + @cp ../WiiSXRX.dol apps/WiiSXRX/boot.dol + @mkdir -p \ + wiisxrx/bios \ + wiisxrx/saves \ + wiisxrx/isos + @zip -r ../../WiiSXRX-$(VERSION).zip wiisxrx apps README + +clean: + @$(ECHO) "Cleaning..." + @rm -f apps/WiiSXRX/boot.dol ../../WiiSXRX-*.zip \ No newline at end of file diff --git a/Gamecube/release/apps/README b/Gamecube/release/apps/README new file mode 100644 index 0000000..ac02448 --- /dev/null +++ b/Gamecube/release/apps/README @@ -0,0 +1,170 @@ +README : WiiSXRX / CubeSXRX +Beta 2.2 + +LICENSE: + This software is licensed under the GNU General Public License v2 + which is available at: http://www.gnu.org/licenses/gpl-2.0.txt + This requires any released modifications to be licensed similarly, + and to have the source available. + +QUICK USAGE: + * ISOs can be .bin/.cue (Make sure .cue contains _relative_ directory!), .img, or .iso format + * To install: Extract the contents of WiiSXRX.zip to the root of your SD card + * For SD/USB: Put ISOs (.bin/.cue or other formats) in the directory named /wiisxrx/isos, + All save types will automatically be placed in /wiisxrx/saves + * For DVD: ISOs may be anywhere on the disc (requires DVDxV2 on Wii) + * For actual BIOS: Put SCPH1001.BIN in the directory on SD/USB named /wiisxrx/bios + * Load the executable from the HBC or in the loader of your choice + Once loaded, select 'Load ISO' and choose the source and select the ISO to load + (Note: to go up a directory select '..', B will exit the file browser) + * Select 'Play Game' to play + The game can be exited any time by pressing a configurable key combination together + on a GC pad (START & X), Wii Classic Controller or Pro (HOME), Wiimote (- & +), + Wii U Pro Controller (HOME) + Wiimote+Nunchuck (1 & 2), or the reset button + (Note: this must be done to save your game; it will not be done automatically) + +Controls: + * Controls are now fully configurable so any button on your controller can be mapped + * The controller configuration screen presents each PSX button and allows you to toggle through sources + * There are 4 configuration slots for each type of controller + * To load a different, previously saved configuration, select the slot, and click 'Load' + * After configuring the controls as desired, select the slot, and click 'Save' + * After saving different configurations to the slots, be sure to save your configs in the input tab of the settings frame + * Clicking 'Next Pad' will cycle through the PSX controllers assigned + * There is an option to invert the Y axis of the PSX's analog sticks; by default this is 'Normal Y' + * The 'Menu Combo' configuration allows you to select a button combination to return to the menu + +Settings: + * General + * Native Saves Device: Choose where to load and save native game saves + * Save States Device: Choose where to load and save save states + * Select CPU Core: Choose whether to play games with pure interpreter + (better compatibility) or dynarec (better speed) + * Save settings.cfg: Save all of these settings either SD or USB (to be loaded automatically next time) + * Video + * Show FPS: Display the framerate in the top-left corner of the screen + * Screen Mode: Select the aspect ratio of the display; 'Force 16:9' will pillar-box the in-game display + * Input + * Configure Input: Select controllers to use in game + * Configure Buttons: Enter the controller configuration screen described above + * Save Button Configs: Save all of the controller configuration slots to SD or USB + * Auto Load Slot: Select which slot to automatically be loaded for each type of controller + * Audio + * Disable Audio: Select to mute the sound + * Saves + * Auto Save Native Saves: When enabled, the emulator will automatically load + saves from the selected device on ISO load and save when returning to the menu or + turning off the console + * Copy Saves: Not yet implemented + * Delete Saves: Not yet implemented + +REPORTING ISSUES: + Report any issues to https://github.com/niuus/wiisxrx/issues + +CODE: + Source code can be found here https://github.com/niuus/wiisxrx/ + +CREDITS: + * WiiSXRX fork: NiuuS + * WiiSXRX logo: NiuuS + * WIISXR fork: mystro256 + * WIISXR logo: iiiGerardoiii + * General Coder: emu_kidid + * Graphics & Menu Coder: sepp256 + * Audio & Core Coder: tehpola + * Artwork: drmr + * USB 2.0 support: matguitarist + * LibWUPC integration: Daxtsu + * LibWUPC: https://github.com/FIX94/libwupc + * pcsx team http://www.pcsx.net/ + * pcsx-df http://pcsx-df.sourceforge.net/ + * pcsxr http://pcsxr.codeplex.com/ + * pcsx 1.5-test3 mac version by Gil Pederson http://pcsx.gpost.dk/ + * P.E.Op.S. PSX Gpu & SPU http://sourceforge.net/projects/peops/ + * franspu + * CDRMooby + * SSSPSX + * Compiled using devKitPro + ( http://sourceforge.net/projects/devkitpro ) + * www.emulatemii.com and https://code.google.com/archive/p/pcsxgc/downloads + +OLD CHANGE LOG: +Beta 2.2: + * Very minor speed tweaks (some games are smoother) + * UStealth support + * Fix crashes for a handful of games + * Fix crash when quitting + * Built on lastest devKitPro + * Rebranding to WiiSXR + +Beta 2.1 Mod 6 (Daxtsu): + + LibWupc (support for WiiU Classic Controller Pro) + +Beta 2.1 Mod 4 (matguitarist): + + cIOS no longer required (official IOS58 required) + +Beta 2.1 Mod 3 (matguitarist): + + improved support for USB 2.0 + + support for both USB Port 0 and Port 1 + +Beta 2.1 Mod 2 (matguitarist): + + support for USB 2.0 + +Beta 2.1: + * Compiled with devkitPPC r21 / libOGC SVN + * Compiled with new libDI / DVDx V2 + * Saving improvements + * Fixed issues where save was not written to memcard + + Audio state saved/loaded for save states + * Controller improvements + * Fixed inverted Y-axis on analog input + * Fixed rumble + * Fixed button presses on unused input port + + Added “Home” button as a menu combo for CC + + Added disable rumble setting + * Network improvements + * SMB correction to allow anonymous user and password + + Threaded network init and proper error messages when it fails +Beta 2: + * Compiled with devkitPPC r21 / libOGC SVN + * Compiled with new libDI / DVDx V2 + * DVD reads are now done with direct PowerPC access + + Samba loading + + Execute BIOS + * Controller improvements + + Rumble for Wiimote-based input + + Wiimote-only controls + + Classic Controller Pro & 3rd party controller support + + Reconfigurable button mapping + + Save/Load button mapping from file + + New menu system + + Classic Controller support + + Wiimote / Wiimote & nunchuck support + + Settings saving + + Auto load/save option for saves + * PEOPS GPU + + Pillar-boxing 'Force 16:9' mode + * Fixed color mapping for FMV + + FranSPU + * Smooth stereo audio at full FPS + - PEOPS SPU + + SSSPSX input plugin + + DualShock Controller support + + Rumble support + * Analog/Digital switching + + CDRMooby + * Improved compatibility + * CDDA not implemented yet +Beta 1: + * Working audio (choppy) + * DVD loading + * Software GFX with GX scaling + * Saving to SD card + * Text UI + * Known Issues: + * CDDA audio streaming is not implemented + * XA audio fails at times + * Final Fantasy VII crashes Dynarec + * FPS limit not working at times + diff --git a/Gamecube/release/apps/WiiSXRX/icon.png b/Gamecube/release/apps/WiiSXRX/icon.png new file mode 100644 index 0000000..03ee883 Binary files /dev/null and b/Gamecube/release/apps/WiiSXRX/icon.png differ diff --git a/Gamecube/release/apps/WiiSXRX/meta.xml b/Gamecube/release/apps/WiiSXRX/meta.xml new file mode 100644 index 0000000..ec1f266 --- /dev/null +++ b/Gamecube/release/apps/WiiSXRX/meta.xml @@ -0,0 +1,27 @@ + + + WiiSXRX + NiuuS + 2.2 Beta + 202007090028 + PSX Emulator for Wii + +Featuring: +- Gamecube controller support. +- Wii U Pro controller support. +- Wii U Gamepad controller support through VC injects. +- Wii Classic Controller and Pro support. +- Classic Controllers support (NES / SNES) + +* WiiSX/CubeSX is a PCSX port. The original team was: +emu_kidid - general coding +sepp256 - graphics & menu +tehpola - audio +* Later updates by: +matguitarist +Daxtsu +Mystro256 +FIX94 + + + diff --git a/Gamecube/utils/ehcmodule_elf.h b/Gamecube/utils/ehcmodule_elf.h new file mode 100644 index 0000000..e2729ca --- /dev/null +++ b/Gamecube/utils/ehcmodule_elf.h @@ -0,0 +1,3 @@ +extern const u8 ehcmodule_elf_end[]; +extern const u8 ehcmodule_elf[]; +extern const u32 ehcmodule_elf_size; diff --git a/Gamecube/utils/mload.c b/Gamecube/utils/mload.c new file mode 100644 index 0000000..498a902 --- /dev/null +++ b/Gamecube/utils/mload.c @@ -0,0 +1,277 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HW_RVL + +#include +#include +#include +#include +#include +#include +#include "unistd.h" +#include "ehcmodule_elf.h" + +#define MLOAD_MLOAD_THREAD_ID 0x4D4C4400 +#define MLOAD_LOAD_MODULE 0x4D4C4480 +#define MLOAD_RUN_MODULE 0x4D4C4481 +#define MLOAD_RUN_THREAD 0x4D4C4482 + +#define MLOAD_STOP_THREAD 0x4D4C4484 +#define MLOAD_CONTINUE_THREAD 0x4D4C4485 + +#define MLOAD_GET_LOAD_BASE 0x4D4C4490 +#define MLOAD_MEMSET 0x4D4C4491 + +#define MLOAD_GET_EHCI_DATA 0x4D4C44A0 + +#define MLOAD_SET_ES_IOCTLV 0x4D4C44B0 + +#define getbe32(x) ((adr[x]<<24) | (adr[x+1]<<16) | (adr[x+2]<<8) | (adr[x+3])) + +typedef struct +{ + u32 ident0; + u32 ident1; + u32 ident2; + u32 ident3; + u32 machinetype; + u32 version; + u32 entry; + u32 phoff; + u32 shoff; + u32 flags; + u16 ehsize; + u16 phentsize; + u16 phnum; + u16 shentsize; + u16 shnum; + u16 shtrndx; +} elfheader; + +typedef struct +{ + u32 type; + u32 offset; + u32 vaddr; + u32 paddr; + u32 filesz; + u32 memsz; + u32 flags; + u32 align; +} elfphentry; + +typedef struct +{ + void *start; + int prio; + void *stack; + int size_stack; +} data_elf; + +static const char mload_fs[] ATTRIBUTE_ALIGN(32) = "/dev/mload"; +static s32 mload_fd = -1; +static s32 hid = -1; + +// to init/test if the device is running +int mload_init() +{ + int n; + + if (mload_fd >= 0) + return 0; + + for (n = 0; n < 10; n++) // try 2.5 seconds + { + mload_fd = IOS_Open(mload_fs, 0); + + if (mload_fd >= 0) + break; + + usleep(250 * 1000); + } + + return mload_fd; +} + +// to close the device (remember call it when rebooting the IOS!) +int mload_close() +{ + int ret; + + if (mload_fd < 0) + return -1; + + ret = IOS_Close(mload_fd); + + mload_fd = -1; + + return ret; +} + +// fix starlet address to read/write (uses SEEK_SET, etc as mode) +static int mload_seek(int offset, int mode) +{ + if (mload_init() < 0) + return -1; + return IOS_Seek(mload_fd, offset, mode); +} + +// write bytes from starlet (it update the offset) +static int mload_write(const void * buf, u32 size) +{ + if (mload_init() < 0) + return -1; + return IOS_Write(mload_fd, buf, size); +} + +// fill a block (similar to memset) +static int mload_memset(void *starlet_addr, int set, int len) +{ + int ret; + + if (mload_init() < 0) + return -1; + + if (hid < 0) + hid = iosCreateHeap(0x800); + + if (hid < 0) + return hid; + + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_MEMSET, "iii:", starlet_addr, + set, len); + + return ret; +} + +// load a module from the PPC +// the module must be a elf made with stripios +static int mload_elf(void *my_elf, data_elf *data_elf) +{ + int n, m; + int p; + u8 *adr; + u32 elf = (u32) my_elf; + + if (elf & 3) + return -1; // aligned to 4 please! + + elfheader *head = (void *) elf; + + if (head->ident0 != 0x7F454C46) + return -1; + if (head->ident1 != 0x01020161) + return -1; + if (head->ident2 != 0x01000000) + return -1; + + p = head->phoff; + + data_elf->start = (void *) head->entry; + + for (n = 0; n < head->phnum; n++) + { + elfphentry *entries = (void *) (elf + p); + p += sizeof(elfphentry); + + if (entries->type == 4) + { + adr = (void *) (elf + entries->offset); + + if (getbe32(0) != 0) + return -2; // bad info (sure) + + for (m = 4; m < entries->memsz; m += 8) + { + switch (getbe32(m)) + { + case 0x9: + data_elf->start = (void *) getbe32(m+4); + break; + case 0x7D: + data_elf->prio = getbe32(m+4); + break; + case 0x7E: + data_elf->size_stack = getbe32(m+4); + break; + case 0x7F: + data_elf->stack = (void *) (getbe32(m+4)); + break; + + } + } + } + else if (entries->type == 1 && entries->memsz != 0 && entries->vaddr != 0) + { + + if (mload_memset((void *) entries->vaddr, 0, entries->memsz) < 0) + return -1; + if (mload_seek(entries->vaddr, SEEK_SET) < 0) + return -1; + if (mload_write((void *) (elf + entries->offset), entries->filesz) < 0) + return -1; + } + } + + return 0; +} + +// run one thread (you can use to load modules or binary files) +static int mload_run_thread(void *starlet_addr, void *starlet_top_stack, + int stack_size, int priority) +{ + int ret; + + if (mload_init() < 0) + return -1; + + if (hid < 0) + hid = iosCreateHeap(0x800); + + if (hid < 0) + return hid; + + ret = IOS_IoctlvFormat(hid, mload_fd, MLOAD_RUN_THREAD, "iiii:", + starlet_addr, starlet_top_stack, stack_size, priority); + + return ret; +} + +bool load_ehci_module() +{ + data_elf my_data_elf; + my_data_elf.start = NULL; + my_data_elf.prio = 0; + my_data_elf.stack = NULL; + my_data_elf.size_stack = 0; + + if(mload_elf((void *) ehcmodule_elf, &my_data_elf) != 0) + return false; + + if (mload_run_thread(my_data_elf.start, my_data_elf.stack, + my_data_elf.size_stack, my_data_elf.prio) < 0) + { + usleep(1000); + if (mload_run_thread(my_data_elf.start, my_data_elf.stack, + my_data_elf.size_stack, 0x47) < 0) + return false; + } + return true; +} + +#endif diff --git a/Gamecube/utils/mload.h b/Gamecube/utils/mload.h new file mode 100644 index 0000000..fd52989 --- /dev/null +++ b/Gamecube/utils/mload.h @@ -0,0 +1,33 @@ +/* mload.c (for PPC) (c) 2009, Hermes + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MLOAD_H__ +#define __MLOAD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int mload_init(); +bool load_ehci_module(); +int mload_close(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Gamecube/utils/usb2storage.c b/Gamecube/utils/usb2storage.c new file mode 100644 index 0000000..e31bf7f --- /dev/null +++ b/Gamecube/utils/usb2storage.c @@ -0,0 +1,385 @@ +/**************************************************************************** + * WiiMC + * usb2storage.c -- USB mass storage support, inside starlet + * Copyright (C) 2008 Kwiirk + * Improved for homebrew by rodries and Tantric + * + * IOS 202 and the ehcmodule must be loaded before using this! + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + ***************************************************************************/ + +#ifdef HW_RVL + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG_USB2 + +#ifdef DEBUG_USB2 +#define debug_printf(fmt, args...) \ + fprintf(stderr, "%s:%d:" fmt, __FUNCTION__, __LINE__, ##args) +#else +#define debug_printf(fmt, args...) +#endif // DEBUG_USB2 + +#define UMS_BASE (('U'<<24)|('M'<<16)|('S'<<8)) +#define USB_IOCTL_UMS_INIT (UMS_BASE+0x1) +#define USB_IOCTL_UMS_GET_CAPACITY (UMS_BASE+0x2) +#define USB_IOCTL_UMS_READ_SECTORS (UMS_BASE+0x3) +#define USB_IOCTL_UMS_WRITE_SECTORS (UMS_BASE+0x4) +#define USB_IOCTL_UMS_READ_STRESS (UMS_BASE+0x5) +#define USB_IOCTL_UMS_SET_VERBOSE (UMS_BASE+0x6) +#define USB_IOCTL_UMS_IS_INSERTED (UMS_BASE+0x7) + +#define USB_IOCTL_UMS_UMOUNT (UMS_BASE+0x10) +#define USB_IOCTL_UMS_START (UMS_BASE+0x11) +#define USB_IOCTL_UMS_STOP (UMS_BASE+0x12) +#define USB_IOCTL_UMS_EXIT (UMS_BASE+0x16) + +#define UMS_HEAPSIZE 2*1024 +#define UMS_MAXPATH 16 + +static s32 hId = -1; +static s32 __usb2fd = -1; +static u32 sector_size; +static mutex_t usb2_mutex = LWP_MUTEX_NULL; +static u8 *fixed_buffer = NULL; + +#define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f) +#define USB2_BUFFER 128*1024 +static heap_cntrl usb2_heap; +static u8 __usb2_heap_created = 0; + +static DISC_INTERFACE __io_usb1storage; +static int usb1disc_inited = 0; +extern const DISC_INTERFACE __io_usb2storage; +static int currentMode = 2; // 1 = use USB1 interface, 2 = use USB2 interface + +static s32 USB2CreateHeap() +{ + u32 level; + void *usb2_heap_ptr; + + if (__usb2_heap_created != 0) + return IPC_OK; + + _CPU_ISR_Disable(level); + + usb2_heap_ptr = (void *) ROUNDDOWN32(((u32)SYS_GetArena2Hi() - (USB2_BUFFER+(4*1024)))); + if ((u32) usb2_heap_ptr < (u32) SYS_GetArena2Lo()) + { + _CPU_ISR_Restore(level); + return IPC_ENOMEM; + } + SYS_SetArena2Hi(usb2_heap_ptr); + __lwp_heap_init(&usb2_heap, usb2_heap_ptr, (USB2_BUFFER + (4 * 1024)), 32); + __usb2_heap_created = 1; + _CPU_ISR_Restore(level); + return IPC_OK; +} + +static s32 USB2Storage_Initialize() +{ + static bool inited = false; + + if(inited) + return 0; + + if (usb2_mutex == LWP_MUTEX_NULL) + LWP_MutexInit(&usb2_mutex, false); + + if (hId == -1) + hId = iosCreateHeap(UMS_HEAPSIZE); + + if (hId < 0) + { + debug_printf("error IPC_ENOMEM\n"); + return IPC_ENOMEM; + } + + if (USB2CreateHeap() != IPC_OK) + { + debug_printf("error USB2 IPC_ENOMEM\n"); + return IPC_ENOMEM; + } + + if (fixed_buffer == NULL) + fixed_buffer = __lwp_heap_allocate(&usb2_heap, USB2_BUFFER); + + inited = true; + return 0; +} + +static s32 USB2Storage_Open(int verbose) +{ + s32 ret = USB_OK; + u32 size = 0; + + if(__usb2fd > 0) + return 0; + + if(USB2Storage_Initialize() < 0) + return -1; + + LWP_MutexLock(usb2_mutex); + + if (__usb2fd <= 0) + { + char *devicepath = iosAlloc(hId, UMS_MAXPATH); + if (devicepath == NULL) + { + LWP_MutexUnlock(usb2_mutex); + return IPC_ENOMEM; + } + + snprintf(devicepath, USB_MAXPATH, "/dev/usb2"); + __usb2fd = IOS_Open(devicepath, 0); + iosFree(hId, devicepath); + } + + if(__usb2fd <= 0) + return -1; + + if (verbose) + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_SET_VERBOSE, ":"); + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_INIT, ":"); + debug_printf("usb2 init value: %i\n", ret); + + if (ret < 0) + debug_printf("usb2 error init\n"); + else + size = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_GET_CAPACITY, ":i", + §or_size); + debug_printf("usb2 GET_CAPACITY: %d\n", size); + + if (size == 0) + ret = -2012; + else + ret = 1; + + return ret; +} + +static void USB2Storage_Close() +{ + if(__usb2fd <= 0) + return; + + IOS_Close(__usb2fd); + __usb2fd = -1; +} + +static inline int is_MEM2_buffer(const void *buffer) +{ + u32 high_addr = ((u32) buffer) >> 24; + return (high_addr == 0x90) || (high_addr == 0xD0); +} + +void USB2Enable(bool enable) +{ + if(!usb1disc_inited) + { + usb1disc_inited = 1; + memcpy(&__io_usb1storage, &__io_usbstorage, sizeof(DISC_INTERFACE)); + } + + if(!enable) + { + memcpy(&__io_usbstorage, &__io_usb1storage, sizeof(DISC_INTERFACE)); + } + else + { + USB2Storage_Initialize(); + memcpy(&__io_usbstorage, &__io_usb2storage, sizeof(DISC_INTERFACE)); + } +} + +static bool __usb2storage_Startup(void) +{ + if(__usb2fd > 0) + return true; + + USB2Storage_Open(0); + + if(__usb2fd > 0) + { + currentMode = 2; + return true; + } + + if(__io_usb1storage.startup()) + { + currentMode = 1; + return true; + } + return false; +} + +static bool __usb2storage_IsInserted(void) +{ + if (!__usb2storage_Startup()) + return false; + + if(usb2_mutex == LWP_MUTEX_NULL) + return false; + + if (__usb2fd > 0) + { + LWP_MutexLock(usb2_mutex); + int retval = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_IS_INSERTED, ":"); + LWP_MutexUnlock(usb2_mutex); + debug_printf("isinserted usb2 retval: %d ret: %d\n",retval,ret); + + if (retval > 0) + return true; + } + + if (__io_usb1storage.isInserted() > 0) + { + debug_printf("isinserted usb1 retval: %d\n",retval); + return true; + } + return false; +} + +static bool __usb2storage_ReadSectors(u32 sector, u32 numSectors, void *buffer) +{ + s32 ret = 1; + u32 sectors = 0; + uint8_t *dest = buffer; + + if (currentMode == 1) + return __io_usb1storage.readSectors(sector, numSectors, buffer); + + if (__usb2fd < 1 || usb2_mutex == LWP_MUTEX_NULL) + return false; + + LWP_MutexLock(usb2_mutex); + + while (numSectors > 0) + { + if (numSectors * sector_size > USB2_BUFFER) + sectors = USB2_BUFFER / sector_size; + else + sectors = numSectors; + + if (!is_MEM2_buffer(dest)) //libfat is not providing us good buffers :-( + { + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", + sector, sectors, fixed_buffer, sector_size * sectors); + memcpy(dest, fixed_buffer, sector_size * sectors); + } + else + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_READ_SECTORS, "ii:d", + sector, sectors, dest, sector_size * sectors); + + dest += sector_size * sectors; + if (ret < 1) break; + + sector += sectors; + numSectors -= sectors; + } + if(ret<1) USB2Storage_Close(); + LWP_MutexUnlock(usb2_mutex); + if (ret < 1) return false; + return true; +} + +static bool __usb2storage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) +{ + s32 ret = 1; + u32 sectors = 0; + uint8_t *dest = (uint8_t *) buffer; + + if (currentMode == 1) + return __io_usb1storage.writeSectors(sector, numSectors, buffer); + + if (__usb2fd < 1 || usb2_mutex == LWP_MUTEX_NULL) + return false; + + LWP_MutexLock(usb2_mutex); + while (numSectors > 0 && ret > 0) + { + if (numSectors * sector_size > USB2_BUFFER) + sectors = USB2_BUFFER / sector_size; + else + sectors = numSectors; + + numSectors -= sectors; + + if (!is_MEM2_buffer(dest)) // libfat is not providing us good buffers :-( + { + memcpy(fixed_buffer, dest, sector_size * sectors); + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_WRITE_SECTORS, + "ii:d", sector, sectors, fixed_buffer, sector_size + * sectors); + } + else + ret = IOS_IoctlvFormat(hId, __usb2fd, USB_IOCTL_UMS_WRITE_SECTORS, + "ii:d", sector, sectors, dest, sector_size * sectors); + if (ret < 1)break; + + dest += sector_size * sectors; + sector += sectors; + } + LWP_MutexUnlock(usb2_mutex); + if(ret < 1 ) return false; + return true; +} + +static bool __usb2storage_ClearStatus(void) +{ + if (currentMode == 1) + return __io_usb1storage.clearStatus(); + + return true; +} + +static bool __usb2storage_Shutdown(void) +{ + if (currentMode == 1) + return __io_usb1storage.shutdown(); + + return true; +} + +const DISC_INTERFACE __io_usb2storage = { + DEVICE_TYPE_WII_USB, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP) & __usb2storage_Startup, + (FN_MEDIUM_ISINSERTED) & __usb2storage_IsInserted, + (FN_MEDIUM_READSECTORS) & __usb2storage_ReadSectors, + (FN_MEDIUM_WRITESECTORS) & __usb2storage_WriteSectors, + (FN_MEDIUM_CLEARSTATUS) & __usb2storage_ClearStatus, + (FN_MEDIUM_SHUTDOWN) & __usb2storage_Shutdown +}; + +#endif diff --git a/Gamecube/utils/usb2storage.h b/Gamecube/utils/usb2storage.h new file mode 100644 index 0000000..78bcd5c --- /dev/null +++ b/Gamecube/utils/usb2storage.h @@ -0,0 +1,23 @@ +/**************************************************************************** + * WiiMC + * usb2storage.h -- USB mass storage support, inside starlet + * Copyright (C) 2008 Kwiirk + * Improved for homebrew by rodries and Tantric + * + * IOS 202 and the ehcimodule must be loaded before using this! + ***************************************************************************/ + +#ifndef __USB2STORAGE_H__ +#define __USB2STORAGE_H__ + +#ifdef __cplusplus + extern "C" { +#endif + +void USB2Enable(bool e); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/Gamecube/wiiSXconfig.h b/Gamecube/wiiSXconfig.h new file mode 100644 index 0000000..2da97a5 --- /dev/null +++ b/Gamecube/wiiSXconfig.h @@ -0,0 +1,232 @@ +/** + * WiiSX - wiiSXconfig.h + * Copyright (C) 2007, 2008, 2009, 2010 sepp256 + * + * External declaration and enumeration of config variables + * + * WiiSX homepage: http://www.emulatemii.com + * email address: sepp256@gmail.com + * + * + * This program is free software; you can redistribute it and/ + * or modify it under the terms of the GNU General Public Li- + * cence as published by the Free Software Foundation; either + * version 2 of the Licence, or any later version. + * + * This program is distributed in the hope that it will be use- + * ful, but WITHOUT ANY WARRANTY; without even the implied war- + * ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public Licence for more details. + * +**/ + + +#ifndef WIISXCONFIG_H +#define WIISXCONFIG_H + + +extern char audioEnabled; +enum audioEnabled +{ + AUDIO_DISABLE=0, + AUDIO_ENABLE +}; + +enum ConfigXa //Config.Xa +{ + XA_ENABLE=0, + XA_DISABLE +}; + +enum ConfigCdda //Config.Cdda +{ + CDDA_ENABLE=0, + CDDA_DISABLE +}; + +extern int iVolume; +extern char volume; +enum iVolume +{ + VOLUME_LOUDEST=1, + VOLUME_LOUD, + VOLUME_MEDIUM, + VOLUME_LOW +}; + +extern char showFPSonScreen; +enum showFPSonScreen +{ + FPS_HIDE=0, + FPS_SHOW +}; + +extern char printToScreen; +enum printToScreen +{ + DEBUG_HIDE=0, + DEBUG_SHOW +}; + +extern char printToSD; +enum printToSD +{ + SDLOG_DISABLE=0, + SDLOG_ENABLE +}; + +extern char frameLimit; +enum frameLimit +{ + FRAMELIMIT_NONE=0, + FRAMELIMIT_AUTO, +}; + +extern char frameSkip; +enum frameSkip +{ + FRAMESKIP_DISABLE=0, + FRAMESKIP_ENABLE, +}; + +extern int iUseDither; +enum iUseDither +{ + USEDITHER_NONE=0, + USEDITHER_DEFAULT, + USEDITHER_ALWAYS +}; + +extern char saveEnabled; //??? + +extern char nativeSaveDevice; +enum nativeSaveDevice +{ + NATIVESAVEDEVICE_NONE=-1, + NATIVESAVEDEVICE_SD, + NATIVESAVEDEVICE_USB, + NATIVESAVEDEVICE_CARDA, + NATIVESAVEDEVICE_CARDB +}; + +extern char saveStateDevice; +enum saveStateDevice +{ + SAVESTATEDEVICE_SD=0, + SAVESTATEDEVICE_USB +}; + +extern char autoSave; +enum autoSave +{ + AUTOSAVE_DISABLE=0, + AUTOSAVE_ENABLE +}; + +extern char creditsScrolling; //deprecated? + +extern char dynacore; +enum dynacore +{ + + DYNACORE_DYNAREC=0, + DYNACORE_INTERPRETER, +}; + +extern char biosDevice; +enum biosDevice +{ + BIOSDEVICE_HLE=0, + BIOSDEVICE_SD, + BIOSDEVICE_USB +}; + +extern char LoadCdBios; +enum loadCdBios +{ + BOOTTHRUBIOS_NO=0, + BOOTTHRUBIOS_YES +}; + +extern char screenMode; +enum screenMode +{ + SCREENMODE_4x3=0, + SCREENMODE_16x9, + SCREENMODE_16x9_PILLARBOX +}; + +extern char videoMode; +enum videoMode +{ + VIDEOMODE_AUTO=0, + VIDEOMODE_NTSC, + VIDEOMODE_PAL, + VIDEOMODE_PROGRESSIVE +}; + +extern char fileSortMode; +enum fileSortMode +{ + FILESORT_DIRS_MIXED=0, + FILESORT_DIRS_FIRST +}; + +extern char padAutoAssign; +enum padAutoAssign +{ + PADAUTOASSIGN_MANUAL=0, + PADAUTOASSIGN_AUTOMATIC +}; + +extern char padType[2]; +enum padType +{ + PADTYPE_NONE=0, + PADTYPE_GAMECUBE, + PADTYPE_WII +}; + +extern char padAssign[2]; +enum padAssign +{ + PADASSIGN_INPUT0=0, + PADASSIGN_INPUT1, + PADASSIGN_INPUT2, + PADASSIGN_INPUT3 +}; + +extern char rumbleEnabled; +enum rumbleEnabled +{ + RUMBLE_DISABLE=0, + RUMBLE_ENABLE +}; + +extern char loadButtonSlot; +enum loadButtonSlot +{ + LOADBUTTON_SLOT0=0, + LOADBUTTON_SLOT1, + LOADBUTTON_SLOT2, + LOADBUTTON_SLOT3, + LOADBUTTON_DEFAULT +}; + +extern char controllerType; +enum controllerType +{ + CONTROLLERTYPE_STANDARD=0, + CONTROLLERTYPE_ANALOG, + CONTROLLERTYPE_LIGHTGUN +}; + +extern char numMultitaps; +enum numMultitaps +{ + MULTITAPS_NONE=0, + MULTITAPS_ONE, + MULTITAPS_TWO +}; + +#endif //WIISXCONFIG_H diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..96ccd7b --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +#This is just here for convenience +#Call "make help" for available commands +ifndef ECHO +ECHO = echo +endif + +VERSION = beta2.2 + +.PHONY: all + +all: + @$(ECHO) "Rebuilding Wii and logging to build.log..." + @$(MAKE) -C Gamecube clean -f Makefile_Wii + @$(MAKE) -C Gamecube -f Makefile_Wii 2> temp.log + #This step removes all leading pathes from the build.log + @sed 's|.*wiisxr/Gamecube|/wiisxr/Gamecube|;s|/./|/|;s|\r\n|\n|' temp.log > build.log + #note that msys doesn't seem to like sed -i + @rm temp.log + +Wii: + @$(ECHO) "Building Wii..." + @$(MAKE) -C Gamecube -f Makefile_Wii + +GC: + @$(ECHO) "Building GC..." + @$(MAKE) -C Gamecube -f Makefile_GC + +dist: Wii + @$(MAKE) -C Gamecube/release/ VERSION=$(VERSION) + +clean: + @$(ECHO) "Cleaning..." + @$(MAKE) -C Gamecube clean -f Makefile_Wii + +help: + @$(ECHO) + @$(ECHO) "Available commands:" + @$(ECHO) + @$(ECHO) "make # cleans, rebuilds and log errors (Wii)" + @$(ECHO) "make Wii # build everything (Wii)" + @$(ECHO) "make GC # build everything (Gamecube)" + @$(ECHO) "make clean # clean everything" diff --git a/PeopsGXGPU/cfg.c b/PeopsGXGPU/cfg.c new file mode 100644 index 0000000..154848f --- /dev/null +++ b/PeopsGXGPU/cfg.c @@ -0,0 +1,332 @@ +/*************************************************************************** + * gpu.c - description + * ------------------- + * begin : Fri Feb 8 2016 + * copyright : (C) 2016 Jeremy Newton + * + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +#include "stdafx.h" + +#include "../Gamecube/wiiSXconfig.h" + +#define _IN_CFG + +#include +#undef FALSE +#undef TRUE +#define MAKELONG(low,high) ((unsigned long)(((unsigned short)(low)) | (((unsigned long)((unsigned short)(high))) << 16))) + +#include "externals.h" +#include "cfg.h" +#include "gpu.h" + +///////////////////////////////////////////////////////////////////////////// +// CONFIG FILE helpers.... used in (non-fpse) Linux and ZN Windows +///////////////////////////////////////////////////////////////////////////// + +char * pConfigFile=NULL; + +#include + +// some helper macros: + +#define GetValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') var = atoi(p); \ + } + +#define GetFloatValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') var = (float)atof(p); \ + } + +#define SetValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') { \ + len = sprintf(t1, "%d", var); \ + strncpy(p, t1, len); \ + if (p[len] != ' ' && p[len] != '\n' && p[len] != 0) p[len] = ' '; \ + } \ + } \ + else { \ + size+=sprintf(pB+size, "%s = %d\n", name, var); \ + } + +#define SetFloatValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') { \ + len = sprintf(t1, "%.1f", (float)var); \ + strncpy(p, t1, len); \ + if (p[len] != ' ' && p[len] != '\n' && p[len] != 0) p[len] = ' '; \ + } \ + } \ + else { \ + size+=sprintf(pB+size, "%s = %.1f\n", name, (float)var); \ + } + +///////////////////////////////////////////////////////////////////////////// + +void ReadConfigFile() +{ + struct stat buf; + FILE *in;char t[256]; + int size; + //int len; + char * pB, * p; + + if(pConfigFile) + strcpy(t,pConfigFile); + else + { + strcpy(t,"cfg/gpuPeopsSoftX.cfg"); + in = fopen(t,"rb"); + if (!in) + { + strcpy(t,"gpuPeopsSoftX.cfg"); + in = fopen(t,"rb"); + if(!in) sprintf(t,"%s/gpuPeopsSoftX.cfg",getenv("HOME")); + else fclose(in); + } + else fclose(in); + } + + if (stat(t, &buf) == -1) return; + size = buf.st_size; + + in = fopen(t,"rb"); + if (!in) return; + + pB=(char *)malloc(size); + memset(pB,0,size); + + //len = + fread(pB, 1, size, in); + fclose(in); + + GetValue("ResX", iResX); + if(iResX<20) iResX=20; + iResX=(iResX/4)*4; + + GetValue("ResY", iResY); + if(iResY<20) iResY=20; + iResY=(iResY/4)*4; + + iWinSize=MAKELONG(iResX,iResY); + + GetValue("NoStretch", iUseNoStretchBlt); + + GetValue("Dithering", iUseDither); + + GetValue("ShowFPS", iShowFPS); + if(iShowFPS<0) iShowFPS=0; + if(iShowFPS>1) iShowFPS=1; + + GetValue("SSSPSXLimit", bSSSPSXLimit); + if(iShowFPS<0) iShowFPS=0; + if(iShowFPS>1) iShowFPS=1; + + GetValue("UseFrameLimit", UseFrameLimit); + if(UseFrameLimit<0) UseFrameLimit=0; + if(UseFrameLimit>1) UseFrameLimit=1; + + GetValue("UseFrameSkip", UseFrameSkip); + if(UseFrameSkip<0) UseFrameSkip=0; + if(UseFrameSkip>1) UseFrameSkip=1; + + GetValue("FPSDetection", iFrameLimit); + if(iFrameLimit<1) iFrameLimit=1; + if(iFrameLimit>2) iFrameLimit=2; + + GetFloatValue("FrameRate", fFrameRate); + if(fFrameRate<10.0f) fFrameRate=10.0f; + if(fFrameRate>1000.0f) fFrameRate=1000.0f; + + GetValue("CfgFixes", dwCfgFixes); + + GetValue("UseFixes", iUseFixes); + if(iUseFixes<0) iUseFixes=0; + if(iUseFixes>1) iUseFixes=1; + + free(pB); + +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +void ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgPeopsSoft"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + strcpy(cfg, "./cfg/cfgPeopsSoft"); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + sprintf(cfg, "%s/cfgPeopsSoft", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + sprintf(cfg, "%s %s", cfg, arg); + system(cfg); return; + } + + printf("cfgPeopsSoft file not found!\n"); +} + +void SoftDlgProc(void) +{ + ExecCfg("configure"); +} + +extern unsigned char revision; +extern unsigned char build; +#define RELEASE_DATE "01.05.2008" + +void AboutDlgProc(void) +{ + char args[256]; + + sprintf(args, "about %d %d %s", revision, build, RELEASE_DATE); + ExecCfg(args); +} + + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// + +void ReadConfig(void) +{ + // defaults + iResX=640;iResY=480; + iWinSize=MAKELONG(iResX,iResY); + if (frameLimit == FRAMELIMIT_AUTO) + { + UseFrameLimit=1; + iFrameLimit=2; + } + else + { + UseFrameLimit=0; + iFrameLimit=0; + } + UseFrameSkip = frameSkip; + fFrameRate=60.0f; + dwCfgFixes=0; + iUseFixes=0; + iUseNoStretchBlt=1; + iShowFPS=0; + bSSSPSXLimit=FALSE; + + // read sets + ReadConfigFile(); + + // additional checks + if(iUseFixes) dwActFixes=dwCfgFixes; + SetFixes(); +} + +void WriteConfig(void) { + + struct stat buf; + FILE *out;char t[256];int len, size; + char * pB, * p; char t1[8]; + + if(pConfigFile) + strcpy(t,pConfigFile); + else + { + strcpy(t,"cfg/gpuPeopsSoftX.cfg"); + out = fopen(t,"rb"); + if (!out) + { + strcpy(t,"gpuPeopsSoftX.cfg"); + out = fopen(t,"rb"); + if(!out) sprintf(t,"%s/gpuPeopsSoftX.cfg",getenv("HOME")); + else fclose(out); + } + else fclose(out); + } + + if (stat(t, &buf) != -1) size = buf.st_size; + else size = 0; + + out = fopen(t,"rb"); + if (!out) { + // defaults + iResX=640;iResY=480; + UseFrameLimit=0; + UseFrameSkip=0; + iFrameLimit=2; + fFrameRate=200.0f; + dwCfgFixes=0; + iUseFixes=0; + iUseNoStretchBlt=1; + iUseDither=0; + iShowFPS=0; + bSSSPSXLimit=FALSE; + + size = 0; + pB=(char *)malloc(4096); + memset(pB,0,4096); + } + else { + pB=(char *)malloc(size+4096); + memset(pB,0,size+4096); + + len = fread(pB, 1, size, out); + fclose(out); + } + + SetValue("ResX", iResX); + SetValue("ResY", iResY); + SetValue("NoStretch", iUseNoStretchBlt); + SetValue("Dithering", iUseDither); + SetValue("ShowFPS", iShowFPS); + SetValue("SSSPSXLimit", bSSSPSXLimit); + SetValue("UseFrameLimit", UseFrameLimit); + SetValue("UseFrameSkip", UseFrameSkip); + SetValue("FPSDetection", iFrameLimit); + SetFloatValue("FrameRate", fFrameRate); + SetValue("CfgFixes", (unsigned int)dwCfgFixes); + SetValue("UseFixes", iUseFixes); + + out = fopen(t,"wb"); + if (!out) return; + + len = fwrite(pB, 1, size, out); + fclose(out); + + free(pB); + +} diff --git a/PeopsGXGPU/cfg.h b/PeopsGXGPU/cfg.h new file mode 100644 index 0000000..8cd8cd5 --- /dev/null +++ b/PeopsGXGPU/cfg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + cfg.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_CFG_H_ +#define _GPU_CFG_H_ + +void ReadConfig(void); +void WriteConfig(void); +void ReadWinSizeConfig(void); + +void SoftDlgProc(void); +void AboutDlgProc(void); + +#endif // _GPU_CFG_H_ + diff --git a/PeopsGXGPU/externals.h b/PeopsGXGPU/externals.h new file mode 100644 index 0000000..8fba052 --- /dev/null +++ b/PeopsGXGPU/externals.h @@ -0,0 +1,279 @@ +/*************************************************************************** + externals.h - description + ------------------- + begin : Fri Feb 5 2016 + copyright : (C) 2016 Jeremy Newton + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +#define INFO_TW 0 +#define INFO_DRAWSTART 1 +#define INFO_DRAWEND 2 +#define INFO_DRAWOFF 3 + +#define DATAREGISTERMODES unsigned short + +#define DR_NORMAL 0 +#define DR_VRAMTRANSFER 1 + + +#define GPUSTATUS_ODDLINES 0x80000000 +#define GPUSTATUS_DMABITS 0x60000000 // Two bits +#define GPUSTATUS_READYFORCOMMANDS 0x10000000 +#define GPUSTATUS_READYFORVRAM 0x08000000 +#define GPUSTATUS_IDLE 0x04000000 +#define GPUSTATUS_DISPLAYDISABLED 0x00800000 +#define GPUSTATUS_INTERLACED 0x00400000 +#define GPUSTATUS_RGB24 0x00200000 +#define GPUSTATUS_PAL 0x00100000 +#define GPUSTATUS_DOUBLEHEIGHT 0x00080000 +#define GPUSTATUS_WIDTHBITS 0x00070000 // Three bits +#define GPUSTATUS_MASKENABLED 0x00001000 +#define GPUSTATUS_MASKDRAWN 0x00000800 +#define GPUSTATUS_DRAWINGALLOWED 0x00000400 +#define GPUSTATUS_DITHER 0x00000200 + +#define GPUIsBusy (lGPUstatusRet &= ~GPUSTATUS_IDLE) +#define GPUIsIdle (lGPUstatusRet |= GPUSTATUS_IDLE) + +#define GPUIsNotReadyForCommands (lGPUstatusRet &= ~GPUSTATUS_READYFORCOMMANDS) +#define GPUIsReadyForCommands (lGPUstatusRet |= GPUSTATUS_READYFORCOMMANDS) + +///////////////////////////////////////////////////////////////////////////// + +typedef struct VRAMLOADTAG +{ + short x; + short y; + short Width; + short Height; + short RowsRemaining; + short ColsRemaining; + unsigned short *ImagePtr; +} VRAMLoad_t; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct PSXPOINTTAG +{ + long x; + long y; +} PSXPoint_t; + +typedef struct PSXSPOINTTAG +{ + short x; + short y; +} PSXSPoint_t; + +typedef struct PSXRECTTAG +{ + short x0; + short x1; + short y0; + short y1; +} PSXRect_t; + + +// defines for some windows stuff + +#define FALSE 0 +#define TRUE 1 +#define BOOL unsigned short +#define LOWORD(l) ((unsigned short)(l)) +#define HIWORD(l) ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define DWORD unsigned long +#define __int64 long long int + +typedef struct RECTTAG +{ + int left; + int top; + int right; + int bottom; +}RECT; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct TWINTAG +{ + PSXRect_t Position; +} TWin_t; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct PSXDISPLAYTAG +{ + PSXPoint_t DisplayModeNew; + PSXPoint_t DisplayMode; + PSXPoint_t DisplayPosition; + PSXPoint_t DisplayEnd; + + long Double; + long Height; + long PAL; + long InterlacedNew; + long Interlaced; + long RGB24New; + long RGB24; + PSXSPoint_t DrawOffset; + long Disabled; + PSXRect_t Range; + +} PSXDisplay_t; + +#define dwGPUVersion 0 +#define iGPUHeight 512 +#define iGPUHeightMask 511 +#define GlobalTextIL 0 +#define iTileCheat 0 + +///////////////////////////////////////////////////////////////////////////// + +// draw.c + +#ifndef _IN_DRAW + + +extern char * pCaptionText; + +extern int iResX; +extern int iResY; +extern long GlobalTextAddrX,GlobalTextAddrY,GlobalTextTP; +extern long GlobalTextREST,GlobalTextABR,GlobalTextPAGE; +extern short ly0,lx0,ly1,lx1,ly2,lx2,ly3,lx3; +extern long lLowerpart; +extern BOOL bIsFirstFrame; +extern int iWinSize; +extern BOOL bCheckMask; +extern unsigned short sSetMask; +extern unsigned long lSetMask; +extern BOOL bDeviceOK; +extern short g_m1; +extern short g_m2; +extern short g_m3; +extern short DrawSemiTrans; +extern int iUseGammaVal; +extern int iDesktopCol; +extern int iUseNoStretchBlt; +extern int iShowFPS; +extern int iFastFwd; +extern int iDebugMode; +extern int iFVDisplay; +extern PSXPoint_t ptCursorPoint[]; +extern unsigned short usCursorActive; + +#endif + +// prim.c + +#ifndef _IN_PRIMDRAW + +extern BOOL bUsingTWin; +extern TWin_t TWin; +extern unsigned long clutid; +extern void (*primTableJ[256])(unsigned char *); +extern void (*primTableSkip[256])(unsigned char *); +extern unsigned short usMirror; +extern int iDither; +extern unsigned long dwCfgFixes; +extern unsigned long dwActFixes; +extern unsigned long dwEmuFixes; +extern int iUseFixes; +extern int iUseDither; +extern BOOL bDoVSyncUpdate; +extern long drawX; +extern long drawY; +extern long drawW; +extern long drawH; + +#endif + +// gpu.c + +#ifndef _IN_GPU + +extern VRAMLoad_t VRAMWrite; +extern VRAMLoad_t VRAMRead; +extern DATAREGISTERMODES DataWriteMode; +extern DATAREGISTERMODES DataReadMode; +extern char szDispBuf[]; +extern char szMenuBuf[]; +extern char szDebugText[]; +extern short sDispWidths[]; +extern BOOL bDebugText; +//extern unsigned int iMaxDMACommandCounter; +//extern unsigned long dwDMAChainStop; +extern PSXDisplay_t PSXDisplay; +extern PSXDisplay_t PreviousPSXDisplay; +extern BOOL bSkipNextFrame; +extern long lGPUstatusRet; +extern long drawingLines; +extern unsigned char * psxVSecure; +extern unsigned char * psxVub; +extern signed char * psxVsb; +extern unsigned short * psxVuw; +extern signed short * psxVsw; +extern unsigned long * psxVul; +extern signed long * psxVsl; +extern unsigned short * psxVuw_eom; +extern long lSelectedSlot; +extern DWORD dwLaceCnt; +extern unsigned long lGPUInfoVals[]; +extern unsigned long ulStatusControl[]; +extern int iRumbleVal; +extern int iRumbleTime; + +#endif + +// menu.c + +#ifndef _IN_MENU + +extern unsigned long dwCoreFlags; + +#endif + +// key.c + +#ifndef _IN_KEY + +extern unsigned long ulKeybits; + +#endif + +// fps.c + +#ifndef _IN_FPS + +extern BOOL bInitCap; +extern int UseFrameLimit; +extern int UseFrameSkip; +extern float fFrameRate; +extern int iFrameLimit; +extern float fFrameRateHz; +extern float fps_skip; +extern float fps_cur; +extern BOOL bSSSPSXLimit; + +#endif + +// cfg.c + +#ifndef _IN_CFG + +extern char * pConfigFile; + +#endif diff --git a/PeopsGXGPU/fps.c b/PeopsGXGPU/fps.c new file mode 100644 index 0000000..86268f5 --- /dev/null +++ b/PeopsGXGPU/fps.c @@ -0,0 +1,478 @@ +/*************************************************************************** + fps.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2007/10/27 - Pete +// - Added Nagisa's changes for SSSPSX as a special gpu config option +// +// 2005/04/15 - Pete +// - Changed user frame limit to floating point value +// +// 2003/07/30 - Pete +// - fixed frame limitation if "old skipping method" is used +// +// 2002/12/14 - Pete +// - improved skipping and added some skipping security code +// +// 2002/11/24 - Pete +// - added new frameskip func +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_FPS + +#include "externals.h" +#include "fps.h" +#include "gpu.h" + +#include "../Gamecube/DEBUG.h" + +//////////////////////////////////////////////////////////////////////// +// FPS stuff +//////////////////////////////////////////////////////////////////////// + +#include + +float fFrameRateHz=0; +DWORD dwFrameRateTicks=16; +float fFrameRate; +int iFrameLimit; +int UseFrameLimit=0; +int UseFrameSkip=0; +BOOL bSSSPSXLimit=FALSE; + +//////////////////////////////////////////////////////////////////////// +// FPS skipping / limit +//////////////////////////////////////////////////////////////////////// + +BOOL bInitCap = TRUE; +float fps_skip = 0; +float fps_cur = 0; + +//////////////////////////////////////////////////////////////////////// + +#define MAXLACE 16 + +void CheckFrameRate(void) +{ +#ifdef PROFILE + start_section(IDLE_SECTION); +#endif + if(UseFrameSkip) // skipping mode? + { + if(!(dwActFixes&0x80)) // not old skipping mode? + { + dwLaceCnt++; // -> store cnt of vsync between frames + if(dwLaceCnt>=MAXLACE && UseFrameLimit) // -> if there are many laces without screen toggling, + { // do std frame limitation + if(dwLaceCnt==MAXLACE) bInitCap=TRUE; + + if(bSSSPSXLimit) FrameCapSSSPSX(); + else FrameCap(); + } + } + else + if(UseFrameLimit) + { + if(bSSSPSXLimit) FrameCapSSSPSX(); + else FrameCap(); + } + calcfps(); // -> calc fps display in skipping mode + } + else // non-skipping mode: + { + if(UseFrameLimit) FrameCap(); // -> do it + if(ulKeybits&KEY_SHOWFPS) calcfps(); // -> and calc fps display + } +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif +} + +//////////////////////////////////////////////////////////////////////// + +#define TIMEBASE 100000 + +// prototypes + long long gettime(void); + unsigned int diff_usec(long long start,long long end); + +unsigned long timeGetTime() +{ + long long nowTick = gettime(); + return diff_usec(0,nowTick)/10; +} + +void FrameCap (void) +{ + static unsigned long curticks, lastticks, _ticks_since_last_update; + static unsigned long TicksToWait = 0; + BOOL Waiting = TRUE; + + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + + if((_ticks_since_last_update > TicksToWait) || + (curticks dwFrameRateTicks) + TicksToWait=0; + else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait); +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: No Wait; dwFrameRateTicks %i; TicksToWait %i",(int)dwFrameRateTicks, (int)TicksToWait); +// DEBUG_print(txtbuffer,DBG_GPU2); +#endif //SHOW_DEBUG + } + else + { +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: Wait; dwFRTicks %i; TicksWait %i; TicksSince %i",(int)dwFrameRateTicks, (int)TicksToWait, (int)_ticks_since_last_update); +// DEBUG_print(txtbuffer,DBG_GPU3); +#endif //SHOW_DEBUG + while (Waiting) + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + if ((_ticks_since_last_update > TicksToWait) || + (curticks < lastticks)) + { +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: Done Wait; TicksWait %i; TicksSince %i; cur %i; last %i",(int)TicksToWait, (int)_ticks_since_last_update, (int)curticks, (int)lastticks); +// DEBUG_print(txtbuffer,DBG_GPU3+1); +#endif //SHOW_DEBUG + Waiting = FALSE; + lastticks = curticks; + TicksToWait = dwFrameRateTicks; + } + } + } + } +} + +void FrameCapSSSPSX(void) // frame limit func SSSPSX +{ + static DWORD reqticks, curticks; + static float offset; + +//--------------------------------------------------------- + if(bInitCap) + { + bInitCap=FALSE; + reqticks = curticks = timeGetTime(); + offset = 0; + return; + } +//--------------------------------------------------------- + offset+=1000/fFrameRateHz; + reqticks+=(DWORD)offset; + offset-=(DWORD)offset; + + curticks = timeGetTime(); + if ((signed int)(reqticks - curticks) > 60) + usleep((reqticks - curticks) * 500L); // pete: a simple Sleep doesn't burn 100% cpu cycles, but it isn't as exact as a brute force loop + + if ((signed int)(curticks - reqticks) > 60) + reqticks += (curticks - reqticks) / 2; +} + +//////////////////////////////////////////////////////////////////////// + +#define MAXSKIP 120 + +void FrameSkip(void) +{ + static int iNumSkips=0,iAdditionalSkip=0; // number of additional frames to skip + static DWORD dwLastLace=0; // helper var for frame limitation + static DWORD curticks, lastticks, _ticks_since_last_update; + + if(!dwLaceCnt) return; // important: if no updatelace happened, we ignore it completely + +#ifdef PROFILE + start_section(IDLE_SECTION); +#endif + + if(iNumSkips) // we are in skipping mode? + { + dwLastLace+=dwLaceCnt; // -> calc frame limit helper (number of laces) + bSkipNextFrame = TRUE; // -> we skip next frame + iNumSkips--; // -> ok, one done + } + else // ok, no additional skipping has to be done... + { // we check now, if some limitation is needed, or a new skipping has to get started + DWORD dwWaitTime; + + if(bInitCap || bSkipNextFrame) // first time or we skipped before? + { + if(UseFrameLimit && !bInitCap) // frame limit wanted and not first time called? + { + DWORD dwT=_ticks_since_last_update; // -> that's the time of the last drawn frame + dwLastLace+=dwLaceCnt; // -> and that's the number of updatelace since the start of the last drawn frame + + curticks = timeGetTime(); // -> now we calc the time of the last drawn frame + the time we spent skipping + _ticks_since_last_update= dwT+curticks - lastticks; + + dwWaitTime=dwLastLace*dwFrameRateTicks; // -> and now we calc the time the real psx would have needed + + if(_ticks_since_last_update we were too fast? + { + if((dwWaitTime-_ticks_since_last_update)> // -> some more security, to prevent + (60*dwFrameRateTicks)) // wrong waiting times + _ticks_since_last_update=dwWaitTime; + + while(_ticks_since_last_update loop until we have reached the real psx time + { // (that's the additional limitation, yup) + curticks = timeGetTime(); + _ticks_since_last_update = dwT+curticks - lastticks; + } + } + else // we were still too slow ?!!? + { + if(iAdditionalSkip well, somewhen we really have to stop skipping on very slow systems + { + iAdditionalSkip++; // -> inc our watchdog var + dwLaceCnt=0; // -> reset lace count + lastticks = timeGetTime(); +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif + return; // -> done, we will skip next frame to get more speed + } + } + } + + bInitCap=FALSE; // -> ok, we have inited the frameskip func + iAdditionalSkip=0; // -> init additional skip + bSkipNextFrame=FALSE; // -> we don't skip the next frame + lastticks = timeGetTime(); // -> we store the start time of the next frame + dwLaceCnt=0; // -> and we start to count the laces + dwLastLace=0; + _ticks_since_last_update=0; +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif + return; // -> done, the next frame will get drawn + } + + bSkipNextFrame=FALSE; // init the frame skip signal to 'no skipping' first + + curticks = timeGetTime(); // get the current time (we are now at the end of one drawn frame) + _ticks_since_last_update = curticks - lastticks; + + dwLastLace=dwLaceCnt; // store curr count (frame limitation helper) + dwWaitTime=dwLaceCnt*dwFrameRateTicks; // calc the 'real psx lace time' + + if(_ticks_since_last_update>dwWaitTime) // hey, we needed way too long for that frame... + { + if(UseFrameLimit) // if limitation, we skip just next frame, + { // and decide after, if we need to do more + iNumSkips=0; + } + else + { + iNumSkips=_ticks_since_last_update/dwWaitTime; // -> calc number of frames to skip to catch up + iNumSkips--; // -> since we already skip next frame, one down + if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP; // -> well, somewhere we have to draw a line + } + bSkipNextFrame = TRUE; // -> signal for skipping the next frame + } + else // we were faster than real psx? fine :) + if(UseFrameLimit) // frame limit used? so we wait til the 'real psx time' has been reached + { + if(dwLaceCnt>MAXLACE) // -> security check + _ticks_since_last_update=dwWaitTime; + + while(_ticks_since_last_update just do a waiting loop... + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + } + } + + lastticks = timeGetTime(); // ok, start time of the next frame + } + + dwLaceCnt=0; // init lace counter +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif +} + +//////////////////////////////////////////////////////////////////////// + +void calcfps(void) +{ + static unsigned long curticks,_ticks_since_last_update,lastticks; + static long fps_cnt = 0; + static unsigned long fps_tck = 1; + static long fpsskip_cnt = 0; + static unsigned long fpsskip_tck = 1; + + { + curticks = timeGetTime(); + _ticks_since_last_update=curticks-lastticks; + + if(UseFrameSkip && !UseFrameLimit && _ticks_since_last_update) + fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f)); + + lastticks = curticks; + } + + if(UseFrameSkip && UseFrameLimit) + { + fpsskip_tck += _ticks_since_last_update; + + if(++fpsskip_cnt==2) + { + fps_skip = (float)2000/(float)fpsskip_tck; + fps_skip +=6.0f; + fpsskip_cnt = 0; + fpsskip_tck = 1; + } + } + + fps_tck += _ticks_since_last_update; + + if(++fps_cnt==10) + { + fps_cur = (float)(TIMEBASE*10)/(float)fps_tck; + + fps_cnt = 0; + fps_tck = 1; + + if(UseFrameLimit && fps_cur>fFrameRateHz) // optical adjust ;) avoids flickering fps display + fps_cur=fFrameRateHz; + } + +} + +void PCFrameCap (void) +{ + static unsigned long curticks, lastticks, _ticks_since_last_update; + static unsigned long TicksToWait = 0; + BOOL Waiting = TRUE; + + while (Waiting) + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + if ((_ticks_since_last_update > TicksToWait) || + (curticks < lastticks)) + { + Waiting = FALSE; + lastticks = curticks; + TicksToWait = (TIMEBASE/ (unsigned long)fFrameRateHz); + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void PCcalcfps(void) +{ + static unsigned long curticks,_ticks_since_last_update,lastticks; + static long fps_cnt = 0; + static float fps_acc = 0; + float CurrentFPS=0; + + curticks = timeGetTime(); + _ticks_since_last_update=curticks-lastticks; + if(_ticks_since_last_update) + CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update; + else CurrentFPS = 0; + lastticks = curticks; + + fps_acc += CurrentFPS; + + if(++fps_cnt==10) + { + fps_cur = fps_acc / 10; + fps_acc = 0; + fps_cnt = 0; + } + + fps_skip=CurrentFPS+1.0f; +} + +//////////////////////////////////////////////////////////////////////// + +void SetAutoFrameCap(void) +{ + if(iFrameLimit==1) + { + fFrameRateHz = fFrameRate; + dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); + return; + } + + if(dwActFixes&32) + { + if (PSXDisplay.Interlaced) + fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f; + else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f; + } + else + { + //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f; + if(PSXDisplay.PAL) + { + if (lGPUstatusRet&GPUSTATUS_INTERLACED) + fFrameRateHz=33868800.0f/677343.75f; // 50.00238 + else fFrameRateHz=33868800.0f/680595.00f; // 49.76351 + } + else + { + if (lGPUstatusRet&GPUSTATUS_INTERLACED) + fFrameRateHz=33868800.0f/565031.25f; // 59.94146 + else fFrameRateHz=33868800.0f/566107.50f; // 59.82750 + } +// dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); + dwFrameRateTicks=(unsigned long) (TIMEBASE / fFrameRateHz); + } +} + +//////////////////////////////////////////////////////////////////////// + +void SetFPSHandler(void) +{ +} + +//////////////////////////////////////////////////////////////////////// + +void InitFPS(void) +{ + if(!fFrameRate) fFrameRate=200.0f; + + if(fFrameRateHz==0) + { + if(iFrameLimit==2) fFrameRateHz=59.94f; // auto framerate? set some init val (no pal/ntsc known yet) + else fFrameRateHz=fFrameRate; // else set user framerate + } + + dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); +} + diff --git a/PeopsGXGPU/fps.h b/PeopsGXGPU/fps.h new file mode 100644 index 0000000..9e35a75 --- /dev/null +++ b/PeopsGXGPU/fps.h @@ -0,0 +1,41 @@ +/*************************************************************************** + fps.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _FPS_INTERNALS_H +#define _FPS_INTERNALS_H + +void FrameCap(void); +void FrameCapSSSPSX (void); +void FrameSkip(void); +void calcfps(void); +void PCFrameCap (void); +void PCcalcfps(void); +void SetAutoFrameCap(void); +void SetFPSHandler(void); +void InitFPS(void); +void CheckFrameRate(void); + +#endif // _FPS_INTERNALS_H diff --git a/PeopsGXGPU/gpu.c b/PeopsGXGPU/gpu.c new file mode 100644 index 0000000..e336dd2 --- /dev/null +++ b/PeopsGXGPU/gpu.c @@ -0,0 +1,1516 @@ +/*************************************************************************** + * gpu.c - description + * ------------------- + * begin : Fri Feb 5 2016 + * copyright : (C) 2016 Jeremy Newton + * + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//TODO WIP, lots of stubbed functions +#include "stdafx.h" + +#include "../Gamecube/DEBUG.h" +#include "../Gamecube/wiiSXconfig.h" + +#define _IN_GPU + +#include "externals.h" +#include "gpu.h" +//#include "draw.h" +#include "cfg.h" +//#include "prim.h" +#include "psemu.h" +//#include "menu.h" +#include "fps.h" +#include "swap.h" + +//////////////////////////////////////////////////////////////////////// +// PPDK developer must change libraryName field and can change revision and build +//////////////////////////////////////////////////////////////////////// + +const unsigned char version = 1; // do not touch - library for PSEmu 1.x +const unsigned char revision = 1; +const unsigned char build = 0; + +static char *libraryName = "P.E.Op.S. GX Driver"; +static char *libraryInfo = + "P.E.Op.S. GX Driver V1.0\nCoded by Jeremy Newton, based on code from Pete Bernert and the P.E.Op.S. team\n"; + +static char *PluginAuthor = + "Jeremy Newton, Pete Bernert, and the P.E.Op.S. team"; + +//////////////////////////////////////////////////////////////////////// +// memory image of the PSX vram +//////////////////////////////////////////////////////////////////////// + +unsigned char psxVSecure[(iGPUHeight * 2) * 1024 + (1024 * 1024)]; +unsigned char *psxVub; +signed char *psxVsb; +unsigned short *psxVuw; +unsigned short *psxVuw_eom; +signed short *psxVsw; +unsigned long *psxVul; +signed long *psxVsl; + +//////////////////////////////////////////////////////////////////////// +// GPU globals +//////////////////////////////////////////////////////////////////////// + +static long lGPUdataRet; +long lGPUstatusRet; +char szDispBuf[64]; +char szDebugText[512]; +unsigned long ulStatusControl[256]; + +static unsigned long gpuDataM[256]; +static unsigned char gpuCommand = 0; +static long gpuDataC = 0; +static long gpuDataP = 0; + +unsigned char * pGfxCardScreen = 0; + +VRAMLoad_t VRAMWrite; +VRAMLoad_t VRAMRead; +DATAREGISTERMODES DataWriteMode; +DATAREGISTERMODES DataReadMode; + +BOOL bSkipNextFrame = FALSE; +DWORD dwLaceCnt = 0; + +short sDispWidths[8] = { 256, 320, 512, 640, 368, 384, 512, 640 }; + +PSXDisplay_t PSXDisplay; +PSXDisplay_t PreviousPSXDisplay; +long lSelectedSlot = 0; +unsigned long lGPUInfoVals[16]; +int iFakePrimBusy = 0; +int iRumbleVal = 0; +int iRumbleTime = 0; + +//////////////////////////////////////////////////////////////////////// +// some misc external display funcs +//////////////////////////////////////////////////////////////////////// + +#include +time_t tStart; + +void PEOPS_GPUdisplayText(char * pText) // some debug func +{ + if (!pText) { + szDebugText[0] = 0; + return; + } + if (strlen(pText) > 511) + return; + time(&tStart); + strcpy(szDebugText, pText); +} + +//////////////////////////////////////////////////////////////////////// +// stuff to make this a true PDK module +//////////////////////////////////////////////////////////////////////// + +char * CALLBACK PSEgetLibName(void) { + return libraryName; +} + +unsigned long CALLBACK PSEgetLibType(void) { + return PSE_LT_GPU; +} + +unsigned long CALLBACK PSEgetLibVersion(void) { + return version << 16 | revision << 8 | build; +} + +char * GPUgetLibInfos(void) { + return libraryInfo; +} + +//////////////////////////////////////////////////////////////////////// +// Snapshot func +//////////////////////////////////////////////////////////////////////// + +char * pGetConfigInfos() { + char szO[2][4] = { "off", "on " }; + char szTxt[256]; + char * pB = (char *) malloc(32767); + + if (!pB) + return NULL; + *pB = 0; + //----------------------------------------------------// + sprintf(szTxt, "Plugin: %s %d.%d.%d\r\n", libraryName, version, revision, + build); + strcat(pB, szTxt); + sprintf(szTxt, "Author: %s\r\n\r\n", PluginAuthor); + strcat(pB, szTxt); + //----------------------------------------------------// + sprintf(szTxt, "Resolution/Color:\r\n- %dx%d ", iResX, iResY); + strcat(pB, szTxt); + strcpy(szTxt, "Window mode\r\n"); + strcat(pB, szTxt); + + sprintf(szTxt, "Dither mode: %d\r\n\r\n", iUseDither); + strcat(pB, szTxt); + //----------------------------------------------------// + sprintf(szTxt, "Framerate:\r\n- FPS limit: %s\r\n", szO[UseFrameLimit]); + strcat(pB, szTxt); + sprintf(szTxt, "- Frame skipping: %s", szO[UseFrameSkip]); + strcat(pB, szTxt); + strcat(pB, "\r\n"); + if (iFrameLimit == 2) + strcpy(szTxt, "- FPS limit: Auto\r\n\r\n"); + else + sprintf(szTxt, "- FPS limit: %.1f\r\n\r\n", fFrameRate); + strcat(pB, szTxt); + //----------------------------------------------------// + sprintf(szTxt, "Misc:\r\n- Game fixes: %s [%08lx]\r\n", szO[iUseFixes], + dwCfgFixes); + strcat(pB, szTxt); + //----------------------------------------------------// + return pB; +} + +void DoTextSnapShot(int iNum) { + FILE *txtfile; + char szTxt[256]; + char * pB; + + sprintf(szTxt, "%s/peopsgx%03d.txt", getenv("HOME"), iNum); + + if ((txtfile = fopen(szTxt, "wb")) == NULL) + return; + //----------------------------------------------------// + pB = pGetConfigInfos(); + if (pB) { + fwrite(pB, strlen(pB), 1, txtfile); + free(pB); + } + fclose(txtfile); +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUmakeSnapshot() // snapshot of whole vram +{ + FILE *bmpfile; + char filename[256]; + unsigned char header[0x36]; + long size, height; + unsigned char line[1024 * 3]; + short i, j; + unsigned char empty[2] = { 0, 0 }; + unsigned short color; + unsigned long snapshotnr = 0; + + height = iGPUHeight; + + size = height * 1024 * 3 + 0x38; + + // fill in proper values for BMP + + // hardcoded BMP header + memset(header, 0, 0x36); + header[0] = 'B'; + header[1] = 'M'; + header[2] = size & 0xff; + header[3] = (size >> 8) & 0xff; + header[4] = (size >> 16) & 0xff; + header[5] = (size >> 24) & 0xff; + header[0x0a] = 0x36; + header[0x0e] = 0x28; + header[0x12] = 1024 % 256; + header[0x13] = 1024 / 256; + header[0x16] = height % 256; + header[0x17] = height / 256; + header[0x1a] = 0x01; + header[0x1c] = 0x18; + header[0x26] = 0x12; + header[0x27] = 0x0B; + header[0x2A] = 0x12; + header[0x2B] = 0x0B; + + // increment snapshot value & try to get filename + do { + snapshotnr++; + sprintf(filename, "%s/peopsgx%03ld.bmp", getenv("HOME"), snapshotnr); + + bmpfile = fopen(filename, "rb"); + if (bmpfile == NULL) + break; + fclose(bmpfile); + } while (TRUE); + + // try opening new snapshot file + if ((bmpfile = fopen(filename, "wb")) == NULL) + return; + + fwrite(header, 0x36, 1, bmpfile); + //TODO + //for (i = height - 1; i >= 0; i--) { + // for (j = 0; j < 1024; j++) { + // color = psxVuw[i * 1024 + j]; + // line[j * 3 + 2] = (color << 3) & 0xf1; + // line[j * 3 + 1] = (color >> 2) & 0xf1; + // line[j * 3 + 0] = (color >> 7) & 0xf1; + // } + // fwrite(line, 1024 * 3, 1, bmpfile); + //} + fwrite(empty, 0x2, 1, bmpfile); + fclose(bmpfile); + + DoTextSnapShot(snapshotnr); +} + +//////////////////////////////////////////////////////////////////////// +// GPU Init, init for vars and whatnot +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUinit() { + memset(ulStatusControl, 0, 256 * sizeof(unsigned long)); // init save state scontrol field + + szDebugText[0] = 0; // init debug text buffer + + //!!! ATTENTION !!! + psxVub = psxVSecure + 512 * 1024; // security offset into double sized psx vram! + + psxVsb = (signed char *) psxVub; // different ways of accessing PSX VRAM + psxVsw = (signed short *) psxVub; + psxVsl = (signed long *) psxVub; + psxVuw = (unsigned short *) psxVub; + psxVul = (unsigned long *) psxVub; + + psxVuw_eom = psxVuw + 1024 * iGPUHeight; // pre-calc of end of vram + + memset(psxVSecure, 0x00, (iGPUHeight * 2) * 1024 + (1024 * 1024)); + memset(lGPUInfoVals, 0x00, 16 * sizeof(unsigned long)); + + SetFPSHandler(); + + PSXDisplay.RGB24 = FALSE; // init some stuff + PSXDisplay.Interlaced = FALSE; + PSXDisplay.DrawOffset.x = 0; + PSXDisplay.DrawOffset.y = 0; + PSXDisplay.DisplayMode.x = 320; + PSXDisplay.DisplayMode.y = 240; + + PSXDisplay.Disabled = FALSE; + PreviousPSXDisplay.Range.x0 = 0; + PreviousPSXDisplay.Range.y0 = 0; + PSXDisplay.Range.x0 = 0; + PSXDisplay.Range.x1 = 0; + PreviousPSXDisplay.DisplayModeNew.y = 0; + PSXDisplay.Double = 1; + lGPUdataRet = 0x400; + + DataWriteMode = DR_NORMAL; + + // Reset transfer values, to prevent mis-transfer of data + memset(&VRAMWrite, 0, sizeof(VRAMLoad_t)); + memset(&VRAMRead, 0, sizeof(VRAMLoad_t)); + + // device initialised already ! + lGPUstatusRet = 0x14802000; + GPUIsIdle; + GPUIsReadyForCommands; + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Open GPU, start +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUopen(unsigned long * disp, char * CapText, char * CfgFile) { + unsigned long d; + + pCaptionText = CapText; + + pConfigFile = CfgFile; + + ReadConfig(); // read registry + + iShowFPS = 1; //Default config turns this off.. + InitFPS(); + + bIsFirstFrame = TRUE; + + //TODO + //sysdep_create_display(); + //InitializeTextureStore(); + //GXinitialize(); + d = 0; //ulInitDisplay(); + + if (disp) + *disp = d; + + if (d) + return 0; + return -1; +} + +//////////////////////////////////////////////////////////////////////// +// Close GPU, ending and cleanup +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUclose() { + //TODO + //GXcleanup(); // close GX + + if (pGfxCardScreen) + free(pGfxCardScreen); // free helper memory + pGfxCardScreen = 0; + + //TODO + //CloseDisplay(); // shutdown direct draw + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Shutdown GPU, likely abrupt or on error/fault +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUshutdown() { + //Nothing to do? + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Update display (swap buffers)... called in interlaced mode on +// every emulated vsync, otherwise whenever the displayed screen region +// has been changed + +void updateDisplay(void) { + + //TODO + + if (PSXDisplay.Disabled) // disable? + { + //TODO + } + + if (dwActFixes & 32) // pc fps calculation fix + { + if (UseFrameLimit) + PCFrameCap(); // -> brake + if (UseFrameSkip) + PCcalcfps(); + } + + if (UseFrameSkip) // skip ? + { + //TODO + //if(!bSkipNextFrame) + // DoBufferSwap(); // -> to skip or not to skip + if (dwActFixes & 0xa0) // -> pc fps calculation fix/old skipping fix + { + if ((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) // -> skip max one in a row + { + bSkipNextFrame = TRUE; + fps_skip = fFrameRateHz; + } else + bSkipNextFrame = FALSE; + } else + FrameSkip(); + } else // no skip ? + { + //TODO + } +} + +//////////////////////////////////////////////////////////////////////// +// check if update needed +//////////////////////////////////////////////////////////////////////// + +void ChangeDispOffsetsX(void) // CENTER X +{ + long lx, l; + + if (!PSXDisplay.Range.x1) + return; + + l = PreviousPSXDisplay.DisplayMode.x; //TODO PSXDisplay.DisplayMode + + l *= (long) PSXDisplay.Range.x1; + l /= 2560; + lx = l; + l &= 0xfffffff8; + + if (l == PreviousPSXDisplay.Range.y1) + return; // abusing range.y1 for + PreviousPSXDisplay.Range.y1 = (short) l; // storing last x range and test + + if (lx >= PreviousPSXDisplay.DisplayMode.x) { + PreviousPSXDisplay.Range.x1 = (short) PreviousPSXDisplay.DisplayMode.x; + PreviousPSXDisplay.Range.x0 = 0; + } else { + PreviousPSXDisplay.Range.x1 = (short) l; + + PreviousPSXDisplay.Range.x0 = (PSXDisplay.Range.x0 - 500) / 8; + + if (PreviousPSXDisplay.Range.x0 < 0) + PreviousPSXDisplay.Range.x0 = 0; + + if ((PreviousPSXDisplay.Range.x0 + lx) + > PreviousPSXDisplay.DisplayMode.x) //TODO PSXDisplay.DisplayMode + { + PreviousPSXDisplay.Range.x0 = + (short) (PreviousPSXDisplay.DisplayMode.x - lx); //TODO PSXDisplay.DisplayMode + PreviousPSXDisplay.Range.x0 += 2; //TODO ??? + + PreviousPSXDisplay.Range.x1 += (short) (lx - l); //TODO ??? + PreviousPSXDisplay.Range.x1 -= 2; // makes stretching easier + } + + // some alignment security TODO Needed? + PreviousPSXDisplay.Range.x0 = PreviousPSXDisplay.Range.x0 >> 1; + PreviousPSXDisplay.Range.x0 = PreviousPSXDisplay.Range.x0 << 1; + PreviousPSXDisplay.Range.x1 = PreviousPSXDisplay.Range.x1 >> 1; + PreviousPSXDisplay.Range.x1 = PreviousPSXDisplay.Range.x1 << 1; + + //TODO + //DoClearScreenBuffer(); + } + + bDoVSyncUpdate = TRUE; +} + +//////////////////////////////////////////////////////////////////////// + +void ChangeDispOffsetsY(void) { + //TODO +} + +//////////////////////////////////////////////////////////////////////// +// check if update needed +//////////////////////////////////////////////////////////////////////// + +void updateDisplayIfChanged(void) { + //TODO +} + +//////////////////////////////////////////////////////////////////////// +// Update Lace, called every VSync +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUupdateLace() { + //TODO STUB +} + +//////////////////////////////////////////////////////////////////////// +// Read Request, process request from GPU status register +//////////////////////////////////////////////////////////////////////// + +unsigned long PEOPS_GPUreadStatus() { + if (dwActFixes & 1) { + static int iNumRead = 0; // odd/even hack + if ((iNumRead++) == 2) { + iNumRead = 0; + lGPUstatusRet ^= 0x80000000; // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older) + } + } + + // if(GetAsyncKeyState(VK_SHIFT)&32768) auxprintf("1 %08x\n",lGPUstatusRet); + + if (iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff + { + iFakePrimBusy--; + + if (iFakePrimBusy & 1) // we do a busy-idle-busy-idle sequence after/while drawing prims + { + GPUIsBusy; + GPUIsNotReadyForCommands; + } else { + GPUIsIdle; + GPUIsReadyForCommands; + } + // auxprintf("2 %08x\n",lGPUstatusRet); + } + + return lGPUstatusRet; +} + +//////////////////////////////////////////////////////////////////////// +// Write data to GPU status register +// These should be single packet commands. +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUwriteStatus(unsigned long gdata) { + unsigned long lCommand = (gdata >> 24) & 0xff; + + ulStatusControl[lCommand] = gdata; // store command for freezing + + switch (lCommand) { + //--------------------------------------------------// + // reset gpu + case 0x00: + memset(lGPUInfoVals, 0x00, 16 * sizeof(unsigned long)); + lGPUstatusRet = 0x14802000; + PSXDisplay.Disabled = 1; + DataWriteMode = DataReadMode = DR_NORMAL; + PSXDisplay.DrawOffset.x = PSXDisplay.DrawOffset.y = 0; + drawX = drawY = 0; + drawW = drawH = 0; + sSetMask = 0; + lSetMask = 0; + bCheckMask = FALSE; + usMirror = 0; + GlobalTextAddrX = 0; + GlobalTextAddrY = 0; + GlobalTextTP = 0; + GlobalTextABR = 0; + PSXDisplay.RGB24 = FALSE; + PSXDisplay.Interlaced = FALSE; + bUsingTWin = FALSE; + return; + //--------------------------------------------------// + // dis/enable display + case 0x03: + + PreviousPSXDisplay.Disabled = PSXDisplay.Disabled; + PSXDisplay.Disabled = (gdata & 1); + + if (PSXDisplay.Disabled) + lGPUstatusRet |= GPUSTATUS_DISPLAYDISABLED; + else + lGPUstatusRet &= ~GPUSTATUS_DISPLAYDISABLED; + return; + + //--------------------------------------------------// + // setting transfer mode + case 0x04: + gdata &= 0x03; // Only want the lower two bits + + DataWriteMode = DataReadMode = DR_NORMAL; + if (gdata == 0x02) + DataWriteMode = DR_VRAMTRANSFER; + if (gdata == 0x03) + DataReadMode = DR_VRAMTRANSFER; + lGPUstatusRet &= ~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits + lGPUstatusRet |= (gdata << 29); // Set the DMA bits according to the received data + + return; + //--------------------------------------------------// + // setting display position + case 0x05: { + PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x; + PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y; + + if (iGPUHeight == 1024) { + if (dwGPUVersion == 2) + PSXDisplay.DisplayPosition.y = (short) ((gdata >> 12) & 0x3ff); + else + PSXDisplay.DisplayPosition.y = (short) ((gdata >> 10) & 0x3ff); + } else + PSXDisplay.DisplayPosition.y = (short) ((gdata >> 10) & 0x1ff); + + // store the same val in some helper var, we need it on later compares + PreviousPSXDisplay.DisplayModeNew.x = PSXDisplay.DisplayPosition.y; + + if ((PSXDisplay.DisplayPosition.y + PSXDisplay.DisplayMode.y) + > iGPUHeight) { + int dy1 = iGPUHeight - PSXDisplay.DisplayPosition.y; + int dy2 = (PSXDisplay.DisplayPosition.y + PSXDisplay.DisplayMode.y) + - iGPUHeight; + + if (dy1 >= dy2) { + PreviousPSXDisplay.DisplayModeNew.y = -dy2; + } else { + PSXDisplay.DisplayPosition.y = 0; + PreviousPSXDisplay.DisplayModeNew.y = -dy1; + } + } else + PreviousPSXDisplay.DisplayModeNew.y = 0; + // eon + + PSXDisplay.DisplayPosition.x = (short) (gdata & 0x3ff); + PSXDisplay.DisplayEnd.x = PSXDisplay.DisplayPosition.x + + PSXDisplay.DisplayMode.x; + PSXDisplay.DisplayEnd.y = PSXDisplay.DisplayPosition.y + + PSXDisplay.DisplayMode.y + + PreviousPSXDisplay.DisplayModeNew.y; + PreviousPSXDisplay.DisplayEnd.x = PreviousPSXDisplay.DisplayPosition.x + + PSXDisplay.DisplayMode.x; + PreviousPSXDisplay.DisplayEnd.y = PreviousPSXDisplay.DisplayPosition.y + + PSXDisplay.DisplayMode.y + + PreviousPSXDisplay.DisplayModeNew.y; + + bDoVSyncUpdate = TRUE; + + if (!(PSXDisplay.Interlaced)) // stupid frame skipping option + { + if (UseFrameSkip) + updateDisplay(); + //TODO + //if(dwActFixes&64) bDoLazyUpdate=TRUE; + } + } + return; + //--------------------------------------------------// + // setting width + case 0x06: + + PSXDisplay.Range.x0 = (short) (gdata & 0x7ff); + PSXDisplay.Range.x1 = (short) ((gdata >> 12) & 0xfff); + + PSXDisplay.Range.x1 -= PSXDisplay.Range.x0; + + ChangeDispOffsetsX(); + + return; + //--------------------------------------------------// + // setting height + case 0x07: { + + PSXDisplay.Range.y0 = (short) (gdata & 0x3ff); + PSXDisplay.Range.y1 = (short) ((gdata >> 10) & 0x3ff); + + PreviousPSXDisplay.Height = PSXDisplay.Height; + + PSXDisplay.Height = PSXDisplay.Range.y1 - PSXDisplay.Range.y0 + + PreviousPSXDisplay.DisplayModeNew.y; + + if (PreviousPSXDisplay.Height != PSXDisplay.Height) { + PSXDisplay.DisplayModeNew.y = PSXDisplay.Height * PSXDisplay.Double; + + ChangeDispOffsetsY(); + + updateDisplayIfChanged(); + } + return; + } + //--------------------------------------------------// + // setting display infos + case 0x08: + + PSXDisplay.DisplayModeNew.x = sDispWidths[(gdata & 0x03) + | ((gdata & 0x40) >> 4)]; + + if (gdata & 0x04) + PSXDisplay.Double = 2; + else + PSXDisplay.Double = 1; + + PSXDisplay.DisplayModeNew.y = PSXDisplay.Height * PSXDisplay.Double; + + ChangeDispOffsetsY(); + + PSXDisplay.PAL = (gdata & 0x08) ? TRUE : FALSE; // if 1 - PAL mode, else NTSC + PSXDisplay.RGB24New = (gdata & 0x10) ? TRUE : FALSE; // if 1 - TrueColor + PSXDisplay.InterlacedNew = (gdata & 0x20) ? TRUE : FALSE; // if 1 - Interlace + + lGPUstatusRet &= ~GPUSTATUS_WIDTHBITS; // Clear the width bits + lGPUstatusRet |= (((gdata & 0x03) << 17) | ((gdata & 0x40) << 10)); // Set the width bits + + if (PSXDisplay.InterlacedNew) { + if (!PSXDisplay.Interlaced) { + PreviousPSXDisplay.DisplayPosition.x = + PSXDisplay.DisplayPosition.x; + PreviousPSXDisplay.DisplayPosition.y = + PSXDisplay.DisplayPosition.y; + } + lGPUstatusRet |= GPUSTATUS_INTERLACED; + } else + lGPUstatusRet &= ~GPUSTATUS_INTERLACED; + + if (PSXDisplay.PAL) + lGPUstatusRet |= GPUSTATUS_PAL; + else + lGPUstatusRet &= ~GPUSTATUS_PAL; + + if (PSXDisplay.Double == 2) + lGPUstatusRet |= GPUSTATUS_DOUBLEHEIGHT; + else + lGPUstatusRet &= ~GPUSTATUS_DOUBLEHEIGHT; + + if (PSXDisplay.RGB24New) + lGPUstatusRet |= GPUSTATUS_RGB24; + else + lGPUstatusRet &= ~GPUSTATUS_RGB24; + + updateDisplayIfChanged(); + + return; + //--------------------------------------------------// + // ask about GPU version and other stuff + case 0x10: + + gdata &= 0xff; + + switch (gdata) { + case 0x02: + lGPUdataRet = lGPUInfoVals[INFO_TW]; // tw infos + return; + case 0x03: + lGPUdataRet = lGPUInfoVals[INFO_DRAWSTART]; // draw start + return; + case 0x04: + lGPUdataRet = lGPUInfoVals[INFO_DRAWEND]; // draw end + return; + case 0x05: + case 0x06: + lGPUdataRet = lGPUInfoVals[INFO_DRAWOFF]; // draw offset + return; + case 0x07: + if (dwGPUVersion == 2) + lGPUdataRet = 0x01; + else + lGPUdataRet = 0x02; // gpu type + return; + case 0x08: + case 0x0F: // some bios addr? + lGPUdataRet = 0xBFC03720; + return; + } + return; + //--------------------------------------------------// + } +} + +//////////////////////////////////////////////////////////////////////// +// vram read/write helpers, needed by LEWPY's optimized vram read/write :) +//////////////////////////////////////////////////////////////////////// + +__inline void FinishedVRAMWrite(void) { + // Set register to NORMAL operation + DataWriteMode = DR_NORMAL; + // Reset transfer values, to prevent mis-transfer of data + VRAMWrite.x = 0; + VRAMWrite.y = 0; + VRAMWrite.Width = 0; + VRAMWrite.Height = 0; + VRAMWrite.ColsRemaining = 0; + VRAMWrite.RowsRemaining = 0; +} + +__inline void FinishedVRAMRead(void) { + // Set register to NORMAL operation + DataReadMode = DR_NORMAL; + // Reset transfer values, to prevent mis-transfer of data + VRAMRead.x = 0; + VRAMRead.y = 0; + VRAMRead.Width = 0; + VRAMRead.Height = 0; + VRAMRead.ColsRemaining = 0; + VRAMRead.RowsRemaining = 0; + + // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER + lGPUstatusRet &= ~GPUSTATUS_READYFORVRAM; +} + +//////////////////////////////////////////////////////////////////////// +// Read core data from vram +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUreadDataMem(unsigned long * pMem, int iSize) { + int i; + + if (DataReadMode != DR_VRAMTRANSFER) + return; + + GPUIsBusy; + + // adjust read ptr, if necessary + while (VRAMRead.ImagePtr >= psxVuw_eom) + VRAMRead.ImagePtr -= iGPUHeight * 1024; + while (VRAMRead.ImagePtr < psxVuw) + VRAMRead.ImagePtr += iGPUHeight * 1024; + + for (i = 0; i < iSize; i++) { + // do 2 seperate 16bit reads for compatibility (wrap issues) + if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0)) { + // lower 16 bit + lGPUdataRet = (unsigned long) GETLE16(VRAMRead.ImagePtr); + + VRAMRead.ImagePtr++; + if (VRAMRead.ImagePtr >= psxVuw_eom) + VRAMRead.ImagePtr -= iGPUHeight * 1024; + VRAMRead.RowsRemaining--; + + if (VRAMRead.RowsRemaining <= 0) { + VRAMRead.RowsRemaining = VRAMRead.Width; + VRAMRead.ColsRemaining--; + VRAMRead.ImagePtr += 1024 - VRAMRead.Width; + if (VRAMRead.ImagePtr >= psxVuw_eom) + VRAMRead.ImagePtr -= iGPUHeight * 1024; + } + + // higher 16 bit (always, even if it's an odd width) + lGPUdataRet |= (unsigned long) GETLE16(VRAMRead.ImagePtr) << 16; + PUTLE32(pMem, lGPUdataRet); + pMem++; + + if (VRAMRead.ColsRemaining <= 0) { + FinishedVRAMRead(); + goto ENDREAD; + } + + VRAMRead.ImagePtr++; + if (VRAMRead.ImagePtr >= psxVuw_eom) + VRAMRead.ImagePtr -= iGPUHeight * 1024; + VRAMRead.RowsRemaining--; + if (VRAMRead.RowsRemaining <= 0) { + VRAMRead.RowsRemaining = VRAMRead.Width; + VRAMRead.ColsRemaining--; + VRAMRead.ImagePtr += 1024 - VRAMRead.Width; + if (VRAMRead.ImagePtr >= psxVuw_eom) + VRAMRead.ImagePtr -= iGPUHeight * 1024; + } + if (VRAMRead.ColsRemaining <= 0) { + FinishedVRAMRead(); + goto ENDREAD; + } + } else { + FinishedVRAMRead(); + goto ENDREAD; + } + } + + ENDREAD: + GPUIsIdle; +} + +//////////////////////////////////////////////////////////////////////// + +unsigned long PEOPS_GPUreadData() { + unsigned long l; + PEOPS_GPUreadDataMem(&l, 1); + return lGPUdataRet; +} + +//////////////////////////////////////////////////////////////////////// +// processes data send to GPU data register +// extra table entries for fixing polyline troubles +//////////////////////////////////////////////////////////////////////// + +const unsigned char primTableCX[256] = { +// 00 + 0, 0, 3, 0, 0, 0, 0, 0, + // 08 + 0, 0, 0, 0, 0, 0, 0, 0, + // 10 + 0, 0, 0, 0, 0, 0, 0, 0, + // 18 + 0, 0, 0, 0, 0, 0, 0, 0, + // 20 + 4, 4, 4, 4, 7, 7, 7, 7, + // 28 + 5, 5, 5, 5, 9, 9, 9, 9, + // 30 + 6, 6, 6, 6, 9, 9, 9, 9, + // 38 + 8, 8, 8, 8, 12, 12, 12, 12, + // 40 + 3, 3, 3, 3, 0, 0, 0, 0, + // 48 +// 5,5,5,5,6,6,6,6, // FLINE + 254, 254, 254, 254, 254, 254, 254, 254, + // 50 + 4, 4, 4, 4, 0, 0, 0, 0, + // 58 +// 7,7,7,7,9,9,9,9, // GLINE + 255, 255, 255, 255, 255, 255, 255, 255, + // 60 + 3, 3, 3, 3, 4, 4, 4, 4, + // 68 + 2, 2, 2, 2, 3, 3, 3, 3, // 3=SPRITE1??? + // 70 + 2, 2, 2, 2, 3, 3, 3, 3, + // 78 + 2, 2, 2, 2, 3, 3, 3, 3, + // 80 + 4, 0, 0, 0, 0, 0, 0, 0, + // 88 + 0, 0, 0, 0, 0, 0, 0, 0, + // 90 + 0, 0, 0, 0, 0, 0, 0, 0, + // 98 + 0, 0, 0, 0, 0, 0, 0, 0, + // a0 + 3, 0, 0, 0, 0, 0, 0, 0, + // a8 + 0, 0, 0, 0, 0, 0, 0, 0, + // b0 + 0, 0, 0, 0, 0, 0, 0, 0, + // b8 + 0, 0, 0, 0, 0, 0, 0, 0, + // c0 + 3, 0, 0, 0, 0, 0, 0, 0, + // c8 + 0, 0, 0, 0, 0, 0, 0, 0, + // d0 + 0, 0, 0, 0, 0, 0, 0, 0, + // d8 + 0, 0, 0, 0, 0, 0, 0, 0, + // e0 + 0, 1, 1, 1, 1, 1, 1, 0, + // e8 + 0, 0, 0, 0, 0, 0, 0, 0, + // f0 + 0, 0, 0, 0, 0, 0, 0, 0, + // f8 + 0, 0, 0, 0, 0, 0, 0, 0 }; + +//////////////////////////////////////////////////////////////////////// +// Write core data to vram +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUwriteDataMem(unsigned long * pMem, int iSize) { + unsigned char command; + unsigned long gdata = 0; + int i = 0; + +#ifdef PEOPS_SDLOG + int jj,jjmax; + DEBUG_print("append",DBG_SDGECKOAPPEND); + sprintf(txtbuffer,"Calling GPUwriteDataMem(): mode = %d, *pmem = 0x%8x, iSize = %d\r\n",DataWriteMode,GETLE32(pMem),iSize); + DEBUG_print(txtbuffer,DBG_SDGECKOPRINT); + DEBUG_print("close",DBG_SDGECKOCLOSE); +#endif //PEOPS_SDLOG + + GPUIsBusy; + GPUIsNotReadyForCommands; + + STARTVRAM: + + if (DataWriteMode == DR_VRAMTRANSFER) { + BOOL bFinished = FALSE; + + // make sure we are in vram + while (VRAMWrite.ImagePtr >= psxVuw_eom) + VRAMWrite.ImagePtr -= iGPUHeight * 1024; + while (VRAMWrite.ImagePtr < psxVuw) + VRAMWrite.ImagePtr += iGPUHeight * 1024; + + // now do the loop + while (VRAMWrite.ColsRemaining > 0) { + while (VRAMWrite.RowsRemaining > 0) { + if (i >= iSize) { + goto ENDVRAM; + } + i++; + + gdata = GETLE32(pMem); + pMem++; + + PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); + VRAMWrite.ImagePtr++; + if (VRAMWrite.ImagePtr >= psxVuw_eom) + VRAMWrite.ImagePtr -= iGPUHeight * 1024; + VRAMWrite.RowsRemaining--; + + if (VRAMWrite.RowsRemaining <= 0) { + VRAMWrite.ColsRemaining--; + if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width + { + gdata = (gdata & 0xFFFF) + | (((unsigned long) GETLE16(VRAMWrite.ImagePtr)) + << 16); + FinishedVRAMWrite(); + bDoVSyncUpdate = TRUE; + goto ENDVRAM; + } + VRAMWrite.RowsRemaining = VRAMWrite.Width; + VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width; + } + + PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); + VRAMWrite.ImagePtr++; + if (VRAMWrite.ImagePtr >= psxVuw_eom) + VRAMWrite.ImagePtr -= iGPUHeight * 1024; + VRAMWrite.RowsRemaining--; + } + + VRAMWrite.RowsRemaining = VRAMWrite.Width; + VRAMWrite.ColsRemaining--; + VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width; + bFinished = TRUE; + } + + FinishedVRAMWrite(); + if (bFinished) + bDoVSyncUpdate = TRUE; + } + + ENDVRAM: + + if (DataWriteMode == DR_NORMAL) { + void (* *primFunc)(unsigned char *); + if (bSkipNextFrame) + primFunc = primTableSkip; + else + primFunc = primTableJ; + + for (; i < iSize;) { + if (DataWriteMode == DR_VRAMTRANSFER) + goto STARTVRAM; + + gdata = GETLE32(pMem); + pMem++; + i++; + + if (gpuDataC == 0) { + command = (unsigned char) ((gdata >> 24) & 0xff); + + //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command); + + if (primTableCX[command]) { + gpuDataC = primTableCX[command]; + gpuCommand = command; + PUTLE32(&gpuDataM[0], gdata); + gpuDataP = 1; + } else + continue; + } else { + PUTLE32(&gpuDataM[gpuDataP], gdata); + if (gpuDataC > 128) { + if ((gpuDataC == 254 && gpuDataP >= 3) + || (gpuDataC == 255 && gpuDataP >= 4 + && !(gpuDataP & 1))) { + if ((gdata & 0xF000F000) == 0x50005000) + gpuDataP = gpuDataC - 1; + } + } + gpuDataP++; + } + + if (gpuDataP == gpuDataC) { +#ifdef PEOPS_SDLOG + DEBUG_print("append",DBG_SDGECKOAPPEND); + sprintf(txtbuffer," primeFunc[%d](",gpuCommand); + DEBUG_print(txtbuffer,DBG_SDGECKOPRINT); + jjmax = (gpuDataC>128) ? 6 : gpuDataP; + for(jj = 0; jj 2000000) + break; + if (CheckForEndlessLoop(addr)) + break; + + count = baseAddrB[addr + 3]; + + dmaMem = addr + 4; + + if (count > 0) + PEOPS_GPUwriteDataMem(&baseAddrL[dmaMem >> 2], count); + + addr = GETLE32(&baseAddrL[addr>>2]) & 0xffffff; + } while (addr != 0xffffff); + + GPUIsIdle; + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// show about dlg +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUabout(void) // ABOUT +{ + AboutDlgProc(); +} + +//////////////////////////////////////////////////////////////////////// +// We are ever fine ;) +//////////////////////////////////////////////////////////////////////// + +long CALLBACK GPUtest(void) { + // if test fails this function should return negative value for error (unable to continue) + // and positive value for warning (can continue but output might be crappy) + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// GPU Freeze save state functions (taken from PeopsSoftGPU) +//////////////////////////////////////////////////////////////////////// + +typedef struct GPUFREEZETAG { + unsigned long ulFreezeVersion; // should be always 1 for now (set by main emu) + unsigned long ulStatus; // current gpu status + unsigned long ulControl[256]; // latest control register values +//unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN) +} GPUFreeze_t; + +//////////////////////////////////////////////////////////////////////// +// Freeze GPU +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUfreeze(unsigned long ulGetFreezeData, GPUFreeze_t * pF) { + //----------------------------------------------------// + if (ulGetFreezeData == 2) // 2: info, which save slot is selected? (just for display) + { + long lSlotNum = *((long *) pF); + if (lSlotNum < 0) + return 0; + if (lSlotNum > 8) + return 0; + lSelectedSlot = lSlotNum + 1; + //TODO + //BuildDispMenu(0); + return 1; + } + //----------------------------------------------------// + if (!pF) + return 0; // some checks + if (pF->ulFreezeVersion != 1) + return 0; + + if (ulGetFreezeData == 1) // 1: get data (Save State) + { + pF->ulStatus = lGPUstatusRet; + memcpy(pF->ulControl, ulStatusControl, 256 * sizeof(unsigned long)); + //memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2); //done in Misc.c + + return 1; + } + + if (ulGetFreezeData != 0) + return 0; // 0: set data (Load State) + + lGPUstatusRet = pF->ulStatus; + memcpy(ulStatusControl, pF->ulControl, 256 * sizeof(unsigned long)); + //memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2); //done in Misc.c + + // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT + + PEOPS_GPUwriteStatus(ulStatusControl[0]); + PEOPS_GPUwriteStatus(ulStatusControl[1]); + PEOPS_GPUwriteStatus(ulStatusControl[2]); + PEOPS_GPUwriteStatus(ulStatusControl[3]); + PEOPS_GPUwriteStatus(ulStatusControl[8]); // try to repair things + PEOPS_GPUwriteStatus(ulStatusControl[6]); + PEOPS_GPUwriteStatus(ulStatusControl[7]); + PEOPS_GPUwriteStatus(ulStatusControl[5]); + PEOPS_GPUwriteStatus(ulStatusControl[4]); + + return 1; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SAVE STATE DISPLAY STUFF +//////////////////////////////////////////////////////////////////////// + +// font 0-9, 24x20 pixels, 1 byte = 4 dots +// 00 = black +// 01 = white +// 10 = red +// 11 = transparent + +unsigned char cFont[10][120] = { +// 0 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, + 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 1 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x05, 0x50, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x80, 0x00, 0x05, 0x55, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 2 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x01, 0x40, 0x00, + 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x15, 0x55, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 3 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x01, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 4 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0x00, 0x00, 0x54, 0x00, + 0x00, 0x80, 0x00, 0x01, 0x54, 0x00, 0x00, 0x80, 0x00, 0x01, + 0x54, 0x00, 0x00, 0x80, 0x00, 0x05, 0x14, 0x00, 0x00, 0x80, + 0x00, 0x14, 0x14, 0x00, 0x00, 0x80, 0x00, 0x15, 0x55, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x80, 0x00, 0x00, 0x55, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 5 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x15, 0x55, 0x00, 0x00, 0x80, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x00, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x15, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 6 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x01, 0x54, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x00, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x15, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x15, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 7 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x15, 0x55, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x14, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x80, 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x50, 0x00, 0x00, 0x80, 0x00, 0x01, 0x40, 0x00, + 0x00, 0x80, 0x00, 0x01, 0x40, 0x00, 0x00, 0x80, 0x00, 0x05, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 8 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, +// 9 + { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x54, 0x00, 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x14, 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, + 0x05, 0x00, 0x00, 0x80, 0x00, 0x14, 0x15, 0x00, 0x00, 0x80, + 0x00, 0x05, 0x55, 0x00, 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x05, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x80, 0x00, 0x05, 0x50, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa } }; + +//////////////////////////////////////////////////////////////////////// + +void PaintPicDot(unsigned char * p, unsigned char c) { + + if (c == 0) { + *p++ = 0x00; + *p++ = 0x00; + *p = 0x00; + return; + } // black + if (c == 1) { + *p++ = 0xff; + *p++ = 0xff; + *p = 0xff; + return; + } // white + if (c == 2) { + *p++ = 0x00; + *p++ = 0x00; + *p = 0xff; + return; + } // red + // transparent +} + +//////////////////////////////////////////////////////////////////////// +// the main emu allocs 128x96x3 bytes, and passes a ptr +// to it in pMem... the plugin has to fill it with +// 8-8-8 bit BGR screen data (Win 24 bit BMP format +// without header). +// Beware: the func can be called at any time, +// so you have to use the frontbuffer to get a fully +// rendered picture + +//TODO +//extern char * Xpixels; + +void GPUgetScreenPic(unsigned char * pMem) { + //Unsupported +} + +//////////////////////////////////////////////////////////////////////// +// func will be called with 128x96x3 BGR data. +// the plugin has to store the data and display +// it in the upper right corner. +// If the func is called with a NULL ptr, you can +// release your picture data and stop displaying +// the screen pic + +void CALLBACK GPUshowScreenPic(unsigned char * pMem) { + //TODO + //DestroyPic(); // destroy old pic data + if (pMem == 0) + return; // done + //TODO + //CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUsetframelimit(unsigned long option) { + bInitCap = TRUE; + + if (frameLimit == FRAMELIMIT_AUTO) { + UseFrameLimit = 1; + iFrameLimit = 2; + SetAutoFrameCap(); + } else { + UseFrameLimit = 0; + iFrameLimit = 0; + } + UseFrameSkip = frameSkip; + //TODO + //BuildDispMenu(0); +} diff --git a/PeopsGXGPU/gpu.h b/PeopsGXGPU/gpu.h new file mode 100644 index 0000000..030c64e --- /dev/null +++ b/PeopsGXGPU/gpu.h @@ -0,0 +1,72 @@ +/*************************************************************************** + gpu.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_INTERNALS_H +#define _GPU_INTERNALS_H + +///////////////////////////////////////////////////////////////////////////// + +#define OPAQUEON 10 +#define OPAQUEOFF 11 + +#define KEY_RESETTEXSTORE 1 +#define KEY_SHOWFPS 2 +#define KEY_RESETOPAQUE 4 +#define KEY_RESETDITHER 8 +#define KEY_RESETFILTER 16 +#define KEY_RESETADVBLEND 32 +//#define KEY_BLACKWHITE 64 +#define KEY_BADTEXTURES 128 +#define KEY_CHECKTHISOUT 256 + +#ifndef _BIG_ENDIAN +#ifndef _FPSE +#define RED(x) (x & 0xff) +#define BLUE(x) ((x>>16) & 0xff) +#define GREEN(x) ((x>>8) & 0xff) +#define COLOR(x) (x & 0xffffff) +#else +#define BLUE(x) (x & 0xff) +#define RED(x) ((x>>16) & 0xff) +#define GREEN(x) ((x>>8) & 0xff) +#define COLOR(x) (x & 0xffffff) +#endif +#else //!_BIG_ENDIAN +#define RED(x) ((x>>24) & 0xff) +#define BLUE(x) ((x>>8) & 0xff) +#define GREEN(x) ((x>>16) & 0xff) +#define COLOR(x) SWAP32(x & 0xffffff) +#endif //_BIG_ENDIAN + +///////////////////////////////////////////////////////////////////////////// + +void updateDisplay(void); +void SetAutoFrameCap(void); +void SetFixes(void); + +///////////////////////////////////////////////////////////////////////////// + +#endif // _GPU_INTERNALS_H diff --git a/PeopsGXGPU/psemu.h b/PeopsGXGPU/psemu.h new file mode 100644 index 0000000..ec76b02 --- /dev/null +++ b/PeopsGXGPU/psemu.h @@ -0,0 +1,36 @@ +/*************************************************************************** + psemu.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _PSEMU_PLUGIN_DEFS_H +#define _PSEMU_PLUGIN_DEFS_H + +// plugin type returned by PSEgetLibType +#define PSE_LT_CDR 1 +#define PSE_LT_GPU 2 +#define PSE_LT_SPU 4 + + +#endif // _PSEMU_PLUGIN_DEFS_H diff --git a/PeopsGXGPU/stdafx.h b/PeopsGXGPU/stdafx.h new file mode 100644 index 0000000..0b78791 --- /dev/null +++ b/PeopsGXGPU/stdafx.h @@ -0,0 +1,35 @@ +/*************************************************************************** + stdafx.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define __inline inline +#define CALLBACK + +#include +#include +#include +#include +#include + diff --git a/PeopsGXGPU/stubs.c b/PeopsGXGPU/stubs.c new file mode 100644 index 0000000..a20c230 --- /dev/null +++ b/PeopsGXGPU/stubs.c @@ -0,0 +1,73 @@ +//TODO These are variables are "stubbed" +//TODO Delete these after implementation + +///////////////////////////////////////////////////////////////////////////// + +#include "externals.h" + +// draw.c + +#define _IN_DRAW + +char * pCaptionText; + +int iResX; +int iResY; +long GlobalTextAddrX,GlobalTextAddrY,GlobalTextTP; +long GlobalTextREST,GlobalTextABR,GlobalTextPAGE; +short ly0,lx0,ly1,lx1,ly2,lx2,ly3,lx3; +long lLowerpart; +BOOL bIsFirstFrame; +int iWinSize; +BOOL bCheckMask; +unsigned short sSetMask; +unsigned long lSetMask; +BOOL bDeviceOK; +short g_m1; +short g_m2; +short g_m3; +short DrawSemiTrans; +int iUseGammaVal; +int iUseScanLines; +int iDesktopCol; +int iUseNoStretchBlt; +int iShowFPS; +int iFastFwd; +int iDebugMode; +int iFVDisplay; +PSXPoint_t ptCursorPoint[]; +unsigned short usCursorActive; + +// prim.c + +#define _IN_PRIMDRAW + +BOOL bUsingTWin; +TWin_t TWin; +unsigned long clutid; +void (*primTableJ[256])(unsigned char *); +void (*primTableSkip[256])(unsigned char *); +unsigned short usMirror; +int iDither; +unsigned long dwCfgFixes; +unsigned long dwActFixes; +unsigned long dwEmuFixes; +int iUseFixes; +int iUseDither; +BOOL bDoVSyncUpdate; +long drawX; +long drawY; +long drawW; +long drawH; + +// menu.c + +#define _IN_MENU + +unsigned long dwCoreFlags; + +// key.c + +#define _IN_KEY +//TODO Replace all instances of this with 0, key.c is useless +unsigned long ulKeybits=0; diff --git a/PeopsGXGPU/swap.h b/PeopsGXGPU/swap.h new file mode 100644 index 0000000..2d9ef0a --- /dev/null +++ b/PeopsGXGPU/swap.h @@ -0,0 +1,51 @@ + +// byteswappings + +#define SWAP16(x) (((x)>>8 & 0xff) | ((x)<<8 & 0xff00)) +#define SWAP32(x) (((x)>>24 & 0xfful) | ((x)>>8 & 0xff00ul) | ((x)<<8 & 0xff0000ul) | ((x)<<24 & 0xff000000ul)) + +// big endian config +#define HOST2LE32(x) SWAP32(x) +#define HOST2BE32(x) (x) +#define LE2HOST32(x) SWAP32(x) +#define BE2HOST32(x) (x) + +#define HOST2LE16(x) SWAP16(x) +#define HOST2BE16(x) (x) +#define LE2HOST16(x) SWAP16(x) +#define BE2HOST16(x) (x) + +#define GETLEs16(X) ((short)GETLE16((unsigned short *)X)) +#define GETLEs32(X) ((short)GETLE32((unsigned short *)X)) + +#ifdef _BIG_ENDIAN +// GCC style +extern __inline__ unsigned short GETLE16(unsigned short *ptr) { + unsigned short ret; __asm__ ("lhbrx %0, 0, %1" : "=r" (ret) : "r" (ptr)); + return ret; +} +extern __inline__ unsigned long GETLE32(unsigned long *ptr) { + unsigned long ret; + __asm__ ("lwbrx %0, 0, %1" : "=r" (ret) : "r" (ptr)); + return ret; +} +extern __inline__ unsigned long GETLE16D(unsigned long *ptr) { + unsigned long ret; + __asm__ ("lwbrx %0, 0, %1\n" + "rlwinm %0, %0, 16, 0, 31" : "=r" (ret) : "r" (ptr)); + return ret; +} + +extern __inline__ void PUTLE16(unsigned short *ptr, unsigned short val) { + __asm__ ("sthbrx %0, 0, %1" : : "r" (val), "r" (ptr) : "memory"); +} +extern __inline__ void PUTLE32(unsigned long *ptr, unsigned long val) { + __asm__ ("stwbrx %0, 0, %1" : : "r" (val), "r" (ptr) : "memory"); +} +#else // _BIG_ENDIAN +#define GETLE16(X) ((unsigned short *)X) +#define GETLE32(X) ((unsigned long *)X) +#define GETLE16D(X) ({unsigned long val = GETLE32(X); (val<<16 | val >> 16)}) +#define PUTLE16(X, Y) {((unsigned short *)X)=(unsigned short)X} +#define PUTLE32(X, Y) {((unsigned long *)X)=(unsigned long)X} +#endif //!_BIG_ENDIAN diff --git a/PeopsSoftGPU/DrawString.c b/PeopsSoftGPU/DrawString.c new file mode 100644 index 0000000..1b4b5b1 --- /dev/null +++ b/PeopsSoftGPU/DrawString.c @@ -0,0 +1,118 @@ + +#include "DrawString.h" +#include "DrawStringFont.h" + +#define CHAR_W 10 +#define CHAR_H 14 + +void (*drawChar) (char *, int, char, int, int, int); +void (*drawHline) (char *, int, char, int, int, int); + +static void drawChar15(char *ptr, int lPitch, char c, int mw, int mh, int mode) { + int x, y, w, h; + int fx, fy; + + if (mw > CHAR_W) w = CHAR_W; else w = mw; + if (mh > CHAR_H) h = CHAR_H; else h = mh; + if (w <=0 || h <= 0) return; + + fx = font_tc[c*4+0] + 2; + fy = font_tc[c*4+1]; + + for (y=0; y CHAR_W) w = CHAR_W; else w = mw; + if (mh > CHAR_H) h = CHAR_H; else h = mh; + if (w <=0 || h <= 0) return; + + fx = font_tc[c*4+0] + 2; + fy = font_tc[c*4+1]; + + for (y=0; y CHAR_W) w = CHAR_W; else w = mw; + if (mh > CHAR_H) h = CHAR_H; else h = mh; + if (w <=0 || h <= 0) return; + + fx = font_tc[c*4+0] + 2; + fy = font_tc[c*4+1]; + + for (y=0; y CHAR_W) w = CHAR_W; else w = mw; + if (mh > CHAR_H) h = CHAR_H; else h = mh; + if (w <=0 || h <= 0) return; + + fx = font_tc[c*4+0] + 2; + fy = font_tc[c*4+1]; + + for (y=0; y 0) drawChar(ptr, lPitch, *str, w - x, h - y, mode); + else drawChar(ptr, lPitch, ' ', w - x, h - y, mode); + str++; len--; x+= CHAR_W; + } +} diff --git a/PeopsSoftGPU/DrawString.h b/PeopsSoftGPU/DrawString.h new file mode 100644 index 0000000..94861e7 --- /dev/null +++ b/PeopsSoftGPU/DrawString.h @@ -0,0 +1,10 @@ + +// mode flags + +#define DSM_NORMAL 0 +#define DSM_TRANSPARENT 1 + +// draws a string over buff +void DrawString(char *buff, int lPitch, int bpp, + int x, int y, int w, int h, + char *str, int len, int mode); diff --git a/PeopsSoftGPU/DrawStringFont.h b/PeopsSoftGPU/DrawStringFont.h new file mode 100644 index 0000000..07a4f32 --- /dev/null +++ b/PeopsSoftGPU/DrawStringFont.h @@ -0,0 +1,33039 @@ +// based on the fixed font made by Tony Saveski + +int font_tc[] = { + 0, 0, 1, 1, // 000 - + 0, 0, 1, 1, // 001 - + 0, 0, 1, 1, // 002 - + 0, 0, 1, 1, // 003 - + 0, 0, 1, 1, // 004 - + 0, 0, 1, 1, // 005 - + 0, 0, 1, 1, // 006 - + 0, 0, 1, 1, // 007 - + 0, 0, 1, 1, // 008 - + 0, 0, 1, 1, // 009 - + 0, 0, 1, 1, // 010 - + 0, 0, 1, 1, // 011 - + 0, 0, 1, 1, // 012 - + 0, 0, 1, 1, // 013 - + 0, 0, 1, 1, // 014 - + 0, 0, 1, 1, // 015 - + 0, 0, 1, 1, // 016 - + 0, 0, 1, 1, // 017 - + 0, 0, 1, 1, // 018 - + 0, 0, 1, 1, // 019 - + 0, 0, 1, 1, // 020 - + 0, 0, 1, 1, // 021 - + 0, 0, 1, 1, // 022 - + 0, 0, 1, 1, // 023 - + 0, 0, 1, 1, // 024 - + 0, 0, 1, 1, // 025 - + 0, 0, 1, 1, // 026 - + 0, 0, 1, 1, // 027 - + 0, 0, 1, 1, // 028 - + 0, 0, 1, 1, // 029 - + 0, 0, 1, 1, // 030 - + 0, 0, 1, 1, // 031 - + + 0, 0, 15, 15, // 032 - space + 16, 0, 31, 15, // 033 - ! + 32, 0, 47, 15, // 034 - " + 48, 0, 63, 15, // 035 - # + 64, 0, 79, 15, // 036 - $ + 80, 0, 95, 15, // 037 - % + 96, 0, 111, 15, // 038 - & + 112, 0, 127, 15, // 039 - ' + 128, 0, 143, 15, // 040 - ( + 144, 0, 159, 15, // 041 - ) + 160, 0, 175, 15, // 042 - * + 176, 0, 191, 15, // 043 - + + 192, 0, 207, 15, // 044 - , + 208, 0, 223, 15, // 045 - - + 224, 0, 239, 15, // 046 - . + 240, 0, 255, 15, // 047 - / + + 0, 16, 15, 31, // 048 - 0 + 16, 16, 31, 31, // 049 - 1 + 32, 16, 47, 31, // 050 - 2 + 48, 16, 63, 31, // 051 - 3 + 64, 16, 79, 31, // 052 - 4 + 80, 16, 95, 31, // 053 - 5 + 96, 16, 111, 31, // 054 - 6 + 112, 16, 127, 31, // 055 - 7 + 128, 16, 143, 31, // 056 - 8 + 144, 16, 159, 31, // 057 - 9 + 160, 16, 175, 31, // 058 - : + 176, 16, 191, 31, // 059 - ; + 192, 16, 207, 31, // 060 - < + 208, 16, 223, 31, // 061 - = + 224, 16, 239, 31, // 062 - > + 240, 16, 255, 31, // 063 - ? + + 0, 32, 15, 47, // 064 - @ + 16, 32, 31, 47, // 065 - A + 32, 32, 47, 47, // 066 - B + 48, 32, 63, 47, // 067 - C + 64, 32, 79, 47, // 068 - D + 80, 32, 95, 47, // 069 - E + 96, 32, 111, 47, // 070 - F + 112, 32, 127, 47, // 071 - G + 128, 32, 143, 47, // 072 - H + 144, 32, 159, 47, // 073 - I + 160, 32, 175, 47, // 074 - J + 176, 32, 191, 47, // 075 - K + 192, 32, 207, 47, // 076 - L + 208, 32, 223, 47, // 077 - M + 224, 32, 239, 47, // 078 - N + 240, 32, 255, 47, // 079 - O + + 0, 48, 15, 63, // 080 - P + 16, 48, 31, 63, // 081 - Q + 32, 48, 47, 63, // 082 - R + 48, 48, 63, 63, // 083 - S + 64, 48, 79, 63, // 084 - T + 80, 48, 95, 63, // 085 - U + 96, 48, 111, 63, // 086 - V + 112, 48, 127, 63, // 087 - W + 128, 48, 143, 63, // 088 - X + 144, 48, 159, 63, // 089 - Y + 160, 48, 175, 63, // 090 - Z + 176, 48, 191, 63, // 091 - [ + 192, 48, 207, 63, // 092 - backslash + 208, 48, 223, 63, // 093 - ] + 224, 48, 239, 63, // 094 - ^ + 240, 48, 255, 63, // 095 - _ + + 0, 64, 15, 79, // 096 - ` + 16, 64, 31, 79, // 097 - a + 32, 64, 47, 79, // 098 - b + 48, 64, 63, 79, // 099 - c + 64, 64, 79, 79, // 100 - d + 80, 64, 95, 79, // 101 - e + 96, 64, 111, 79, // 102 - f + 112, 64, 127, 79, // 103 - g + 128, 64, 143, 79, // 104 - h + 144, 64, 159, 79, // 105 - i + 160, 64, 175, 79, // 106 - j + 176, 64, 191, 79, // 107 - k + 192, 64, 207, 79, // 108 - l + 208, 64, 223, 79, // 109 - m + 224, 64, 239, 79, // 110 - n + 240, 64, 255, 79, // 111 - o + + 0, 80, 15, 95, // 112 - p + 16, 80, 31, 95, // 113 - q + 32, 80, 47, 95, // 114 - r + 48, 80, 63, 95, // 115 - s + 64, 80, 79, 95, // 116 - t + 80, 80, 95, 95, // 117 - u + 96, 80, 111, 95, // 118 - v + 112, 80, 127, 95, // 119 - w + 128, 80, 143, 95, // 120 - x + 144, 80, 159, 95, // 121 - y + 160, 80, 175, 95, // 122 - z + 176, 80, 191, 95, // 123 - { + 192, 80, 207, 95, // 124 - | + 208, 80, 223, 95, // 125 - } + 224, 80, 239, 95, // 126 - ~ + 240, 80, 255, 95, // 127 - crap +}; + + + +static unsigned char font[] = { + // row 0 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 1 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 2 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 3 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 4 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 5 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 6 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 7 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 8 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 9 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 10 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 11 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 12 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 13 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 14 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 15 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 16 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 17 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 18 + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 19 + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 20 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 21 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 22 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 23 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 24 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 25 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 26 + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 27 + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 28 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 29 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 30 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 31 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 32 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 33 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 34 + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 35 + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 36 + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 37 + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 38 + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 39 + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 40 + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 41 + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 42 + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 43 + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 44 + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 45 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 46 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 47 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 48 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 49 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 50 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 51 + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 52 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 53 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 54 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 55 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 56 + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 57 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 58 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 59 + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 60 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 61 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 62 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + // row 63 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 64 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 65 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 66 + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 67 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 68 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 69 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 70 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 71 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 72 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 73 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 74 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 75 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 76 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 77 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 78 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 79 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 80 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 81 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 82 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + // row 83 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 84 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 85 + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 86 + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 87 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 88 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 89 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 90 + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 91 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + // row 92 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 93 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 94 + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 95 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 96 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 97 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 98 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + // row 99 + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 100 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 101 + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 102 + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 103 + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 104 + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 105 + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 106 + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + // row 107 + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + // row 108 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 109 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 110 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 111 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 112 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 113 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 114 + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 115 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + // row 116 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 1, + 1, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + // row 117 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 118 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + // row 119 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 120 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 121 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 122 + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 123 + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 0, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + // row 124 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 125 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 126 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + // row 127 + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; diff --git a/PeopsSoftGPU/Makefile b/PeopsSoftGPU/Makefile new file mode 100644 index 0000000..294ab05 --- /dev/null +++ b/PeopsSoftGPU/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for Peops soft gpu +# + +include ./makes/plg.mk +#include ./makes/mk.x11 +#include ./makes/mk.fpse + +# Dependencies + +cfg.o: cfg.c stdafx.h externals.h cfg.h gpu.h +draw.o: draw.c stdafx.h externals.h gpu.h draw.h prim.h menu.h +fps.o: fps.c stdafx.h externals.h fps.h +fpsewp.o: fpsewp.c stdafx.h fpse/type.h fpse/sdk.h fpse/linuxdef.h \ + fpsewp.h externals.h +gpu.o: gpu.c stdafx.h externals.h gpu.h draw.h cfg.h prim.h psemu.h \ + menu.h key.h fps.h +gpupeopssoft.o: gpupeopssoft.c stdafx.h +key.o: key.c stdafx.h externals.h menu.h gpu.h draw.h key.h +menu.o: menu.c stdafx.h externals.h draw.h menu.h gpu.h +prim.o: prim.c stdafx.h externals.h gpu.h draw.h soft.h +record.o: record.c stdafx.h externals.h record.h gpu.h +soft.o: soft.c stdafx.h externals.h gpu.h soft.h prim.h menu.h +zn.o: zn.c stdafx.h externals.h +#hq3x32.o: hq3x32.asm +#hq2x32.o: hq2x32.asm +#hq3x16.o: hq3x16.asm +#hq2x16.o: hq2x16.asm diff --git a/PeopsSoftGPU/Makefile.nodep b/PeopsSoftGPU/Makefile.nodep new file mode 100644 index 0000000..4036c59 --- /dev/null +++ b/PeopsSoftGPU/Makefile.nodep @@ -0,0 +1,8 @@ +# +# Makefile for FPSE plugins +# +include ./makes/plg.mk +include ./makes/mk.fpse + +# Dependencies + diff --git a/PeopsSoftGPU/NoPic.h b/PeopsSoftGPU/NoPic.h new file mode 100644 index 0000000..553cede --- /dev/null +++ b/PeopsSoftGPU/NoPic.h @@ -0,0 +1,1345 @@ +//////////////////////////////////////////////////////////////////////// +// following code taken from the gpuPeopsSoft +//////////////////////////////////////////////////////////////////////// + +// font 0-9, 24x20 pixels, 1 byte = 4 dots +// 00 = black +// 01 = white +// 10 = red +// 11 = transparent + +unsigned char cFont[10][120]= +{ +// 0 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 1 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 2 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 3 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 4 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x14,0x00,0x00, + 0x80,0x00,0x14,0x14,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 5 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 6 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x15,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 7 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 8 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 9 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x15,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +} +}; + +//////////////////////////////////////////////////////////////////////// + +void PaintPicDot(unsigned char * p,unsigned char c) +{ + + if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black + if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white + if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red + // transparent +} + + ///////////////////////////////////////////////////////////////////// + // generic number/border painter + +void DrawNumBorPic(unsigned char *pMem, int lSelectedSlot) +{ + unsigned char *pf; + int x,y; + int c,v; + + pf=pMem+(103*3); // offset to number rect + + for(y=0;y<20;y++) // loop the number rect pixel + { + for(x=0;x<6;x++) + { + c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot) + v=(c&0xc0)>>6; + PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect + v=(c&0x30)>>4; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=(c&0x0c)>>2; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=c&0x03; + PaintPicDot(pf,(unsigned char)v);pf+=3; + } + pf+=104*3; // next rect y line + } + + pf=pMem; // ptr to first pos in 128x96 pic + for(x=0;x<128;x++) // loop top/bottom line + { + *(pf+(95*128*3))=0x00;*pf++=0x00; + *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red + *(pf+(95*128*3))=0xff;*pf++=0xff; + } + pf=pMem; // ptr to first pos + for(y=0;y<96;y++) // loop left/right line + { + *(pf+(127*3))=0x00;*pf++=0x00; + *(pf+(127*3))=0x00;*pf++=0x00; // paint it red + *(pf+(127*3))=0xff;*pf++=0xff; + pf+=127*3; // offset to next line + } +} + +//////////////////////////////////////////////////////////////////////// + + +/* GIMP RGB C-Source image dump (NoPic.h) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 96 * 3 + 1]; +} NoPic_Image = { + 128, 96, 3, + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0U\0\0" + "U\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8" + "\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251" + "\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0" + "\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\305" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0\214\0\0\34\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\305\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0""8\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\305\0\0q\0\0U\0\0U\0" + "\0U\0\0\214\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\251\0\0\251\0\0\251\0\0\251\0\0\251" + "\0\0\251\0\0\251\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\251\0\0U\0\0U\0\0" + "U\0\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0" + "\0\376\0\0\376\0\0\341\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\341\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\341\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\305" + "\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214" + "\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34" + "\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\0\0\0\251\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0" + "\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376" + "\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\214\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0" + "\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0""8\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0" + "\0\0\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\214\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0" + "\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\214\0\0\341\0\0\376" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0" + "\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0" + "\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376" + "\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\305\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\341\0\0\34\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\305" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\214\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\305\0\0\251\0\0\251\0\0\251\0\0\341\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0" + "U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\251\0\0\251\0\0\251\0\0\251\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0" + "\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0q\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\214\0\0\305\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\214\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0", +}; + diff --git a/PeopsSoftGPU/cfg.c b/PeopsSoftGPU/cfg.c new file mode 100644 index 0000000..faa3f28 --- /dev/null +++ b/PeopsSoftGPU/cfg.c @@ -0,0 +1,434 @@ +/*************************************************************************** + cfg.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2007/10/27 - Pete +// - added SSSPSX frame limit mode and MxC stretching modes +// +// 2005/04/15 - Pete +// - changed user frame limit to floating point value +// +// 2004/02/08 - Pete +// - added Windows zn config file handling (no need to change it for Linux version) +// +// 2002/11/06 - Pete +// - added 2xSai, Super2xSaI, SuperEagle cfg stuff +// +// 2002/10/04 - Pete +// - added Win debug mode & full vram view key config +// +// 2002/09/27 - linuzappz +// - separated linux gui to conf.c +// +// 2002/06/09 - linuzappz +// - fixed linux about dialog +// +// 2002/02/23 - Pete +// - added capcom fighter special game fix +// +// 2002/01/06 - lu +// - Connected the signal "destroy" to gtk_main_quit() in the ConfDlg, it +// should fix a possible weird behaviour +// +// 2002/01/06 - lu +// - now fpse for linux has a configurator, some cosmetic changes done. +// +// 2001/12/25 - linuzappz +// - added gtk_main_quit(); in linux config +// +// 2001/12/20 - syo +// - added "Transparent menu" switch +// +// 2001/12/18 - syo +// - added "wait VSYNC" switch +// - support refresh rate change +// - modified key configuration (added toggle wait VSYNC key) +// (Pete: fixed key buffers and added "- default" +// refresh rate (=0) for cards not supporting setting the +// refresh rate) +// +// 2001/12/18 - Darko Matesic +// - added recording configuration +// +// 2001/12/15 - lu +// - now fpsewp has his save and load routines in fpsewp.c +// +// 2001/12/05 - syo +// - added "use system memory" switch +// - The bug which fails in the change in full-screen mode from window mode is corrected. +// - added "Stop screen saver" switch +// +// 2001/11/20 - linuzappz +// - added WriteConfig and rewrite ReadConfigFile +// - added SoftDlgProc and AboutDlgProc for Linux (under gtk+-1.2.5) +// +// 2001/11/11 - lu +// - added some ifdef for FPSE layer +// +// 2001/11/09 - Darko Matesic +// - added recording configuration +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#include "../Gamecube/wiiSXconfig.h" + +#define _IN_CFG + +#include +#undef FALSE +#undef TRUE +#define MAKELONG(low,high) ((unsigned long)(((unsigned short)(low)) | (((unsigned long)((unsigned short)(high))) << 16))) + +#include "externals.h" +#include "cfg.h" +#include "gpu.h" + +///////////////////////////////////////////////////////////////////////////// +// CONFIG FILE helpers.... used in (non-fpse) Linux and ZN Windows +///////////////////////////////////////////////////////////////////////////// + +char * pConfigFile=NULL; + +#include + +// some helper macros: + +#define GetValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') var = atoi(p); \ + } + +#define GetFloatValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') var = (float)atof(p); \ + } + +#define SetValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') { \ + len = sprintf(t1, "%d", var); \ + strncpy(p, t1, len); \ + if (p[len] != ' ' && p[len] != '\n' && p[len] != 0) p[len] = ' '; \ + } \ + } \ + else { \ + size+=sprintf(pB+size, "%s = %d\n", name, var); \ + } + +#define SetFloatValue(name, var) \ + p = strstr(pB, name); \ + if (p != NULL) { \ + p+=strlen(name); \ + while ((*p == ' ') || (*p == '=')) p++; \ + if (*p != '\n') { \ + len = sprintf(t1, "%.1f", (float)var); \ + strncpy(p, t1, len); \ + if (p[len] != ' ' && p[len] != '\n' && p[len] != 0) p[len] = ' '; \ + } \ + } \ + else { \ + size+=sprintf(pB+size, "%s = %.1f\n", name, (float)var); \ + } + +///////////////////////////////////////////////////////////////////////////// + +void ReadConfigFile() +{ + struct stat buf; + FILE *in;char t[256]; + int size; + //int len; + char * pB, * p; + + if(pConfigFile) + strcpy(t,pConfigFile); + else + { + strcpy(t,"cfg/gpuPeopsSoftX.cfg"); + in = fopen(t,"rb"); + if (!in) + { + strcpy(t,"gpuPeopsSoftX.cfg"); + in = fopen(t,"rb"); + if(!in) sprintf(t,"%s/gpuPeopsSoftX.cfg",getenv("HOME")); + else fclose(in); + } + else fclose(in); + } + + if (stat(t, &buf) == -1) return; + size = buf.st_size; + + in = fopen(t,"rb"); + if (!in) return; + + pB=(char *)malloc(size); + memset(pB,0,size); + + //len = + fread(pB, 1, size, in); + fclose(in); + + GetValue("ResX", iResX); + if(iResX<20) iResX=20; + iResX=(iResX/4)*4; + + GetValue("ResY", iResY); + if(iResY<20) iResY=20; + iResY=(iResY/4)*4; + + iWinSize=MAKELONG(iResX,iResY); + + GetValue("NoStretch", iUseNoStretchBlt); + + GetValue("Dithering", iUseDither); + + GetValue("FullScreen", iWindowMode); + if(iWindowMode!=0) iWindowMode=0; + else iWindowMode=1; + + GetValue("ShowFPS", iShowFPS); + if(iShowFPS<0) iShowFPS=0; + if(iShowFPS>1) iShowFPS=1; + + GetValue("SSSPSXLimit", bSSSPSXLimit); + if(iShowFPS<0) iShowFPS=0; + if(iShowFPS>1) iShowFPS=1; + + GetValue("ScanLines", iUseScanLines); + if(iUseScanLines<0) iUseScanLines=0; + if(iUseScanLines>1) iUseScanLines=1; + + GetValue("UseFrameLimit", UseFrameLimit); + if(UseFrameLimit<0) UseFrameLimit=0; + if(UseFrameLimit>1) UseFrameLimit=1; + + GetValue("UseFrameSkip", UseFrameSkip); + if(UseFrameSkip<0) UseFrameSkip=0; + if(UseFrameSkip>1) UseFrameSkip=1; + + GetValue("FPSDetection", iFrameLimit); + if(iFrameLimit<1) iFrameLimit=1; + if(iFrameLimit>2) iFrameLimit=2; + + GetFloatValue("FrameRate", fFrameRate); + if(fFrameRate<10.0f) fFrameRate=10.0f; + if(fFrameRate>1000.0f) fFrameRate=1000.0f; + + GetValue("CfgFixes", dwCfgFixes); + + GetValue("UseFixes", iUseFixes); + if(iUseFixes<0) iUseFixes=0; + if(iUseFixes>1) iUseFixes=1; + + free(pB); + +} + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +void ExecCfg(char *arg) { + char cfg[256]; + struct stat buf; + + strcpy(cfg, "./cfgPeopsSoft"); + if (stat(cfg, &buf) != -1) { + strcat(cfg, " "); + strcat(cfg, arg); + system(cfg); return; + } + + strcpy(cfg, "./cfg/cfgPeopsSoft"); + if (stat(cfg, &buf) != -1) { + strcat(cfg, " "); + strcat(cfg, arg); + system(cfg); return; + } + + sprintf(cfg, "%s/cfgPeopsSoft", getenv("HOME")); + if (stat(cfg, &buf) != -1) { + strcat(cfg, " "); + strcat(cfg, arg); + system(cfg); return; + } + + printf("cfgPeopsSoft file not found!\n"); +} + +void SoftDlgProc(void) +{ + ExecCfg("configure"); +} + +extern unsigned char revision; +extern unsigned char build; +#define RELEASE_DATE "01.05.2008" + +void AboutDlgProc(void) +{ + char args[256]; + + sprintf(args, "about %d %d %s", revision, build, RELEASE_DATE); + ExecCfg(args); +} + + +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// + +void ReadConfig(void) +{ + // defaults + iResX=640;iResY=480; + iWinSize=MAKELONG(iResX,iResY); + iColDepth=16; + iWindowMode=1; + iUseScanLines=0; + if (frameLimit == FRAMELIMIT_AUTO) + { + UseFrameLimit=1; + iFrameLimit=2; + } + else + { + UseFrameLimit=0; + iFrameLimit=0; + } + UseFrameSkip = frameSkip; + fFrameRate=60.0f; + dwCfgFixes=0; + iUseFixes=0; + iUseNoStretchBlt=1; + iShowFPS=0; + bSSSPSXLimit=FALSE; + + // read sets + ReadConfigFile(); + + // additional checks + if(!iColDepth) iColDepth=32; + if(iUseFixes) dwActFixes=dwCfgFixes; + SetFixes(); +} + +void WriteConfig(void) { + + struct stat buf; + FILE *out;char t[256];int len, size; + char * pB, * p; char t1[8]; + + if(pConfigFile) + strcpy(t,pConfigFile); + else + { + strcpy(t,"cfg/gpuPeopsSoftX.cfg"); + out = fopen(t,"rb"); + if (!out) + { + strcpy(t,"gpuPeopsSoftX.cfg"); + out = fopen(t,"rb"); + if(!out) sprintf(t,"%s/gpuPeopsSoftX.cfg",getenv("HOME")); + else fclose(out); + } + else fclose(out); + } + + if (stat(t, &buf) != -1) size = buf.st_size; + else size = 0; + + out = fopen(t,"rb"); + if (!out) { + // defaults + iResX=640;iResY=480; + iColDepth=16; + iWindowMode=1; + iUseScanLines=0; + UseFrameLimit=0; + UseFrameSkip=0; + iFrameLimit=2; + fFrameRate=200.0f; + dwCfgFixes=0; + iUseFixes=0; + iUseNoStretchBlt=1; + iUseDither=0; + iShowFPS=0; + bSSSPSXLimit=FALSE; + + size = 0; + pB=(char *)malloc(4096); + memset(pB,0,4096); + } + else { + pB=(char *)malloc(size+4096); + memset(pB,0,size+4096); + + len = fread(pB, 1, size, out); + fclose(out); + } + + SetValue("ResX", iResX); + SetValue("ResY", iResY); + SetValue("NoStretch", iUseNoStretchBlt); + SetValue("Dithering", iUseDither); + SetValue("FullScreen", !iWindowMode); + SetValue("ShowFPS", iShowFPS); + SetValue("SSSPSXLimit", bSSSPSXLimit); + SetValue("ScanLines", iUseScanLines); + SetValue("UseFrameLimit", UseFrameLimit); + SetValue("UseFrameSkip", UseFrameSkip); + SetValue("FPSDetection", iFrameLimit); + SetFloatValue("FrameRate", fFrameRate); + SetValue("CfgFixes", (int)dwCfgFixes); + SetValue("UseFixes", iUseFixes); + + out = fopen(t,"wb"); + if (!out) { + if(pB) free(pB); + return; + } + + fwrite(pB, 1, size, out); + fclose(out); + + free(pB); + +} + + + + + diff --git a/PeopsSoftGPU/cfg.h b/PeopsSoftGPU/cfg.h new file mode 100644 index 0000000..8cd8cd5 --- /dev/null +++ b/PeopsSoftGPU/cfg.h @@ -0,0 +1,38 @@ +/*************************************************************************** + cfg.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_CFG_H_ +#define _GPU_CFG_H_ + +void ReadConfig(void); +void WriteConfig(void); +void ReadWinSizeConfig(void); + +void SoftDlgProc(void); +void AboutDlgProc(void); + +#endif // _GPU_CFG_H_ + diff --git a/PeopsSoftGPU/changelog.txt b/PeopsSoftGPU/changelog.txt new file mode 100644 index 0000000..135b71a --- /dev/null +++ b/PeopsSoftGPU/changelog.txt @@ -0,0 +1,474 @@ +######################################################################### + +Version 1.18 +------------ + +- added visual rumble funcs - Pete + + files changed: gpu.c, draw.c + +- changed save state picture function - Pete + + files changed: gpu.c + +- added 'fake gpu busy states' game fix - Pete + + files changed: gpu.c, cfg.c + +- added 'GPUsetfix' function - Pete + + files changed: gpu.c, gpuPeopsSoft.def + +- added 'GPUsetframelimit' function - Pete + + files changed: gpu.c, gpuPeopsSoft.def + +- added 'sleep' fps limitation and new fps timings - Nagisa/SSSPSX + + files changed: fps.c + +- added MMX screen filters and some fixes - MxC + + files changed: draw.c, cfg.c, hq....asm files added + + +Version 1.17 +------------ + +- changed user frame limit to floating point value - Pete + + files changed: menu.c, fpsewp.c, fps.c, externals.h, conf.c, key.c, cfg.c + +- added game fix 0x200 (g-shaded quads) - Pete + + files changed: soft.c + +- added 25% mode 3 blending - Pete + + files changed: soft.c + +- added y sprite mirror - Pete + + files changed: soft.c, prim.c + +- added HQ2X,HQ3X,Scale3X screen filters - MxC + + files changed: draw.c, cfg.c + + +Version 1.16 +------------ + +- added ZN stuff - Pete + + files changed: too many to mention ;) + +- improved X8F6VM fullscreen switching a little - Stefan Sperling + + files changed: draw.c + +- added sprite y coord wrap (skullmonkey) - Pete + + files changed: prim.c + +- added game fix 0x100 (dark forces) - Pete + + files changed: soft.c + + +Version 1.15 +------------ + +- fixed frame limitation if "old skipping method" is used - Pete + + files changed: fps.c + +- added pad core flags display - Pete + + files changed: menu.c + +- added sprite x coord wrap (skullmonkey) - Pete + + files changed: prim.c + +- new mingw patches - yokota + + +Version 1.14 +------------ + +- repaired AVISetStreamFormat call in recording funcs - Avery Lee + + files changed: record.c + +- added mingw patches in the "makes" directoy - yokota + +- rewrote Linux Config/About dialogs using Glade / fullscreen modes are get through XF86VM if enabled - linuzappz + + files changed: conf.c + files added: callbacks.c, callbacks.h, interface.c, interface.h, support.c, support.h + + +Version 1.12 +------------ + +- fixed wrapped y display position offset (Legend of Legaia) - Pete + + Files changed: gpu.c + +- the odd/even bit hack (CronoCross status screen) is now a special game fix - Pete + + Files changed: gpu.c + +- gun cursor interface and drawing func - Pete + + Files changed: gpu.c, draw.c + +- added Scale2x display mode - Scale2x (C) 2002 Andrea Mazzoleni (http://scale2x.sourceforge.net) - Pete + + Files changed: draw.c + +- improved frameskip func and added 'old skipping' game fix - Pete + + Files changed: fps.c, gpu.c + +- added dithering and improved g-shading - Pete, thanx to FF + + Files changed: soft.c, prim.c, menu.c, cfg.c, conf.c + +- some more messages for DGA2 errors - linuzappz + improved XStretch funcs a little - linuzappz + fixed non-streched modes for DGA2 - linuzappz + + Files changed: draw.c + + +Version 1.11 +------------ + +- added new frameskip func support and win timer game fix - Pete + + Files changed: gpu.c, fps.c, key.c + +- fixed 5bit masks for 2xSai - linuzappz + + Files changed: draw.c + + +Version 1.10 +------------ + +- changed the y display pos handling - Farfetch'd & Pete + + Files changed: gpu.c + +- added 2xSai, Super2xSaI, SuperEagle - Pete + + Files changed: draw.c, cfg.c, conf.c + + +Version 1.9 +----------- + +- changed: polylines, 11 bit coords, polygon discarding, BlkFill align - Farfetch'd & Pete + + Files changed: prim.c + +- changed: mask bit handling - Farfetch'd & Pete + + Files changed: soft.c, prim.c + +- added all kind of tiny stuff (gpureset, gpugetinfo, dmachain align, polylines, ...) - Farfetch'd & Pete + + Files changed: gpu.c + +- fixed gpuwritedatamem & now doing every data processing with it - Pete + + Files changed: gpu.c + +- added Win debug mode & full vram view key config - Pete + + Files changed: cfg.c, key.c, draw.c + +- separated linux gui to conf.c - linuzappz + + Files changed: cfg.c, mk.X11 + Files added: conf.c + +- STP: read control register is now masked correctly with 0x3 - Farfetch'd + + Files changed: prim.c + + +Version 1.8 +----------- + +- delayed odd/even toggle for FF8 intro scanlines - Pete + + Files changed: gpu.c + +- additional mask bit handling for sprites (AitD4) - Pete + + Files changed: prim.c + +- correct TW coord adjustment (RRT4) - Lewpy & E}I{ + + Files changed: prim.c + +- added DrawString calls for DGA2 (FPS display) - linuzappz + + Files changed: draw.c + Files added: drawstring.c, drawstring.h, drawstringfont.h + +- "Sprite 1" command count added - Pete + + Files changed: gpu.c + +- handles "screen disable" correctly - Pete + + Files changed: gpu.c + + +Version 1.7 +----------- + +- dmawrite/read wrap around - Pete + + Files changed: gpu.c + +- removed dmachain fixes, added dma endless loop detection instead - Pete + + Files changed: gpu.c + +- new line drawing funcs - Lewpy + + Files changed: prim.c, soft.c, soft.h + +- Win95/NT "disable screensaver" fix - Lewpy + + Files changed: gpu.c + +- fixed linux about dialog - linuzappz + + Files changed: cfg.c + +- fixed a mask bit problem with FF9 - Pete + + Files changed: prim.c + +- changed dmachain handler (monkey hero) - Pete + + Files changed: gpu.c, prim.c + + + +Version 1.6 +----------- + +- fast forward frame skipping - linuzappz + + Files changed: gpu.c, key.c, menu.c + +- mdec mask bit problem in FF9 fixed - Pete + + Files changed: prim.c + +- Added dmachain "0" game fix (Ranma1/2) - Pete + + Files changed: gpu.c + +- new coordinate checks, to remove weird polys + (MGS, etc) - Pete + + Files changed: prim.c + +- Added extra code to remove distortions on g-shaded + texture rects - Pete + + Files changed: soft.c + +- Re-done all texture-window funcs... much better + speed - Pete + + Files changed: soft.c + +- Mask bit fixed for non-textured primitives + (Bloody Roar 2, Ace Combat 3) - Pete + + Files changed: soft.c + +- Doom fixed - Pete + + Files changed: soft.c + + +Version 1.5 +----------- + +- fixed mk.x11 - lu + +- added optional SDL only direct blit and direct + stretch - lu + + Files changed: draw.c + +- added Linux fullscreen DGA2 support - linuzappz + + Files changed: draw.c, menu.c, gpu.c + +- added Lunar "ignore blending color" and capcom 2d + fighter fixes - Pete + + Files changed: prim.c, cfg.c, key.c + +- removed "no sprite transparency" and "black poly" + fixes - Pete + + Files changed: prim.c + +- additional Load/MoveImage checks for a few FF9/BOF4 + effects - Pete + + Files changed: prim.c + +- Added dmacheck for The Mummy and T'ai Fu - Pete + + Files changed: gpu.c + + +Version 1.4 +----------- +- Fixed a possible closing issue in the gtk dialog and added + an #ifdef for the title (X11 vs SDL) - lu + + Files changed: cfg.c + +- Enabled configuration for linux FPSE - lu + + Files changed: fpsewp.c gpu.c + +- Fixed linux stretch centering (no more garbled screens in + Star Ocean 2/Grandia/etc) - Pete + + Files changed: draw.c + +- Fixed unwanted screen clearing on horizontal centering - Pete + + Files changed: gpu.c + +- Added "Wait VSYNC" (Windows) - syo + + Files changed: cfg.c draw.c + +- Added toggle "Wait VSYNC" key (Windows) - syo + + Files changed: cfg.c key.c draw.c + +- support refresh rate change (Windows) - syo + + Files changed: cfg.c draw.c + +- added "Transparent menu" (Windows) - syo + + Files changed: cfg.c menu.c + +- enhanced recording: two types of compression (16bit & 24bit) + and FPSE 24bit MDEC support - Darko Matesic + + Files changed: cfg.c, record.c, record.h, win recording dialog + +- linux fullscreen switching (without SDL) - Pete + + Files changed: draw.c + +- linux config dialog fix - linuzappz + + Files changed: cfg.c + + +Version 1.3 +----------- + +- Added Windows FPSE RGB24 mode switch - Pete + + Files changed: fpsewp.c, draw.c, externals.h + +- Yet Another FPSE layer change (hopefully the last one) - lu_zero + + Files changed: fpsewp.c key.c + +- SDL linux fullsreen funcs by lu_zero + + Files changed: gpu.c, draw.c, fpsewp.c + +- added support for 15 bit texture window primitives - Pete + + Files changed: soft.c + +- fix for Grandia in ChangeDispOffsetsX - Pete + + Files changed: gpu.c + +- added special coord checks for Nascar and Syphon Filter 2 - Pete + + Files changed: prim.c + +- fixed a mask bit bug in drawPoly4F - Pete + + Files changed: soft.c + +- added "Use system memory" by syo (syo68k@geocities.co.jp) + (small fixes in save state pic and nvidia scanlines by Pete) + + Files changed: cfg.c draw.c + +- added "Stop screen saver" by syo (syo68k@geocities.co.jp) + + Files changed: cfg.c gpu.c + +- fixed display mode change problem by syo (syo68k@geocities.co.jp) + + Since the radio button was not operating correctly, + it corrects that change in display mode was not completed correctly. + + Files changed: cfg.c + +- native W32 fpse interface funcs by lu_zero + + Files changed: fpsewp.c + +- linux config dialog by linuzappz + + Files changed: cfg.c, gpu.c + + +Version 1.2 +----------- + +- avi recording funcs by Darko + (small adjustments of the recording gpu key/dialog/menu by Pete) + + Files changed: cfg.c, gpu.c ,key.c, menu.c + Files added: record.c, record.h + +- nasm support for windows/linux by linuzappz + note: if you can't/don't want to use nasm, you can remove the + __i386__ define in the project settings + To use nasm (Win version), copy the nasm files into your + VC98/bin directory, and set the MSVCDIR enviroment var to the + VC98 directory. + + Files changed: soft.c, prim.c, Makefile + Files added: i386.asm, macros.inc + +- SDL 1.2.x and FPSE layer support by lu_zero + -D_SDL <--Will set up SDL stuff + -D_FPSE,add the fpsewp.o <--Will add the layer + Note I have to fix the win32 related part. + +Version 1.1 +----------- +- First release + +######################################################################### + diff --git a/PeopsSoftGPU/draw.c.old b/PeopsSoftGPU/draw.c.old new file mode 100644 index 0000000..f978b11 --- /dev/null +++ b/PeopsSoftGPU/draw.c.old @@ -0,0 +1,8096 @@ +/*************************************************************************** + draw.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2008/05/17 - Pete +// - added "visual rumble" stuff to buffer swap func +// +// 2007/10/27 - MxC +// - added HQ2X/HQ3X MMX versions, and fixed stretching +// +// 2005/06/11 - MxC +// - added HQ2X,HQ3X,Scale3X screen filters +// +// 2004/01/31 - Pete +// - added zn stuff +// +// 2003/01/31 - stsp +// - added zn stuff +// +// 2003/12/30 - Stefan Sperling +// - improved XF86VM fullscreen switching a little (refresh frequency issues). +// +// 2002/12/30 - Pete +// - added Scale2x display mode - Scale2x (C) 2002 Andrea Mazzoleni - http://scale2x.sourceforge.net +// +// 2002/12/29 - Pete +// - added gun cursor display +// +// 2002/12/21 - linuzappz +// - some more messages for DGA2 errors +// - improved XStretch funcs a little +// - fixed non-streched modes for DGA2 +// +// 2002/11/10 - linuzappz +// - fixed 5bit masks for 2xSai/etc +// +// 2002/11/06 - Pete +// - added 2xSai, Super2xSaI, SuperEagle +// +// 2002/08/09 - linuzappz +// - added DrawString calls for DGA2 (FPS display) +// +// 2002/03/10 - lu +// - Initial SDL-only blitting function +// - Initial SDL stretch function (using an undocumented SDL 1.2 func) +// - Boht are triggered by -D_SDL -D_SDL2 +// +// 2002/02/18 - linuzappz +// - NoStretch, PIC and Scanlines support for DGA2 (32bit modes untested) +// - Fixed PIC colors in CreatePic for 16/15 bit modes +// +// 2002/02/17 - linuzappz +// - Added DGA2 support, support only with no strecthing disabled (also no FPS display) +// +// 2002/01/13 - linuzappz +// - Added timing for the szDebugText (to 2 secs) +// +// 2002/01/05 - Pete +// - fixed linux stretch centering (no more garbled screens) +// +// 2001/12/30 - Pete +// - Added linux fullscreen desktop switching (non-SDL version, define USE_XF86VM in Makefile) +// +// 2001/12/19 - syo +// - support refresh rate change +// - added wait VSYNC +// +// 2001/12/16 - Pete +// - Added Windows FPSE RGB24 mode switch +// +// 2001/12/05 - syo (syo68k@geocities.co.jp) +// - modified for "Use system memory" option +// (Pete: fixed "system memory" save state pic surface) +// +// 2001/11/11 - lu +// - SDL additions +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifdef __GX__ +#include +#include +#endif // __GX__ + +#include "stdafx.h" + +#define _IN_DRAW + +#include "externals.h" +#include "gpu.h" +#include "draw.h" +#include "prim.h" +#include "menu.h" +#include "swap.h" + +//////////////////////////////////////////////////////////////////////////////////// +// misc globals +//////////////////////////////////////////////////////////////////////////////////// +int iResX; +int iResY; +long lLowerpart; +BOOL bIsFirstFrame = TRUE; +BOOL bCheckMask=FALSE; +unsigned short sSetMask=0; +unsigned long lSetMask=0; +int iDesktopCol=16; +int iShowFPS=0; +int iWinSize; +int iUseScanLines=0; +int iUseNoStretchBlt=0; +int iFastFwd=0; +int iDebugMode=0; +int iFVDisplay=0; +PSXPoint_t ptCursorPoint[8]; +unsigned short usCursorActive=0; + +unsigned int LUT16to32[65536]; +unsigned int RGBtoYUV[65536]; + +// prototypes +extern void hq2x_16( unsigned char * srcPtr, DWORD srcPitch, unsigned char * dstPtr, int width, int height); +extern void hq3x_16( unsigned char * srcPtr, DWORD srcPitch, unsigned char * dstPtr, int width, int height); +extern void hq2x_32( unsigned char * srcPtr, DWORD srcPitch, unsigned char * dstPtr, int width, int height); +extern void hq3x_32( unsigned char * srcPtr, DWORD srcPitch, unsigned char * dstPtr, int width, int height); +void NoStretchedBlit2x(void); +void NoStretchedBlit3x(void); +void StretchedBlit2x(void); +void StretchedBlit3x(void); + +#ifdef __GX__ +extern u32* xfb[2]; /*** Framebuffers ***/ +extern int whichfb; /*** Frame buffer toggle ***/ +#endif //__GX__ + + +//////////////////////////////////////////////////////////////////////// +// HQ Initialize Lookup Table +//////////////////////////////////////////////////////////////////////// + +int InitLUTs(void) +{ + int i, j, k, r, g, b, Y, u, v; + int nMMXsupport = 0; + for (i=0; i<65536; i++) + LUT16to32[i] = ((i & 0xF800) << 8) + ((i & 0x07E0) << 5) + ((i & 0x001F) << 3); + + for (i=0; i<32; i++) + for (j=0; j<64; j++) + for (k=0; k<32; k++) + { + r = i << 3; + g = j << 2; + b = k << 3; + Y = (r + g + b) >> 2; + u = 128 + ((r - b) >> 2); + v = 128 + ((-r + 2*g -b)>>3); + RGBtoYUV[ (i << 11) + (j << 5) + k ] = (Y<<16) + (u<<8) + v; + } + +// This part of the function isn't really needed +// Could just snip this and make it return void +// and make MMX detection it's own function + +#ifndef __GX__ +#ifdef __GNUC__ + __asm__ __volatile__ ("movl $1, %%eax":::"eax"); + __asm__ __volatile__ ("cpuid"); + __asm__ __volatile__ ( "and $0x00800000, %%edx":::"edx"); + __asm__ __volatile__ ( "movl %%edx, %0": "=g" (nMMXsupport)); +#else + __asm + { + mov eax, 1 + cpuid + and edx, 0x00800000 + mov nMMXsupport, edx + } +#endif +#endif //!__GX__ + return nMMXsupport; +} + +//////////////////////////////////////////////////////////////////////// +// generic 2xSaI helpers +//////////////////////////////////////////////////////////////////////// + +void * pSaISmallBuff=NULL; +void * pSaIBigBuff=NULL; + +#define GET_RESULT(A, B, C, D) ((A != C || A != D) - (B != C || B != D)) + +static __inline int GetResult1(DWORD A, DWORD B, DWORD C, DWORD D, DWORD E) +{ + int x = 0; + int y = 0; + int r = 0; + if (A == C) x+=1; else if (B == C) y+=1; + if (A == D) x+=1; else if (B == D) y+=1; + if (x <= 1) r+=1; + if (y <= 1) r-=1; + return r; +} + +static __inline int GetResult2(DWORD A, DWORD B, DWORD C, DWORD D, DWORD E) +{ + int x = 0; + int y = 0; + int r = 0; + if (A == C) x+=1; else if (B == C) y+=1; + if (A == D) x+=1; else if (B == D) y+=1; + if (x <= 1) r-=1; + if (y <= 1) r+=1; + return r; +} + +#define colorMask8 0x00FEFEFE +#define lowPixelMask8 0x00010101 +#define qcolorMask8 0x00FCFCFC +#define qlowpixelMask8 0x00030303 + +#define INTERPOLATE8(A, B) ((((A & colorMask8) >> 1) + ((B & colorMask8) >> 1) + (A & B & lowPixelMask8))) +#define Q_INTERPOLATE8(A, B, C, D) (((((A & qcolorMask8) >> 2) + ((B & qcolorMask8) >> 2) + ((C & qcolorMask8) >> 2) + ((D & qcolorMask8) >> 2) \ + + ((((A & qlowpixelMask8) + (B & qlowpixelMask8) + (C & qlowpixelMask8) + (D & qlowpixelMask8)) >> 2) & qlowpixelMask8)))) + + +void Super2xSaI_ex8(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + DWORD srcPitchHalf = srcPitch>>1; + int finWidth = srcPitch>>2; + DWORD line; + DWORD *dP; + DWORD *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (DWORD *)srcPtr; + dP = (DWORD *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) {iYA=0;} + else {iYA=finWidth;} + if(height>4) {iYB=finWidth;iYC=srcPitchHalf;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorB0 = *(bP- iYA - iXA); + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + colorB3 = *(bP- iYA + iXC); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA0 = *(bP + iYC - iXA); + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + colorA3 = *(bP + iYC + iXC); + + if (color2 == color6 && color5 != color3) + { + product2b = product1b = color2; + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1b = color5; + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color1&0x00ffffff), (colorA1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color4&0x00ffffff), (colorB1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorA2&0x00ffffff), (colorS1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorB2&0x00ffffff), (colorS2&0x00ffffff)); + + if (r > 0) + product2b = product1b = color6; + else + if (r < 0) + product2b = product1b = color5; + else + { + product2b = product1b = INTERPOLATE8(color5, color6); + } + } + else + { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE8 (color3, color3, color3, color2); + else + if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE8 (color2, color2, color2, color3); + else + product2b = INTERPOLATE8 (color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE8 (color6, color6, color6, color5); + else + if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE8 (color6, color5, color5, color5); + else + product1b = INTERPOLATE8 (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE8(color2, color5); + else + if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE8(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE8(color2, color5); + else + if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE8(color2, color5); + else + product1a = color5; + + *dP=product1a; + *(dP+1)=product1b; + *(dP+(srcPitchHalf))=product2a; + *(dP+1+(srcPitchHalf))=product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +void Std2xSaI_ex8(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + DWORD srcPitchHalf = srcPitch>>1; + int finWidth = srcPitch>>2; + DWORD line; + DWORD *dP; + DWORD *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + + DWORD colorA, colorB; + DWORD colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + colorM, colorN, colorO, colorP; + DWORD product, product1, product2; + + line = 0; + + { + for (; height; height-=1) + { + bP = (DWORD *)srcPtr; + dP = (DWORD *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) {iYA=0;} + else {iYA=finWidth;} + if(height>4) {iYB=finWidth;iYC=srcPitchHalf;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorI = *(bP- iYA - iXA); + colorE = *(bP- iYA); + colorF = *(bP- iYA + iXB); + colorJ = *(bP- iYA + iXC); + + colorG = *(bP - iXA); + colorA = *(bP); + colorB = *(bP + iXB); + colorK = *(bP + iXC); + + colorH = *(bP + iYB - iXA); + colorC = *(bP + iYB); + colorD = *(bP + iYB + iXB); + colorL = *(bP + iYB + iXC); + + colorM = *(bP + iYC - iXA); + colorN = *(bP + iYC); + colorO = *(bP + iYC + iXB); + colorP = *(bP + iYC + iXC); + + + if((colorA == colorD) && (colorB != colorC)) + { + if(((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ))) + { + product = colorA; + } + else + { + product = INTERPOLATE8(colorA, colorB); + } + + if(((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM))) + { + product1 = colorA; + } + else + { + product1 = INTERPOLATE8(colorA, colorC); + } + product2 = colorA; + } + else + if((colorB == colorC) && (colorA != colorD)) + { + if(((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) && + (colorA != colorF) && (colorA == colorI))) + { + product = colorB; + } + else + { + product = INTERPOLATE8(colorA, colorB); + } + + if(((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI))) + { + product1 = colorC; + } + else + { + product1=INTERPOLATE8(colorA, colorC); + } + product2 = colorB; + } + else + if((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + register int r = 0; + product1 = INTERPOLATE8(colorA, colorC); + product = INTERPOLATE8(colorA, colorB); + + r += GetResult1 (colorA&0x00FFFFFF, colorB&0x00FFFFFF, colorG&0x00FFFFFF, colorE&0x00FFFFFF, colorI&0x00FFFFFF); + r += GetResult2 (colorB&0x00FFFFFF, colorA&0x00FFFFFF, colorK&0x00FFFFFF, colorF&0x00FFFFFF, colorJ&0x00FFFFFF); + r += GetResult2 (colorB&0x00FFFFFF, colorA&0x00FFFFFF, colorH&0x00FFFFFF, colorN&0x00FFFFFF, colorM&0x00FFFFFF); + r += GetResult1 (colorA&0x00FFFFFF, colorB&0x00FFFFFF, colorL&0x00FFFFFF, colorO&0x00FFFFFF, colorP&0x00FFFFFF); + + if (r > 0) + product2 = colorA; + else + if (r < 0) + product2 = colorB; + else + { + product2 = Q_INTERPOLATE8(colorA, colorB, colorC, colorD); + } + } + } + else + { + product2 = Q_INTERPOLATE8(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ)) + { + product = colorA; + } + else + if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI)) + { + product = colorB; + } + else + { + product = INTERPOLATE8(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM)) + { + product1 = colorA; + } + else + if ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI)) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE8(colorA, colorC); + } + } + +////////////////////////// + + *dP=colorA; + *(dP+1)=product; + *(dP+(srcPitchHalf))=product1; + *(dP+1+(srcPitchHalf))=product2; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +void SuperEagle_ex8(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + DWORD srcPitchHalf = srcPitch>>1; + int finWidth = srcPitch>>2; + DWORD line; + DWORD *dP; + DWORD *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA1, colorA2, + colorB1, colorB2, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (DWORD *)srcPtr; + dP = (DWORD *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) {iYA=0;} + else {iYA=finWidth;} + if(height>4) {iYB=finWidth;iYC=srcPitchHalf;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + + if(color2 == color6 && color5 != color3) + { + product1b = product2a = color2; + if((color1 == color2) || + (color6 == colorB2)) + { + product1a = INTERPOLATE8(color2, color5); + product1a = INTERPOLATE8(color2, product1a); + } + else + { + product1a = INTERPOLATE8(color5, color6); + } + + if((color6 == colorS2) || + (color2 == colorA1)) + { + product2b = INTERPOLATE8(color2, color3); + product2b = INTERPOLATE8(color2, product2b); + } + else + { + product2b = INTERPOLATE8(color2, color3); + } + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || + (color3 == colorS1)) + { + product1b = INTERPOLATE8(color5, color6); + product1b = INTERPOLATE8(color5, product1b); + } + else + { + product1b = INTERPOLATE8(color5, color6); + } + + if ((color3 == colorA2) || + (color4 == color5)) + { + product2a = INTERPOLATE8(color5, color2); + product2a = INTERPOLATE8(color5, product2a); + } + else + { + product2a = INTERPOLATE8(color2, color3); + } + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color1&0x00ffffff), (colorA1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (color4&0x00ffffff), (colorB1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorA2&0x00ffffff), (colorS1&0x00ffffff)); + r += GET_RESULT ((color6&0x00ffffff), (color5&0x00ffffff), (colorB2&0x00ffffff), (colorS2&0x00ffffff)); + + if (r > 0) + { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE8(color5, color6); + } + else + if (r < 0) + { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE8(color5, color6); + } + else + { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + else + { + product2b = product1a = INTERPOLATE8(color2, color6); + product2b = Q_INTERPOLATE8(color3, color3, color3, product2b); + product1a = Q_INTERPOLATE8(color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE8(color5, color3); + product2a = Q_INTERPOLATE8(color2, color2, color2, product2a); + product1b = Q_INTERPOLATE8(color6, color6, color6, product1b); + } + +//////////////////////////////// + + *dP=product1a; + *(dP+1)=product1b; + *(dP+(srcPitchHalf))=product2a; + *(dP+1+(srcPitchHalf))=product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +///////////////////////// + +static __inline void scale2x_32_def_whole(unsigned long* dst0, unsigned long* dst1, const unsigned long* src0, const unsigned long* src1, const unsigned long* src2, unsigned count) +{ + + // first pixel + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[0] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + + // central pixels + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[1] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[1] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 2; + dst1 += 2; + --count; + } + + // last pixel + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src0[0] : src1[0]; + dst0[1] = src1[0] == src0[0] ? src0[0] : src1[0]; + dst1[0] = src1[-1] == src2[0] ? src2[0] : src1[0]; + dst1[1] = src1[0] == src2[0] ? src2[0] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + } +} + + + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +void Scale2x_ex8(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstPtr, int width, int height) +{ +#ifdef _WINDOWS + + const int dstPitch = srcPitch; + int srcpitch = srcPitch >> 2; + int count = height; + + unsigned long *dst0 = (unsigned long *)dstPtr; + unsigned long *dst1 = dst0 + (dstPitch >> 1); + + unsigned long *src0 = (unsigned long *)srcPtr; + unsigned long *src1 = src0 + srcpitch; + unsigned long *src2 = src1 + srcpitch; + scale2x_32_def_whole(dst0, dst1, src0, src0, src1, width); + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + scale2x_32_def_whole(dst0, dst1, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcpitch; + --count; + } + dst0 += dstPitch; + dst1 += dstPitch; + scale2x_32_def_whole(dst0, dst1, src0, src1, src1, width); +#else + + int looph, loopw; + + unsigned char * srcpix = srcPtr; + unsigned char * dstpix = dstPtr; + + const int srcpitch = srcPitch; + const int dstpitch = srcPitch<<1; + + unsigned long E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = *(unsigned long*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw)); + D = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1))); + E = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*loopw)); + F = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*MIN(width-1,loopw+1))); + H = *(unsigned long*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*loopw)); + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = B == F ? F : E; + E2 = D == H ? D : E; + E3 = H == F ? F : E; + } else { + E0 = E; + E1 = E; + E2 = E; + E3 = E; + } + + + *(unsigned long*)(dstpix + looph*2*dstpitch + loopw*2*4) = E0; + *(unsigned long*)(dstpix + looph*2*dstpitch + (loopw*2+1)*4) = E1; + *(unsigned long*)(dstpix + (looph*2+1)*dstpitch + loopw*2*4) = E2; + *(unsigned long*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*4) = E3; + } + } +#endif +} + +static __inline void scale3x_16_def_whole(unsigned short* dst0, unsigned short* dst1, unsigned short* dst2, const unsigned short* src0, const unsigned short* src1, const unsigned short* src2, unsigned count) +{ + // first pixel + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0]; + dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[0]; + dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + + // central pixels + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + --count; + } + + // last pixel + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } +} + + +static __inline void scale3x_32_def_whole(unsigned long* dst0, unsigned long* dst1, unsigned long* dst2, const unsigned long* src0, const unsigned long* src1, const unsigned long* src2, unsigned count) +{ + + // first pixel + if (src0[0] != src2[0] && src1[0] != src1[1]) { + dst0[0] = src1[0]; + dst0[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[0]; + dst2[1] = (src1[0] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[0]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + + // central pixels + count -= 2; + while (count) { + if (src0[0] != src2[0] && src1[-1] != src1[1]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[1] == src0[0] ? src1[1] : src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[1] == src2[0] ? src1[1] : src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } + + ++src0; + ++src1; + ++src2; + dst0 += 3; + dst1 += 3; + dst2 += 3; + --count; + } + + // last pixel + if (src0[0] != src2[0] && src1[-1] != src1[0]) { + dst0[0] = src1[-1] == src0[0] ? src1[-1] : src1[0]; + dst0[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0]; + dst0[2] = src1[0]; + dst1[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0]; + dst1[1] = src1[0]; + dst1[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0]; + dst2[0] = src1[-1] == src2[0] ? src1[-1] : src1[0]; + dst2[1] = (src1[-1] == src2[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src2[-1]) ? src2[0] : src1[0]; + dst2[2] = src1[0]; + } else { + dst0[0] = src1[0]; + dst0[1] = src1[0]; + dst0[2] = src1[0]; + dst1[0] = src1[0]; + dst1[1] = src1[0]; + dst1[2] = src1[0]; + dst2[0] = src1[0]; + dst2[1] = src1[0]; + dst2[2] = src1[0]; + } +} + +void Scale3x_ex6_5(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstPtr, int width, int height) +{ +#ifdef _WINDOWS + int count = height; + int dstPitch = srcPitch; + int srcpitch = srcPitch>>1; + + unsigned short *dst0 = (unsigned short *)dstPtr; + unsigned short *dst1 = dst0 + dstPitch; + unsigned short *dst2 = dst1 + dstPitch; + + unsigned short *src0 = (unsigned short *)srcPtr; + unsigned short *src1 = src0 + srcpitch; + unsigned short *src2 = src1 + srcpitch; + scale3x_16_def_whole(dst0, dst1, dst2, src0, src0, src1, count); + dstPitch *= 3; + count -= 2; + while(count) { + + dst0 += dstPitch; + dst1 += dstPitch; + dst2 += dstPitch; + + scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcpitch; + --count; + } + dst0 += dstPitch; + dst1 += dstPitch; + dst2 += dstPitch; + + scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src1, width); +#else + + int looph, loopw; + + unsigned char * srcpix = srcPtr; + unsigned char * dstpix = dstPtr; + + const int srcpitch = srcPitch; + const int dstpitch = srcPitch*3; + + unsigned short E0, E1, E2, E3, E4, E5, E6, E7, E8; + unsigned short A, B, C, D, E, F, G, H, I; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + A = *(unsigned short*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*MAX(0,loopw-1))); + B = *(unsigned short*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*loopw)); + C = *(unsigned short*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*MIN(width-1,loopw+1))); + D = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*MAX(0,loopw-1))); + E = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*loopw)); + F = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*MIN(width-1,loopw+1))); + G = *(unsigned short*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*MAX(0,loopw-1))); + H = *(unsigned short*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*loopw)); + I = *(unsigned short*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*MIN(width-1,loopw+1))); + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = (D == B && E != C) || (B == F && E != A) ? B : E; + E2 = B == F ? F : E; + E3 = (D == B && E != G) || (D == H && E != A) ? D : E; + E4 = E; + E5 = (B == F && E != I) || (H == F && E != C) ? F : E; + E6 = D == H ? D : E; + E7 = (D == H && E != I) || (H == F && E != G) ? H : E; + E8 = H == F ? F : E; + } else { + E0 = E; + E1 = E; + E2 = E; + E3 = E; + E4 = E; + E5 = E; + E6 = E; + E7 = E; + E8 = E; +} + + + *(unsigned long*)(dstpix + looph*3*dstpitch + loopw*3*2) = E0; + *(unsigned long*)(dstpix + looph*3*dstpitch + (loopw*3+1)*2) = E1; + *(unsigned long*)(dstpix + looph*3*dstpitch + (loopw*3+2)*2) = E2; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + loopw*3*2) = E3; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + (loopw*3+1)*2) = E4; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + (loopw*3+2)*2) = E5; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + loopw*3*2) = E6; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + (loopw*3+1)*2) = E7; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + (loopw*3+2)*2) = E8; + } + } +#endif +} + +void Scale3x_ex8(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstPtr, int width, int height) +{ +#ifdef _WINDOWS + int count = height; + + int dstPitch = srcPitch >> 1; + int srcpitch = srcPitch >> 2; + + unsigned long *dst0 = (unsigned long *)dstPtr; + unsigned long *dst1 = dst0 + dstPitch; + unsigned long *dst2 = dst1 + dstPitch; + + unsigned long *src0 = (unsigned long *)srcPtr; + unsigned long *src1 = src0 + srcpitch; + unsigned long *src2 = src1 + srcpitch; + scale3x_32_def_whole(dst0, dst1, dst2, src0, src0, src1, width); + dstPitch *= 3; + count -= 2; + while(count) { + dst0 += dstPitch; + dst1 += dstPitch; + dst2 += dstPitch; + + scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, width); + src0 = src1; + src1 = src2; + src2 += srcpitch; + --count; + } + dst0 += dstPitch; + dst1 += dstPitch; + dst2 += dstPitch; + + scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src1, width); + +#else + + int looph, loopw; + + unsigned char * srcpix = srcPtr; + unsigned char * dstpix = dstPtr; + + const int srcpitch = srcPitch; + const int dstpitch = srcPitch*3; + + unsigned long E0, E1, E2, E3, E4, E5, E6, E7, E8; + unsigned long A, B, C, D, E, F, G, H, I; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + A = *(unsigned long*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*MAX(0,loopw-1))); + B = *(unsigned long*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw)); + C = *(unsigned long*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*MIN(width-1,loopw+1))); + D = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1))); + E = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*loopw)); + F = *(unsigned long*)(srcpix + (looph*srcpitch) + (4*MIN(width-1,loopw+1))); + G = *(unsigned long*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*MAX(0,loopw-1))); + H = *(unsigned long*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*loopw)); + I = *(unsigned long*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (4*MIN(width-1,loopw+1))); + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = (D == B && E != C) || (B == F && E != A) ? B : E; + E2 = B == F ? F : E; + E3 = (D == B && E != G) || (D == H && E != A) ? D : E; + E4 = E; + E5 = (B == F && E != I) || (H == F && E != C) ? F : E; + E6 = D == H ? D : E; + E7 = (D == H && E != I) || (H == F && E != G) ? H : E; + E8 = H == F ? F : E; + } else { + E0 = E; + E1 = E; + E2 = E; + E3 = E; + E4 = E; + E5 = E; + E6 = E; + E7 = E; + E8 = E; +} + + + *(unsigned long*)(dstpix + looph*3*dstpitch + loopw*3*4) = E0; + *(unsigned long*)(dstpix + looph*3*dstpitch + (loopw*3+1)*4) = E1; + *(unsigned long*)(dstpix + looph*3*dstpitch + (loopw*3+2)*4) = E2; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + loopw*3*4) = E3; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + (loopw*3+1)*4) = E4; + *(unsigned long*)(dstpix + (looph*3+1)*dstpitch + (loopw*3+2)*4) = E5; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + loopw*3*4) = E6; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + (loopw*3+1)*4) = E7; + *(unsigned long*)(dstpix + (looph*3+2)*dstpitch + (loopw*3+2)*4) = E8; + } + } +#endif +} + + +//////////////////////////////////////////////////////////////////////// + +#define colorMask6 0x0000F7DE +#define lowPixelMask6 0x00000821 +#define qcolorMask6 0x0000E79c +#define qlowpixelMask6 0x00001863 + +#define INTERPOLATE6(A, B) ((((A & colorMask6) >> 1) + ((B & colorMask6) >> 1) + (A & B & lowPixelMask6))) +#define Q_INTERPOLATE6(A, B, C, D) (((((A & qcolorMask6) >> 2) + ((B & qcolorMask6) >> 2) + ((C & qcolorMask6) >> 2) + ((D & qcolorMask6) >> 2) \ + + ((((A & qlowpixelMask6) + (B & qlowpixelMask6) + (C & qlowpixelMask6) + (D & qlowpixelMask6)) >> 2) & qlowpixelMask6)))) + +void Super2xSaI_ex6(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + + colorB0 = *(bP- iYA - iXA); + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + colorB3 = *(bP- iYA + iXC); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA0 = *(bP + iYC - iXA); + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + colorA3 = *(bP + iYC + iXC); + +//-------------------------------------- + if (color2 == color6 && color5 != color3) + { + product2b = product1b = color2; + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1b = color5; + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6), (color5), (color1), (colorA1)); + r += GET_RESULT ((color6), (color5), (color4), (colorB1)); + r += GET_RESULT ((color6), (color5), (colorA2), (colorS1)); + r += GET_RESULT ((color6), (color5), (colorB2), (colorS2)); + + if (r > 0) + product2b = product1b = color6; + else + if (r < 0) + product2b = product1b = color5; + else + { + product2b = product1b = INTERPOLATE6 (color5, color6); + } + } + else + { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE6 (color3, color3, color3, color2); + else + if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE6 (color2, color2, color2, color3); + else + product2b = INTERPOLATE6 (color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE6 (color6, color6, color6, color5); + else + if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE6 (color6, color5, color5, color5); + else + product1b = INTERPOLATE6 (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE6 (color2, color5); + else + if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE6(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE6(color2, color5); + else + if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE6(color2, color5); + else + product1a = color5; + + *dP=(unsigned short)product1a; + *(dP+1)=(unsigned short)product1b; + *(dP+(srcPitch))=(unsigned short)product2a; + *(dP+1+(srcPitch))=(unsigned short)product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +void Std2xSaI_ex6(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + + DWORD colorA, colorB; + DWORD colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + colorM, colorN, colorO, colorP; + DWORD product, product1, product2; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorI = *(bP- iYA - iXA); + colorE = *(bP- iYA); + colorF = *(bP- iYA + iXB); + colorJ = *(bP- iYA + iXC); + + colorG = *(bP - iXA); + colorA = *(bP); + colorB = *(bP + iXB); + colorK = *(bP + iXC); + + colorH = *(bP + iYB - iXA); + colorC = *(bP + iYB); + colorD = *(bP + iYB + iXB); + colorL = *(bP + iYB + iXC); + + colorM = *(bP + iYC - iXA); + colorN = *(bP + iYC); + colorO = *(bP + iYC + iXB); + colorP = *(bP + iYC + iXC); + + if((colorA == colorD) && (colorB != colorC)) + { + if(((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ))) + { + product = colorA; + } + else + { + product = INTERPOLATE6(colorA, colorB); + } + + if(((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM))) + { + product1 = colorA; + } + else + { + product1 = INTERPOLATE6(colorA, colorC); + } + product2 = colorA; + } + else + if((colorB == colorC) && (colorA != colorD)) + { + if(((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) && + (colorA != colorF) && (colorA == colorI))) + { + product = colorB; + } + else + { + product = INTERPOLATE6(colorA, colorB); + } + + if(((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI))) + { + product1 = colorC; + } + else + { + product1=INTERPOLATE6(colorA, colorC); + } + product2 = colorB; + } + else + if((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + register int r = 0; + product1 = INTERPOLATE6(colorA, colorC); + product = INTERPOLATE6(colorA, colorB); + + r += GetResult1 (colorA, colorB, colorG, colorE, colorI); + r += GetResult2 (colorB, colorA, colorK, colorF, colorJ); + r += GetResult2 (colorB, colorA, colorH, colorN, colorM); + r += GetResult1 (colorA, colorB, colorL, colorO, colorP); + + if (r > 0) + product2 = colorA; + else + if (r < 0) + product2 = colorB; + else + { + product2 = Q_INTERPOLATE6(colorA, colorB, colorC, colorD); + } + } + } + else + { + product2 = Q_INTERPOLATE6(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ)) + { + product = colorA; + } + else + if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI)) + { + product = colorB; + } + else + { + product = INTERPOLATE6(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM)) + { + product1 = colorA; + } + else + if ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI)) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE6(colorA, colorC); + } + } + + *dP=(unsigned short)colorA; + *(dP+1)=(unsigned short)product; + *(dP+(srcPitch))=(unsigned short)product1; + *(dP+1+(srcPitch))=(unsigned short)product2; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } + } + +//////////////////////////////////////////////////////////////////////// + +void SuperEagle_ex6(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA1, colorA2, + colorB1, colorB2, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + + if(color2 == color6 && color5 != color3) + { + product1b = product2a = color2; + if((color1 == color2) || + (color6 == colorB2)) + { + product1a = INTERPOLATE6(color2, color5); + product1a = INTERPOLATE6(color2, product1a); + } + else + { + product1a = INTERPOLATE6(color5, color6); + } + + if((color6 == colorS2) || + (color2 == colorA1)) + { + product2b = INTERPOLATE6(color2, color3); + product2b = INTERPOLATE6(color2, product2b); + } + else + { + product2b = INTERPOLATE6(color2, color3); + } + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || + (color3 == colorS1)) + { + product1b = INTERPOLATE6(color5, color6); + product1b = INTERPOLATE6(color5, product1b); + } + else + { + product1b = INTERPOLATE6(color5, color6); + } + + if ((color3 == colorA2) || + (color4 == color5)) + { + product2a = INTERPOLATE6(color5, color2); + product2a = INTERPOLATE6(color5, product2a); + } + else + { + product2a = INTERPOLATE6(color2, color3); + } + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6), (color5), (color1), (colorA1)); + r += GET_RESULT ((color6), (color5), (color4), (colorB1)); + r += GET_RESULT ((color6), (color5), (colorA2), (colorS1)); + r += GET_RESULT ((color6), (color5), (colorB2), (colorS2)); + + if (r > 0) + { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE6(color5, color6); + } + else + if (r < 0) + { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE6(color5, color6); + } + else + { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + else + { + product2b = product1a = INTERPOLATE6(color2, color6); + product2b = Q_INTERPOLATE6(color3, color3, color3, product2b); + product1a = Q_INTERPOLATE6(color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE6(color5, color3); + product2a = Q_INTERPOLATE6(color2, color2, color2, product2a); + product1b = Q_INTERPOLATE6(color6, color6, color6, product1b); + } + + *dP=(unsigned short)product1a; + *(dP+1)=(unsigned short)product1b; + *(dP+(srcPitch))=(unsigned short)product2a; + *(dP+1+(srcPitch))=(unsigned short)product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +void Scale2x_ex6_5(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + int looph, loopw; + + unsigned char * srcpix = srcPtr; + unsigned char * dstpix = dstBitmap; + + const int srcpitch = srcPitch; + const int dstpitch = srcPitch<<1; + + unsigned short E0, E1, E2, E3, B, D, E, F, H; + for(looph = 0; looph < height; ++looph) + { + for(loopw = 0; loopw < width; ++ loopw) + { + B = *(unsigned short*)(srcpix + (MAX(0,looph-1)*srcpitch) + (2*loopw)); + D = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*MAX(0,loopw-1))); + E = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*loopw)); + F = *(unsigned short*)(srcpix + (looph*srcpitch) + (2*MIN(width-1,loopw+1))); + H = *(unsigned short*)(srcpix + (MIN(height-1,looph+1)*srcpitch) + (2*loopw)); + + if (B != H && D != F) { + E0 = D == B ? D : E; + E1 = B == F ? F : E; + E2 = D == H ? D : E; + E3 = H == F ? F : E; + } else { + E0 = E; + E1 = E; + E2 = E; + E3 = E; + } + + + *(unsigned short*)(dstpix + looph*2*dstpitch + loopw*2*2) = E0; + *(unsigned short*)(dstpix + looph*2*dstpitch + (loopw*2+1)*2) = E1; + *(unsigned short*)(dstpix + (looph*2+1)*dstpitch + loopw*2*2) = E2; + *(unsigned short*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*2) = E3; + } + } +} + +//////////////////////////////////////////////////////////////////////// + + + + + +//////////////////////////////////////////////////////////////////////// + +/* +#define colorMask5 0x0000F7DE +#define lowPixelMask5 0x00000821 +#define qcolorMask5 0x0000E79c +#define qlowpixelMask5 0x00001863 +*/ + +#define colorMask5 0x00007BDE +#define lowPixelMask5 0x00000421 +#define qcolorMask5 0x0000739c +#define qlowpixelMask5 0x00000C63 + +#define INTERPOLATE5(A, B) ((((A & colorMask5) >> 1) + ((B & colorMask5) >> 1) + (A & B & lowPixelMask5))) +#define Q_INTERPOLATE5(A, B, C, D) (((((A & qcolorMask5) >> 2) + ((B & qcolorMask5) >> 2) + ((C & qcolorMask5) >> 2) + ((D & qcolorMask5) >> 2) \ + + ((((A & qlowpixelMask5) + (B & qlowpixelMask5) + (C & qlowpixelMask5) + (D & qlowpixelMask5)) >> 2) & qlowpixelMask5)))) + +void Super2xSaI_ex5(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA0, colorA1, colorA2, colorA3, + colorB0, colorB1, colorB2, colorB3, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- B1 B2 +// 4 5 6 S2 +// 1 2 3 S1 +// A1 A2 + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + + colorB0 = *(bP- iYA - iXA); + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + colorB3 = *(bP- iYA + iXC); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA0 = *(bP + iYC - iXA); + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + colorA3 = *(bP + iYC + iXC); + +//-------------------------------------- + if (color2 == color6 && color5 != color3) + { + product2b = product1b = color2; + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1b = color5; + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6), (color5), (color1), (colorA1)); + r += GET_RESULT ((color6), (color5), (color4), (colorB1)); + r += GET_RESULT ((color6), (color5), (colorA2), (colorS1)); + r += GET_RESULT ((color6), (color5), (colorB2), (colorS2)); + + if (r > 0) + product2b = product1b = color6; + else + if (r < 0) + product2b = product1b = color5; + else + { + product2b = product1b = INTERPOLATE5 (color5, color6); + } + } + else + { + if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) + product2b = Q_INTERPOLATE5 (color3, color3, color3, color2); + else + if (color5 == color2 && color2 == colorA2 && colorA1 != color3 && color2 != colorA3) + product2b = Q_INTERPOLATE5 (color2, color2, color2, color3); + else + product2b = INTERPOLATE5 (color2, color3); + + if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) + product1b = Q_INTERPOLATE5 (color6, color6, color6, color5); + else + if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) + product1b = Q_INTERPOLATE5 (color6, color5, color5, color5); + else + product1b = INTERPOLATE5 (color5, color6); + } + + if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) + product2a = INTERPOLATE5 (color2, color5); + else + if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) + product2a = INTERPOLATE5(color2, color5); + else + product2a = color2; + + if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) + product1a = INTERPOLATE5(color2, color5); + else + if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) + product1a = INTERPOLATE5(color2, color5); + else + product1a = color5; + + *dP=(unsigned short)product1a; + *(dP+1)=(unsigned short)product1b; + *(dP+(srcPitch))=(unsigned short)product2a; + *(dP+1+(srcPitch))=(unsigned short)product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +void Std2xSaI_ex5(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD colorA, colorB; + DWORD colorC, colorD, + colorE, colorF, colorG, colorH, + colorI, colorJ, colorK, colorL, + colorM, colorN, colorO, colorP; + DWORD product, product1, product2; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { +//--------------------------------------- +// Map of the pixels: I|E F|J +// G|A B|K +// H|C D|L +// M|N O|P + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorI = *(bP- iYA - iXA); + colorE = *(bP- iYA); + colorF = *(bP- iYA + iXB); + colorJ = *(bP- iYA + iXC); + + colorG = *(bP - iXA); + colorA = *(bP); + colorB = *(bP + iXB); + colorK = *(bP + iXC); + + colorH = *(bP + iYB - iXA); + colorC = *(bP + iYB); + colorD = *(bP + iYB + iXB); + colorL = *(bP + iYB + iXC); + + colorM = *(bP + iYC - iXA); + colorN = *(bP + iYC); + colorO = *(bP + iYC + iXB); + colorP = *(bP + iYC + iXC); + + if((colorA == colorD) && (colorB != colorC)) + { + if(((colorA == colorE) && (colorB == colorL)) || + ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ))) + { + product = colorA; + } + else + { + product = INTERPOLATE5(colorA, colorB); + } + + if(((colorA == colorG) && (colorC == colorO)) || + ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM))) + { + product1 = colorA; + } + else + { + product1 = INTERPOLATE5(colorA, colorC); + } + product2 = colorA; + } + else + if((colorB == colorC) && (colorA != colorD)) + { + if(((colorB == colorF) && (colorA == colorH)) || + ((colorB == colorE) && (colorB == colorD) && + (colorA != colorF) && (colorA == colorI))) + { + product = colorB; + } + else + { + product = INTERPOLATE5(colorA, colorB); + } + + if(((colorC == colorH) && (colorA == colorF)) || + ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI))) + { + product1 = colorC; + } + else + { + product1=INTERPOLATE5(colorA, colorC); + } + product2 = colorB; + } + else + if((colorA == colorD) && (colorB == colorC)) + { + if (colorA == colorB) + { + product = colorA; + product1 = colorA; + product2 = colorA; + } + else + { + register int r = 0; + product1 = INTERPOLATE5(colorA, colorC); + product = INTERPOLATE5(colorA, colorB); + + r += GetResult1 (colorA, colorB, colorG, colorE, colorI); + r += GetResult2 (colorB, colorA, colorK, colorF, colorJ); + r += GetResult2 (colorB, colorA, colorH, colorN, colorM); + r += GetResult1 (colorA, colorB, colorL, colorO, colorP); + + if (r > 0) + product2 = colorA; + else + if (r < 0) + product2 = colorB; + else + { + product2 = Q_INTERPOLATE5(colorA, colorB, colorC, colorD); + } + } + } + else + { + product2 = Q_INTERPOLATE5(colorA, colorB, colorC, colorD); + + if ((colorA == colorC) && (colorA == colorF) && + (colorB != colorE) && (colorB == colorJ)) + { + product = colorA; + } + else + if ((colorB == colorE) && (colorB == colorD) && (colorA != colorF) && (colorA == colorI)) + { + product = colorB; + } + else + { + product = INTERPOLATE5(colorA, colorB); + } + + if ((colorA == colorB) && (colorA == colorH) && + (colorG != colorC) && (colorC == colorM)) + { + product1 = colorA; + } + else + if ((colorC == colorG) && (colorC == colorD) && + (colorA != colorH) && (colorA == colorI)) + { + product1 = colorC; + } + else + { + product1 = INTERPOLATE5(colorA, colorC); + } + } + + *dP=(unsigned short)colorA; + *(dP+1)=(unsigned short)product; + *(dP+(srcPitch))=(unsigned short)product1; + *(dP+1+(srcPitch))=(unsigned short)product2; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// + +void SuperEagle_ex5(unsigned char *srcPtr, DWORD srcPitch, + unsigned char *dstBitmap, int width, int height) +{ + DWORD dstPitch = srcPitch<<1; + int finWidth = srcPitch>>1; + DWORD line; + unsigned short *dP; + unsigned short *bP; + int iXA,iXB,iXC,iYA,iYB,iYC,finish; + DWORD color4, color5, color6; + DWORD color1, color2, color3; + DWORD colorA1, colorA2, + colorB1, colorB2, + colorS1, colorS2; + DWORD product1a, product1b, + product2a, product2b; + + line = 0; + + { + for (; height; height-=1) + { + bP = (unsigned short *)srcPtr; + dP = (unsigned short *)(dstBitmap + line*dstPitch); + for (finish = width; finish; finish -= 1 ) + { + if(finish==finWidth) iXA=0; + else iXA=1; + if(finish>4) {iXB=1;iXC=2;} + else + if(finish>3) {iXB=1;iXC=1;} + else {iXB=0;iXC=0;} + if(line==0) iYA=0; + else iYA=finWidth; + if(height>4) {iYB=finWidth;iYC=srcPitch;} + else + if(height>3) {iYB=finWidth;iYC=finWidth;} + else {iYB=0;iYC=0;} + + colorB1 = *(bP- iYA); + colorB2 = *(bP- iYA + iXB); + + color4 = *(bP - iXA); + color5 = *(bP); + color6 = *(bP + iXB); + colorS2 = *(bP + iXC); + + color1 = *(bP + iYB - iXA); + color2 = *(bP + iYB); + color3 = *(bP + iYB + iXB); + colorS1= *(bP + iYB + iXC); + + colorA1 = *(bP + iYC); + colorA2 = *(bP + iYC + iXB); + + if(color2 == color6 && color5 != color3) + { + product1b = product2a = color2; + if((color1 == color2) || + (color6 == colorB2)) + { + product1a = INTERPOLATE5(color2, color5); + product1a = INTERPOLATE5(color2, product1a); + } + else + { + product1a = INTERPOLATE5(color5, color6); + } + + if((color6 == colorS2) || + (color2 == colorA1)) + { + product2b = INTERPOLATE5(color2, color3); + product2b = INTERPOLATE5(color2, product2b); + } + else + { + product2b = INTERPOLATE5(color2, color3); + } + } + else + if (color5 == color3 && color2 != color6) + { + product2b = product1a = color5; + + if ((colorB1 == color5) || + (color3 == colorS1)) + { + product1b = INTERPOLATE5(color5, color6); + product1b = INTERPOLATE5(color5, product1b); + } + else + { + product1b = INTERPOLATE5(color5, color6); + } + + if ((color3 == colorA2) || + (color4 == color5)) + { + product2a = INTERPOLATE5(color5, color2); + product2a = INTERPOLATE5(color5, product2a); + } + else + { + product2a = INTERPOLATE5(color2, color3); + } + } + else + if (color5 == color3 && color2 == color6) + { + register int r = 0; + + r += GET_RESULT ((color6), (color5), (color1), (colorA1)); + r += GET_RESULT ((color6), (color5), (color4), (colorB1)); + r += GET_RESULT ((color6), (color5), (colorA2), (colorS1)); + r += GET_RESULT ((color6), (color5), (colorB2), (colorS2)); + + if (r > 0) + { + product1b = product2a = color2; + product1a = product2b = INTERPOLATE5(color5, color6); + } + else + if (r < 0) + { + product2b = product1a = color5; + product1b = product2a = INTERPOLATE5(color5, color6); + } + else + { + product2b = product1a = color5; + product1b = product2a = color2; + } + } + else + { + product2b = product1a = INTERPOLATE5(color2, color6); + product2b = Q_INTERPOLATE5(color3, color3, color3, product2b); + product1a = Q_INTERPOLATE5(color5, color5, color5, product1a); + + product2a = product1b = INTERPOLATE5(color5, color3); + product2a = Q_INTERPOLATE5(color2, color2, color2, product2a); + product1b = Q_INTERPOLATE5(color6, color6, color6, product1b); + } + + *dP=(unsigned short)product1a; + *(dP+1)=(unsigned short)product1b; + *(dP+(srcPitch))=(unsigned short)product2a; + *(dP+1+(srcPitch))=(unsigned short)product2b; + + bP += 1; + dP += 2; + }//end of for ( finish= width etc..) + + line += 2; + srcPtr += srcPitch; + }; //endof: for (; height; height--) + } +} + +//////////////////////////////////////////////////////////////////////// +// Win code starts here +//////////////////////////////////////////////////////////////////////// + +#ifdef _WINDOWS + +//////////////////////////////////////////////////////////////////////// +// own swap buffer func (window/fullscreen) +//////////////////////////////////////////////////////////////////////// + +sDX DX; +static DDSURFACEDESC ddsd; +GUID guiDev; +BOOL bDeviceOK; +HWND hWGPU; +int iSysMemory=0; +int iFPSEInterface=0; +int iRefreshRate; +BOOL bVsync=FALSE; +BOOL bVsync_Key=FALSE; + +void (*BlitScreen) (unsigned char *,long,long); +void (*pExtraBltFunc) (void); +void (*p2XSaIFunc) (unsigned char *,DWORD,unsigned char *,int,int); + +//////////////////////////////////////////////////////////////////////// + +static __inline void WaitVBlank(void) +{ + if(bVsync_Key) + { + IDirectDraw2_WaitForVerticalBlank(DX.DD,DDWAITVB_BLOCKBEGIN,0); + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen32(unsigned char * surf,long x,long y) // BLIT IN 32bit COLOR MODE +{ + unsigned char * pD;unsigned long lu;unsigned short s; + unsigned int startxy; + short row,column; + short dx=(short)PreviousPSXDisplay.Range.x1; + short dy=(short)PreviousPSXDisplay.DisplayMode.y; + + if(iDebugMode && iFVDisplay) + { + dx=1024; + dy=iGPUHeight; + x=0;y=0; + + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + return; + } + + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*ddsd.lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + surf+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + if(iFPSEInterface) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen32_2xSaI(unsigned char * surf,long x,long y) // BLIT IN 32bit COLOR MODE +{ + unsigned char * pD;unsigned long lu;unsigned short s; + unsigned int startxy,off1,off2; + short row,column; + short dx=(short)PreviousPSXDisplay.Range.x1; + short dy=(short)PreviousPSXDisplay.DisplayMode.y; + unsigned char * pS=(unsigned char *)pSaISmallBuff; + unsigned long * pS1, * pS2; + + if(PreviousPSXDisplay.DisplayMode.x>512) + {BlitScreen32(surf,x,y);return;} + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*2048; + dy-=PreviousPSXDisplay.Range.y0; + } + + pS+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + if(iFPSEInterface) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } + + // ok, here we have filled pSaISmallBuff with PreviousPSXDisplay.DisplayMode.x * PreviousPSXDisplay.DisplayMode.y (*4) data + // now do a 2xSai blit to pSaIBigBuff + + + p2XSaIFunc((unsigned char *)pSaISmallBuff, 2048, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the 2xSai image... + // now transfer it to the surface + + dx=(short)PreviousPSXDisplay.DisplayMode.x<<1; + dy=(short)PreviousPSXDisplay.DisplayMode.y<<1; + off1=(ddsd.lPitch>>2)-dx; + off2=1024-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column512) + {BlitScreen32(surf,x,y);return;} + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*1024; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + pS+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)pS)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = 256 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } + // pSaISmallBuff holds 16 bit data + // 32 bit conversion done in asm function and written to pSaIBigBuff + + + + hq2x_32((unsigned char *)pSaISmallBuff, ddsd.lPitch, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the hq2x 32 bit image... + // now transfer it to the surface + + dx=(short)PreviousPSXDisplay.DisplayMode.x<<1; + dy=(short)PreviousPSXDisplay.DisplayMode.y<<1; + off1=(ddsd.lPitch>>2)-dx; + off2=1024-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column512) + {BlitScreen32(surf,x,y);return;} + + // This should keep games from crashing when 3x is too much + + + if(PreviousPSXDisplay.DisplayMode.x>341) + { + if(pExtraBltFunc==StretchedBlit3x) + pExtraBltFunc=StretchedBlit2x; + if(pExtraBltFunc==NoStretchedBlit3x) + pExtraBltFunc=NoStretchedBlit2x; + p2XSaIFunc=Scale2x_ex8; + BlitScreen32_2xSaI(surf,x,y); + return; + } + + if(pExtraBltFunc==StretchedBlit2x) + pExtraBltFunc=StretchedBlit3x; + if(pExtraBltFunc==NoStretchedBlit2x) + pExtraBltFunc=NoStretchedBlit3x; + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*2048; + dy-=PreviousPSXDisplay.Range.y0; + } + + pS+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + if(iFPSEInterface) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } + + // ok, here we have filled pSaISmallBuff with PreviousPSXDisplay.DisplayMode.x * PreviousPSXDisplay.DisplayMode.y (*4) data + // now do a 2xSai blit to pSaIBigBuff + + Scale3x_ex8((unsigned char *)pSaISmallBuff,2048, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the 2xSai image... + // now transfer it to the surface + //CHANGED << 1 to * 3 + + dx=(short)PreviousPSXDisplay.DisplayMode.x * 3; + dy=(short)PreviousPSXDisplay.DisplayMode.y * 3; + + off1=(ddsd.lPitch>>2)-dx; + off2=1024-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column512) + {BlitScreen32(surf,x,y);return;} + + // This should keep games from crashing when 3x is too much + if(PreviousPSXDisplay.DisplayMode.x>341) + { + if(pExtraBltFunc==StretchedBlit3x) + pExtraBltFunc=StretchedBlit2x; + if(pExtraBltFunc==NoStretchedBlit3x) + pExtraBltFunc=NoStretchedBlit2x; + BlitScreen32_hq2x(surf,x,y); + return; + } + + if(pExtraBltFunc==StretchedBlit2x) + pExtraBltFunc=StretchedBlit3x; + if(pExtraBltFunc==NoStretchedBlit2x) + pExtraBltFunc=NoStretchedBlit3x; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*1024; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + pS+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)pS)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = 256 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } + + // pSaISmallBuff holds 16 bit data + // 32 bit conversion done in asm function and written to pSaIBigBuff + + p2XSaIFunc((unsigned char *)pSaISmallBuff, ddsd.lPitch , + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the hq3x 32 bit image... + // now transfer it to the surface + + dx=(short)PreviousPSXDisplay.DisplayMode.x * 3; + dy=(short)PreviousPSXDisplay.DisplayMode.y * 3; + + off1=(ddsd.lPitch>>2)-dx; + off2=1024-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column>=1; + + LineOffset = 512 - dx; + SurfOffset = (ddsd.lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + return; + } + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*ddsd.lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (ddsd.lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen16_2xSaI(unsigned char * surf,long x,long y) // BLIT IN 16bit COLOR MODE +{ + unsigned long lu; + unsigned short row,column,off1,off2; + unsigned short dx=(unsigned short)PreviousPSXDisplay.Range.x1; + unsigned short dy=(unsigned short)PreviousPSXDisplay.DisplayMode.y; + unsigned char * pS=(unsigned char *)pSaISmallBuff; + unsigned long * pS1, * pS2; + + if(PreviousPSXDisplay.DisplayMode.x>512) + {BlitScreen16(surf,x,y);return;} + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*1024; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + pS+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)pS)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = 256 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } + + // ok, here we have filled pSaISmallBuff with PreviousPSXDisplay.DisplayMode.x * PreviousPSXDisplay.DisplayMode.y (*4) data + // now do a 2xSai blit to pSaIBigBuff +if(p2XSaIFunc == hq2x_16) + p2XSaIFunc((unsigned char *)pSaISmallBuff, ddsd.lPitch, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); +else + p2XSaIFunc((unsigned char *)pSaISmallBuff, 1024, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + // ok, here we have pSaIBigBuff filled with the 2xSai image... + // now transfer it to the surface + + + dx=(short)PreviousPSXDisplay.DisplayMode.x; + dy=(short)PreviousPSXDisplay.DisplayMode.y<<1; + off1=(ddsd.lPitch>>2)-dx; + off2=512-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column512) + {BlitScreen16(surf,x,y);return;} + + // This should keep games from crashing when 3x is too much + + if(PreviousPSXDisplay.DisplayMode.x>341) + { + if(pExtraBltFunc==StretchedBlit3x) + pExtraBltFunc=StretchedBlit2x; + if(pExtraBltFunc==NoStretchedBlit3x) + pExtraBltFunc=NoStretchedBlit2x; + if(p2XSaIFunc==hq3x_16) + p2XSaIFunc=hq2x_16; + else if(p2XSaIFunc==Scale3x_ex6_5) + p2XSaIFunc=Scale2x_ex6_5; + BlitScreen16_2xSaI(surf,x,y); + return; + } + + if(pExtraBltFunc==StretchedBlit2x) + pExtraBltFunc=StretchedBlit3x; + if(pExtraBltFunc==NoStretchedBlit2x) + pExtraBltFunc=NoStretchedBlit3x; + + if(p2XSaIFunc==hq2x_16) + p2XSaIFunc=hq3x_16; + else if(p2XSaIFunc==Scale2x_ex6_5) + p2XSaIFunc=Scale3x_ex6_5; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*1024; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + pS+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)pS)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = 256 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } + + // ok, here we have filled pSaISmallBuff with PreviousPSXDisplay.DisplayMode.x * PreviousPSXDisplay.DisplayMode.y (*4) data + // now do a 2xSai blit to pSaIBigBuff + if(p2XSaIFunc == hq3x_16) + p2XSaIFunc((unsigned char *)pSaISmallBuff, ddsd.lPitch, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + else + p2XSaIFunc((unsigned char *)pSaISmallBuff, 1024, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the 2xSai image... + // now transfer it to the surface + + dx=(short)(PreviousPSXDisplay.DisplayMode.x * 1.5); + dy=(short)PreviousPSXDisplay.DisplayMode.y*3; + + off1=(ddsd.lPitch>>2)-dx; + off2=512-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (ddsd.lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen15_2xSaI(unsigned char * surf,long x,long y) // BLIT IN 16bit COLOR MODE +{ + unsigned long lu; + unsigned short row,column,off1,off2; + unsigned short dx=(unsigned short)PreviousPSXDisplay.Range.x1; + unsigned short dy=(unsigned short)PreviousPSXDisplay.DisplayMode.y; + unsigned char * pS=(unsigned char *)pSaISmallBuff; + unsigned long * pS1, * pS2; + + if(PreviousPSXDisplay.DisplayMode.x>512) + {BlitScreen15(surf,x,y);return;} + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + pS+=PreviousPSXDisplay.Range.y0*1024; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + pS+=PreviousPSXDisplay.Range.x0<<1; + + if(iFPSEInterface) + { + for(column=0;column>3)); + pD+=3; + } + } + } + else + { + for(column=0;column>3)); + pD+=3; + } + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + unsigned long * DSTPtr = + ((unsigned long *)pS)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = 256 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } + + // ok, here we have filled pSaISmallBuff with PreviousPSXDisplay.DisplayMode.x * PreviousPSXDisplay.DisplayMode.y (*4) data + // now do a 2xSai blit to pSaIBigBuff + + p2XSaIFunc((unsigned char *)pSaISmallBuff, 1024, + (unsigned char *)pSaIBigBuff, + PreviousPSXDisplay.DisplayMode.x, + PreviousPSXDisplay.DisplayMode.y); + + // ok, here we have pSaIBigBuff filled with the 2xSai image... + // now transfer it to the surface + + dx=(short)PreviousPSXDisplay.DisplayMode.x; + dy=(short)PreviousPSXDisplay.DisplayMode.y<<1; + off1=(ddsd.lPitch>>2)-dx; + off2=512-dx; + + pS1=(unsigned long *)surf; + pS2=(unsigned long *)pSaIBigBuff; + + for(column=0;column=3) + { + if(pSaISmallBuff) memset(pSaISmallBuff,0,512*512*4); + } +} + +//////////////////////////////////////////////////////////////////////// + +void DoClearFrontBuffer(void) // CLEAR PRIMARY BUFFER +{ + DDBLTFX ddbltfx; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0x00000000; + + IDirectDrawSurface_Blt(DX.DDSPrimary,NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); +} + +//////////////////////////////////////////////////////////////////////// + +void NoStretchedBlit(void) +{ + static int iOldDX=0; + static int iOldDY=0; + + int iDX,iDY; + int iX=iResX-PreviousPSXDisplay.DisplayMode.x; + int iY=iResY-PreviousPSXDisplay.DisplayMode.y; + +/* +float fXS,fYS,fS; +fXS=(float)iResX/(float)PreviousPSXDisplay.DisplayMode.x; +fYS=(float)iResY/(float)PreviousPSXDisplay.DisplayMode.y; +if(fXS=3 &&iUseNoStretchBlt < 13) // 2xsai is twice as big, of course + {dx*=2;dy*=2;} + else if(iUseNoStretchBlt >= 13) + {dx*=3;dy*=3;} + + if(iDesktopCol==32) // 32 bit color depth + { + const unsigned long crCursorColor32[8]={0xffff0000,0xff00ff00,0xff0000ff,0xffff00ff,0xffffff00,0xff00ffff,0xffffffff,0xff7f7f7f}; + + surf+=PreviousPSXDisplay.Range.x0<<2; // -> add x left border + + for(iPlayer=0;iPlayer<8;iPlayer++) // -> loop all possible players + { + if(usCursorActive&(1< player active? + { + const int ty=(ptCursorPoint[iPlayer].y*dy)/256; // -> calculate the cursor pos in the current display + const int tx=(ptCursorPoint[iPlayer].x*dx)/512; + sx=tx-5;if(sx<0) {if(sx&1) sx=1; else sx=0;} + sy=ty-5;if(sy<0) {if(sy&1) sy=1; else sy=0;} + ex=tx+6;if(ex>dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y do dotted y line + *((unsigned long *)((surf)+(y*ddsd.lPitch)+x*4))=crCursorColor32[iPlayer]; + for(y=ty,x=sx;x do dotted x line + *((unsigned long *)((surf)+(y*ddsd.lPitch)+x*4))=crCursorColor32[iPlayer]; + } + } + } + else // 16 bit color depth + { + const unsigned short crCursorColor16[8]={0xf800,0x07c0,0x001f,0xf81f,0xffc0,0x07ff,0xffff,0x7bdf}; + + surf+=PreviousPSXDisplay.Range.x0<<1; // -> same stuff as above + + for(iPlayer=0;iPlayer<8;iPlayer++) + { + if(usCursorActive&(1<dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y512) g=((g-512)*2)+512; + g=0.5f+((g)/1024.0f); + +// some cards will cheat... so we don't trust the caps here +// if (DD_Caps.dwCaps2 & DDCAPS2_PRIMARYGAMMA) + { + float f;DDGAMMARAMP ramp;int i; + LPDIRECTDRAWGAMMACONTROL DD_Gamma = NULL; + + if FAILED(IDirectDrawSurface_QueryInterface(DX.DDSPrimary,&IID_IDirectDrawGammaControl,(void**)&DD_Gamma)) + return; + + for (i=0;i<256;i++) + { + f=(((float)(i*256))*g); + if(f>65535) f=65535; + ramp.red[i]=ramp.green[i]=ramp.blue[i]=(WORD)f; + } + + IDirectDrawGammaControl_SetGammaRamp(DD_Gamma,0,&ramp); + IDirectDrawGammaControl_Release(DD_Gamma); + } +} + +//////////////////////////////////////////////////////////////////////// +// SCAN LINE STUFF +//////////////////////////////////////////////////////////////////////// + +void SetScanLineList(LPDIRECTDRAWCLIPPER Clipper) +{ + LPRGNDATA lpCL;RECT * pr;int y;POINT Point={0,0}; + + IDirectDrawClipper_SetClipList(Clipper,NULL,0); + + lpCL=(LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+((iResY/2)+1)*sizeof(RECT)); + if(iWindowMode) ClientToScreen(DX.hWnd,&Point); + + lpCL->rdh.dwSize=sizeof(RGNDATAHEADER); + lpCL->rdh.iType=RDH_RECTANGLES; + lpCL->rdh.nCount=iResY/2; + lpCL->rdh.nRgnSize=0; + lpCL->rdh.rcBound.left=Point.x; + lpCL->rdh.rcBound.top=Point.y; + lpCL->rdh.rcBound.bottom=Point.y+iResY; + lpCL->rdh.rcBound.right=Point.x+iResX; + + pr=(RECT *)lpCL->Buffer; + for(y=0;yleft=Point.x; + pr->top=Point.y+y; + pr->right=Point.x+iResX; + pr->bottom=Point.y+y+1; + pr++; + } + + IDirectDrawClipper_SetClipList(Clipper,lpCL,0); + + free(lpCL); +} + +//////////////////////////////////////////////////////////////////////// + +void MoveScanLineArea(HWND hwnd) +{ + LPDIRECTDRAWCLIPPER Clipper;HRESULT h; + DDBLTFX ddbltfx;RECT r; + + if(FAILED(h=IDirectDraw_CreateClipper(DX.DD,0,&Clipper,NULL))) + return; + + IDirectDrawSurface_SetClipper(DX.DDSPrimary,NULL); + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0x00000000; + + // Fixed Scanline Mode for FullScreen where desktop was visible + // in background + + if(iWindowMode) + { + GetClientRect(hwnd,&r); + ClientToScreen(hwnd,(LPPOINT)&r.left); + r.right+=r.left; + r.bottom+=r.top; + } + else + { + r.left = 0; + r.top = 0; + r.right = iResX; + r.bottom = iResY; + } + + IDirectDrawSurface_Blt(DX.DDSPrimary,&r,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); + + SetScanLineList(Clipper); + + IDirectDrawSurface_SetClipper(DX.DDSPrimary,Clipper); + IDirectDrawClipper_Release(Clipper); +} + +//////////////////////////////////////////////////////////////////////// +// MAIN DIRECT DRAW INIT +//////////////////////////////////////////////////////////////////////// + +BOOL ReStart=FALSE; + +int DXinitialize() +{ + LPDIRECTDRAW DD;int i; + LPDIRECTDRAWCLIPPER Clipper;HRESULT h; + GUID FAR * guid=0; + unsigned char * c; + DDSCAPS ddscaps; + DDBLTFX ddbltfx; + DDPIXELFORMAT dd; + + // init some DX vars + DX.hWnd = (HWND)hWGPU; + DX.DDSHelper=0; + DX.DDSScreenPic=0; + + // make guid ! + c=(unsigned char *)&guiDev; + for(i=0;i=3) + ddsd.dwWidth = 1024; + else ddsd.dwWidth = 640; + + if(iUseNoStretchBlt>=3) + ddsd.dwHeight = 1024; + else + { + if(iDebugMode) ddsd.dwHeight = iGPUHeight; + else ddsd.dwHeight = 512; + } + + if(IDirectDraw_CreateSurface(DX.DD,&ddsd, &DX.DDSRender, NULL)) + return 0; + + // check for desktop color depth + dd.dwSize=sizeof(DDPIXELFORMAT); + IDirectDrawSurface_GetPixelFormat(DX.DDSRender,&dd); + + if(dd.dwRBitMask==0x00007c00 && + dd.dwGBitMask==0x000003e0 && + dd.dwBBitMask==0x0000001f) + { + if(iUseNoStretchBlt>=3) + BlitScreen=BlitScreen15_2xSaI; + else BlitScreen=BlitScreen15; + iDesktopCol=15; + } + else + if(dd.dwRBitMask==0x0000f800 && + dd.dwGBitMask==0x000007e0 && + dd.dwBBitMask==0x0000001f) + { + if(iUseNoStretchBlt < 3) + BlitScreen = BlitScreen16; + else if(iUseNoStretchBlt < 13) + BlitScreen = BlitScreen16_2xSaI; + else + BlitScreen = BlitScreen16_3x; + iDesktopCol=16; + } + else + { + if(iUseNoStretchBlt < 3) + BlitScreen = BlitScreen32; + else if(iUseNoStretchBlt < 11) + BlitScreen = BlitScreen32_2xSaI; + else if (iUseNoStretchBlt < 13) + BlitScreen = BlitScreen32_hq2x; + else if(iUseNoStretchBlt < 15) + BlitScreen = BlitScreen32_3x; + else + BlitScreen = BlitScreen32_hq3x; + iDesktopCol=32; + } + + //////////////////////////////////////////////////////// extra blts + + switch(iUseNoStretchBlt) + { + case 1: + pExtraBltFunc=NoStretchedBlit; + p2XSaIFunc=NULL; + break; + case 2: + pExtraBltFunc=NoStretchedBlitEx; + p2XSaIFunc=NULL; + break; + case 3: + pExtraBltFunc=StretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Std2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Std2xSaI_ex6; + else p2XSaIFunc=Std2xSaI_ex8; + break; + case 4: + pExtraBltFunc=NoStretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Std2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Std2xSaI_ex6; + else p2XSaIFunc=Std2xSaI_ex8; + break; + case 5: + pExtraBltFunc=StretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Super2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Super2xSaI_ex6; + else p2XSaIFunc=Super2xSaI_ex8; + break; + case 6: + pExtraBltFunc=NoStretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Super2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Super2xSaI_ex6; + else p2XSaIFunc=Super2xSaI_ex8; + break; + case 7: + pExtraBltFunc=StretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=SuperEagle_ex5; + else if(iDesktopCol==16) p2XSaIFunc=SuperEagle_ex6; + else p2XSaIFunc=SuperEagle_ex8; + break; + case 8: + pExtraBltFunc=NoStretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=SuperEagle_ex5; + else if(iDesktopCol==16) p2XSaIFunc=SuperEagle_ex6; + else p2XSaIFunc=SuperEagle_ex8; + break; + case 9: + pExtraBltFunc=StretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Scale2x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale2x_ex6_5; + else p2XSaIFunc=Scale2x_ex8; + break; + case 10: + pExtraBltFunc=NoStretchedBlit2x; + if (iDesktopCol==15) p2XSaIFunc=Scale2x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale2x_ex6_5; + else p2XSaIFunc=Scale2x_ex8; + break; + case 11: + pExtraBltFunc=NoStretchedBlit2x; + InitLUTs(); + if(iDesktopCol==15) p2XSaIFunc=hq2x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq2x_16; + else p2XSaIFunc=hq2x_32; + break; + case 12: + pExtraBltFunc=StretchedBlit2x; + InitLUTs(); + if(iDesktopCol==15) p2XSaIFunc=hq2x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq2x_16; + else p2XSaIFunc=hq2x_32; + break; + case 13: + pExtraBltFunc=StretchedBlit3x; + if(iDesktopCol==15) p2XSaIFunc=Scale3x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale3x_ex6_5; + else p2XSaIFunc=Scale3x_ex8; + break; + case 14: + pExtraBltFunc=NoStretchedBlit3x; + if(iDesktopCol==15) p2XSaIFunc=Scale3x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale3x_ex6_5; + else p2XSaIFunc=Scale3x_ex8; + break; + case 15: + pExtraBltFunc=NoStretchedBlit3x; + InitLUTs(); + if(iDesktopCol==15) p2XSaIFunc=hq3x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq3x_16; + else p2XSaIFunc=hq3x_32; + break; + case 16: + pExtraBltFunc=StretchedBlit3x; + InitLUTs(); + if(iDesktopCol==15) p2XSaIFunc=hq3x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq3x_16; + else p2XSaIFunc=hq3x_32; + break; + default: + pExtraBltFunc=NULL; + p2XSaIFunc=NULL; + break; + } + + //////////////////////////////////////////////////////// clipper init + + if(FAILED(h=IDirectDraw_CreateClipper(DX.DD,0,&Clipper,NULL))) + return 0; + + if(iUseScanLines) + SetScanLineList(Clipper); + else IDirectDrawClipper_SetHWnd(Clipper,0,DX.hWnd); + + IDirectDrawSurface_SetClipper(DX.DDSPrimary,Clipper); + IDirectDrawClipper_Release(Clipper); + + //////////////////////////////////////////////////////// small screen clean up + + DXSetGamma(); + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0x00000000; + + IDirectDrawSurface_Blt(DX.DDSPrimary,NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); + IDirectDrawSurface_Blt(DX.DDSRender,NULL,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); + + //////////////////////////////////////////////////////// finish init + + if(iUseNoStretchBlt>=3) + { + pSaISmallBuff=malloc(512*512*4); + memset(pSaISmallBuff,0,512*512*4); + pSaIBigBuff=malloc(1024*1024*4); + memset(pSaIBigBuff,0,1024*1024*4); + } + + bUsingTWin=FALSE; + + InitMenu(); // menu init + + if(iShowFPS) // fps on startup + { + ulKeybits|=KEY_SHOWFPS; + szDispBuf[0]=0; + BuildDispMenu(0); + } + + bIsFirstFrame = FALSE; // done + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// clean up DX stuff +//////////////////////////////////////////////////////////////////////// + +void DXcleanup() // DX CLEANUP +{ + CloseMenu(); // bye display lists + + if(iUseNoStretchBlt>=3) + { + if(pSaISmallBuff) free(pSaISmallBuff); + pSaISmallBuff=NULL; + if(pSaIBigBuff) free(pSaIBigBuff); + pSaIBigBuff=NULL; + } + + if(!bIsFirstFrame) + { + if(DX.DDSHelper) IDirectDrawSurface_Release(DX.DDSHelper); + DX.DDSHelper=0; + if(DX.DDSScreenPic) IDirectDrawSurface_Release(DX.DDSScreenPic); + DX.DDSScreenPic=0; + IDirectDrawSurface_Release(DX.DDSRender); + IDirectDrawSurface_Release(DX.DDSPrimary); + IDirectDraw_SetCooperativeLevel(DX.DD,DX.hWnd, DDSCL_NORMAL); + IDirectDraw_RestoreDisplayMode(DX.DD); + IDirectDraw_Release(DX.DD); + + ReStart=TRUE; + bIsFirstFrame = TRUE; + } +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +DWORD dwGPUStyle=0; // vars to store some wimdows stuff +HANDLE hGPUMenu=NULL; + +unsigned long ulInitDisplay(void) +{ + HDC hdc;RECT r; + + if(iWindowMode) // win mode? + { + DWORD dw=GetWindowLong(hWGPU, GWL_STYLE); // -> adjust wnd style + dwGPUStyle=dw; + dw&=~WS_THICKFRAME; + dw|=WS_BORDER|WS_CAPTION; + SetWindowLong(hWGPU, GWL_STYLE, dw); + + iResX=LOWORD(iWinSize);iResY=HIWORD(iWinSize); + ShowWindow(hWGPU,SW_SHOWNORMAL); + + if(iUseScanLines) + SetWindowPos(hWGPU,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); + + MoveWindow(hWGPU, // -> move wnd + GetSystemMetrics(SM_CXFULLSCREEN)/2-iResX/2, + GetSystemMetrics(SM_CYFULLSCREEN)/2-iResY/2, + iResX+GetSystemMetrics(SM_CXFIXEDFRAME)+3, + iResY+GetSystemMetrics(SM_CYFIXEDFRAME)+GetSystemMetrics(SM_CYCAPTION)+3, + TRUE); + UpdateWindow(hWGPU); // -> let windows do some update + } + else // no window mode: + { + DWORD dw=GetWindowLong(hWGPU, GWL_STYLE); // -> adjust wnd style + dwGPUStyle=dw; + hGPUMenu=GetMenu(hWGPU); + + dw&=~(WS_THICKFRAME|WS_BORDER|WS_CAPTION); + SetWindowLong(hWGPU, GWL_STYLE, dw); + SetMenu(hWGPU,NULL); + + ShowWindow(hWGPU,SW_SHOWMAXIMIZED); // -> max mode + } + + r.left=r.top=0;r.right=iResX;r.bottom=iResY; // init bkg with black + hdc = GetDC(hWGPU); + FillRect(hdc,&r,(HBRUSH)GetStockObject(BLACK_BRUSH)); + ReleaseDC(hWGPU, hdc); + + DXinitialize(); // init direct draw (not D3D... oh, well) + + if(!iWindowMode) // fullscreen mode? + ShowWindow(hWGPU,SW_SHOWMAXIMIZED); // -> maximize again (fixes strange DX behavior) + + return 1; +} + +//////////////////////////////////////////////////////////////////////// + +void CloseDisplay(void) +{ + DXcleanup(); // cleanup dx + + SetWindowLong(hWGPU, GWL_STYLE,dwGPUStyle); // repair window + if(hGPUMenu) SetMenu(hWGPU,(HMENU)hGPUMenu); +} + +//////////////////////////////////////////////////////////////////////// + +void CreatePic(unsigned char * pMem) +{ + DDSURFACEDESC xddsd;HRESULT ddrval; + unsigned char * ps;int x,y; + + memset(&xddsd, 0, sizeof(DDSURFACEDESC)); + xddsd.dwSize = sizeof(DDSURFACEDESC); + xddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; +// xddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + + if(iSysMemory) + xddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + else + xddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + + xddsd.dwWidth = 128; + xddsd.dwHeight = 96; + + if(IDirectDraw_CreateSurface(DX.DD,&xddsd, &DX.DDSScreenPic, NULL)) + {DX.DDSScreenPic=0;return;} + + ddrval=IDirectDrawSurface_Lock(DX.DDSScreenPic,NULL, &xddsd, DDLOCK_WAIT|DDLOCK_WRITEONLY, NULL); + + if(ddrval==DDERR_SURFACELOST) + { + IDirectDrawSurface_Restore(DX.DDSScreenPic); + } + + if(ddrval!=DD_OK) + { + IDirectDrawSurface_Unlock(DX.DDSScreenPic,&xddsd); + return; + } + + ps=(unsigned char *)xddsd.lpSurface; + + if(iDesktopCol==16) + { + unsigned short s; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + s=(*(pMem+0))>>3; + s|=((*(pMem+1))&0xfc)<<3; + s|=((*(pMem+2))&0xf8)<<8; + pMem+=3; + *((unsigned short *)(ps+y*xddsd.lPitch+x*2))=s; + } + } + } + else + if(iDesktopCol==15) + { + unsigned short s; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + s=(*(pMem+0))>>3; + s|=((*(pMem+1))&0xfc)<<2; + s|=((*(pMem+2))&0xf8)<<7; + pMem+=3; + *((unsigned short *)(ps+y*xddsd.lPitch+x*2))=s; + } + } + } + else + if(iDesktopCol==32) + { + unsigned long l; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + l= *(pMem+0); + l|=(*(pMem+1))<<8; + l|=(*(pMem+2))<<16; + pMem+=3; + *((unsigned long *)(ps+y*xddsd.lPitch+x*4))=l; + } + } + } + + IDirectDrawSurface_Unlock(DX.DDSScreenPic,&xddsd); +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void DestroyPic(void) +{ + if(DX.DDSScreenPic) + { + RECT ScreenRect={iResX-128,0,iResX,96}; + DDBLTFX ddbltfx; + + if(iWindowMode) + { + POINT Point={0,0}; + ClientToScreen(DX.hWnd,&Point); + ScreenRect.left+=Point.x; + ScreenRect.right+=Point.x; + ScreenRect.top+=Point.y; + ScreenRect.bottom+=Point.y; + } + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0x00000000; + IDirectDrawSurface_Blt(DX.DDSPrimary,&ScreenRect,NULL,NULL,DDBLT_COLORFILL,&ddbltfx); + + IDirectDrawSurface_Release(DX.DDSScreenPic); + DX.DDSScreenPic=0; + } +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void DisplayPic(void) +{ + RECT ScreenRect={iResX-128,0,iResX,96}, + HelperRect={0,0,128,96}; + if(iWindowMode) + { + POINT Point={0,0}; + ClientToScreen(DX.hWnd,&Point); + ScreenRect.left+=Point.x; + ScreenRect.right+=Point.x; + ScreenRect.top+=Point.y; + ScreenRect.bottom+=Point.y; + } + +// ??? eh... no need to wait here! +// WaitVBlank(); + + IDirectDrawSurface_Blt(DX.DDSPrimary,&ScreenRect,DX.DDSScreenPic,&HelperRect, + DDBLT_WAIT,NULL); +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void ShowGpuPic(void) +{ + HRSRC hR;HGLOBAL hG;unsigned long * pRMem; + unsigned char * pMem;int x,y;unsigned long * pDMem; + + // turn off any screen pic, if it does already exist + if(DX.DDSScreenPic) {DestroyPic();return;} + + if(ulKeybits&KEY_SHOWFPS) {ShowTextGpuPic();return;} + + // load and lock the bitmap (lock is kinda obsolete in win32) + hR=FindResource(hInst,MAKEINTRESOURCE(IDB_GPU),RT_BITMAP); + hG=LoadResource(hInst,hR); + + // get long ptr to bmp data + pRMem=((unsigned long *)LockResource(hG))+10; + + // change the data upside-down + pMem=(unsigned char *)malloc(128*96*3); + + for(y=0;y<96;y++) + { + pDMem=(unsigned long *)(pMem+(95-y)*128*3); + for(x=0;x<96;x++) *pDMem++=*pRMem++; + } + + // show the pic + CreatePic(pMem); + + // clean up + free(pMem); + DeleteObject(hG); +} + +//////////////////////////////////////////////////////////////////////// + +void ShowTextGpuPic(void) // CREATE TEXT SCREEN PIC +{ // gets an Text and paints + unsigned char * pMem;BITMAPINFO bmi; // it into a rgb24 bitmap + HDC hdc,hdcMem;HBITMAP hBmp,hBmpMem;HFONT hFontMem; // to display it in the gpu + HBRUSH hBrush,hBrushMem;HPEN hPen,hPenMem; + char szB[256]; + RECT r={0,0,128,96}; // size of bmp... don't change that + COLORREF crFrame = RGB(128,255,128); // some example color inits + COLORREF crBkg = RGB(0,0,0); + COLORREF crText = RGB(0,255,0); + + if(DX.DDSScreenPic) DestroyPic(); + + //----------------------------------------------------// creation of the dc & bitmap + + hdc =GetDC(NULL); // create a dc + hdcMem=CreateCompatibleDC(hdc); + ReleaseDC(NULL,hdc); + + memset(&bmi,0,sizeof(BITMAPINFO)); // create a 24bit dib + bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth=128; + bmi.bmiHeader.biHeight=-96; + bmi.bmiHeader.biPlanes=1; + bmi.bmiHeader.biBitCount=24; + bmi.bmiHeader.biCompression=BI_RGB; + hBmp=CreateDIBSection(hdcMem,&bmi,DIB_RGB_COLORS, + (void **)&pMem,NULL,0); // pMem will point to 128x96x3 bitmap data + + hBmpMem = (HBITMAP)SelectObject(hdcMem,hBmp); // sel the bmp into the dc + + //----------------------------------------------------// ok, the following is just a drawing example... change it... + // create & select an additional font... whatever you want to paint, paint it in the dc :) + hBrush=CreateSolidBrush(crBkg); + hPen=CreatePen(PS_SOLID,0,crFrame); + + hBrushMem = (HBRUSH)SelectObject(hdcMem,hBrush); + hPenMem = (HPEN)SelectObject(hdcMem,hPen); + hFontMem = (HFONT)SelectObject(hdcMem,hGFont); + + SetTextColor(hdcMem,crText); + SetBkColor(hdcMem,crBkg); + + Rectangle(hdcMem,r.left,r.top,r.right,r.bottom); // our example: fill rect and paint border + InflateRect(&r,-3,-2); // reduce the text area + + LoadString(hInst,IDS_INFO0+iMPos,szB,255); + DrawText(hdcMem,szB,strlen(szB),&r, // paint the text (including clipping and word break) + DT_LEFT|DT_WORDBREAK); + + //----------------------------------------------------// ok, now store the pMem data, or just call the gpu func + + CreatePic(pMem); + + //----------------------------------------------------// finished, now we clean up... needed, or you will get resource leaks :) + + SelectObject(hdcMem,hBmpMem); // sel old mem dc objects + SelectObject(hdcMem,hBrushMem); + SelectObject(hdcMem,hPenMem); + SelectObject(hdcMem,hFontMem); + DeleteDC(hdcMem); // delete mem dcs + DeleteObject(hBmp); + DeleteObject(hBrush); // delete created objects + DeleteObject(hPen); +} + +//////////////////////////////////////////////////////////////////////// + +#else + +#ifndef _SDL +//////////////////////////////////////////////////////////////////////// +// X STUFF :) +//////////////////////////////////////////////////////////////////////// + +#ifdef USE_XF86VM + +#include +static XF86VidModeModeInfo **modes=0; +static int iOldMode=0; +static int bModeChanged=0; + +#endif + +#ifdef USE_DGA2 + +#include "DrawString.h" +#include +XDGADevice *dgaDev; +static XDGAMode *dgaModes; +static int dgaNModes=0; +static char *Xpic; +#endif + +static Cursor cursor; +XVisualInfo vi; +static XVisualInfo *myvisual; +Display *display; +static Colormap colormap; +static Window window; +static GC hGC; +static XImage * Ximage; +static XImage * XCimage; +static XImage * XFimage; +static XImage * XPimage=0 ; +static int Xpitch; +char * Xpixels; +char * pCaptionText; + +#ifdef __GX__ +// variables needed by GX functions +char * GXtexture; +#endif // __GX__ + +typedef struct { +#define MWM_HINTS_DECORATIONS 2 + long flags; + long functions; + long decorations; + long input_mode; +} MotifWmHints; + +static int fx=0; + +// close display + +void DestroyDisplay(void) +{ + if(display) + { +#ifdef USE_DGA2 + if(iWindowMode) + { +#endif + XFreeColormap(display, colormap); + if(hGC) + { + XFreeGC(display,hGC); + hGC = 0; + } + if(Ximage) + { + XDestroyImage(Ximage); + Ximage=0; + } + if(XCimage) + { + XDestroyImage(XCimage); + XCimage=0; + } + if(XFimage) + { + XDestroyImage(XFimage); + XFimage=0; + } + + XSync(display,False); + +#ifdef USE_DGA2 + } +#endif + +#ifdef USE_XF86VM + +#ifdef USE_DGA2 + if (!iWindowMode) + { + XFree(dgaModes); + XDGACloseFramebuffer(display, DefaultScreen(display)); + + XUngrabKeyboard(display, CurrentTime); + } +#endif + if(bModeChanged) // -> repair screen mode + { + int myscreen=DefaultScreen(display); + XF86VidModeSwitchToMode(display,myscreen, // --> switch mode back + modes[iOldMode]); + XF86VidModeSetViewPort(display,myscreen,0,0); // --> set viewport upperleft + free(modes); // --> finally kill mode infos + bModeChanged=0; // --> done + } + +#endif + + XCloseDisplay(display); + } +} + +int depth=0; + +#ifdef USE_DGA2 +void XClearScreen() +{ + int y; + char *ptr = dgaDev->data; + + for (y=0; ymode.bitsPerPixel / 8)); + ptr+= dgaDev->mode.imageWidth * (dgaDev->mode.bitsPerPixel / 8); + } +} +#endif + +// Selects the mode with the highest vertical refresh frequency +// from all modes with resolution iResX and iResY. +// Returns -1 if no mode is found. +// You can calculate the vertical refresh frequency in Hz with the formula: +// (pixel_clock * 1000 * 1000 / htotal) / vtotal +static int SelectBestMode(XF86VidModeModeInfo* modes[], int nmodes, int iResX, int iResY) +{ + int bestmode = -1; + int vfreq = 0; + int max_vfreq = 0; + int i; + + for (i = 0; i < nmodes; i++) { + if (iResX == modes[i]->hdisplay && + iResY == modes[i]->vdisplay) { + vfreq = (modes[i]->dotclock * 1000 * 1000 / modes[i]->htotal) / modes[i]->vtotal; + if (vfreq > max_vfreq) { + max_vfreq = vfreq; + bestmode = i; + } + } + } + return bestmode; +} + +// Create display + +void CreateDisplay(void) +{ + XSetWindowAttributes winattr; + int myscreen; + Screen * screen; + XEvent event; + XSizeHints hints; + XWMHints wm_hints; + MotifWmHints mwmhints; + Atom mwmatom; + int root_window_id=0; + XGCValues gcv; + static int depth_list[] = { 16, 15, 32, 24 }; + int i; + + // Open display + display=XOpenDisplay(NULL); + + if(!display) + { + fprintf (stderr,"Failed to open display!!!\n"); + DestroyDisplay(); + return; + } + + myscreen=DefaultScreen(display); + + // desktop fullscreen switch +#ifndef USE_XF86VM + if(!iWindowMode) fx=1; +#else + if(!iWindowMode) + { + XF86VidModeModeLine mode; + int nmodes,iC; + + fx=1; // raise flag + XF86VidModeGetModeLine(display,myscreen,&iC,&mode); // get actual mode info + if(mode.privsize) XFree(mode.private); // no need for private stuff + bModeChanged=0; // init mode change flag +#ifndef USE_DGA2 + if(iResX!=mode.hdisplay || iResY!=mode.vdisplay) // wanted mode is different? + { +#endif + XF86VidModeGetAllModeLines(display,myscreen, // -> enum all mode infos + &nmodes,&modes); + if(modes) // -> infos got? + { + int bestmode; + for(iC=0;iC loop modes + { + if(mode.hdisplay==modes[iC]->hdisplay && // -> act mode found? + mode.vdisplay==modes[iC]->vdisplay && // this used to only check for resolution + mode.hsyncstart==modes[iC]->hsyncstart && // but that is not sufficient because + mode.hsyncend==modes[iC]->hsyncend && // there might be several modes with the same + mode.vsyncstart==modes[iC]->vsyncstart && // resolution but different h/v frequency. + mode.htotal==modes[iC]->htotal && + mode.vtotal==modes[iC]->vtotal) + { // if yes: store mode id + iOldMode=iC; + break; + } + } + + if ((bestmode = SelectBestMode(modes, nmodes, iResX, iResY)) > -1) + { + { +#ifndef USE_DGA2 + XF86VidModeSwitchToMode(display,myscreen, // --> switch to mode + modes[bestmode]); + XF86VidModeSetViewPort(display,myscreen,0,0); + + bModeChanged=1; // --> raise flag for repairing mode on close +#else + int Evb, Errb; + int Major, Minor; + + if (!XDGAQueryExtension(display, &Evb, &Errb)) + { + printf("DGA Extension not Available\n"); + return; + } + + if (!XDGAQueryVersion(display, &Major, &Minor) || Major < 2) + { + printf("DGA Version 2 not Available\n"); + return; + } + + dgaModes = XDGAQueryModes(display, myscreen, &dgaNModes); + + for (i=0; imode.flags & XDGAConcurrentAccess)) + { + printf("error DGA2 mode has no ConcurrenAccess\n"); + break; + } + + XDGASetViewport(display, myscreen, 0, 0, XDGAFlipImmediate); + XDGASync(display, myscreen); + + XClearScreen(); + + XGrabKeyboard(display, DefaultRootWindow(display), True, GrabModeAsync, GrabModeAsync, CurrentTime); + XSelectInput(display, DefaultRootWindow(display), KeyPressMask | KeyReleaseMask); + + bModeChanged=1; // --> raise flag for repairing mode on close +#endif + } + } + + if(bModeChanged==0) // -> no mode found? + { + free(modes); // --> free infos + printf("No proper fullscreen mode found!\n"); // --> some info output + } + } +#ifndef USE_DGA2 + } +#endif + } +#endif + + screen=DefaultScreenOfDisplay(display); + + myvisual = 0; + + for(i=0;i<4;i++) + if(XMatchVisualInfo(display,myscreen, depth_list[i], TrueColor, &vi)) + {myvisual = &vi;depth=depth_list[i];break;} + + if(!myvisual) + { + fprintf(stderr,"Failed to obtain visual!!!\n"); + DestroyDisplay(); + return; + } + + if(myvisual->red_mask==0x00007c00 && + myvisual->green_mask==0x000003e0 && + myvisual->blue_mask==0x0000001f) + {iColDepth=15;} + else + if(myvisual->red_mask==0x0000f800 && + myvisual->green_mask==0x000007e0 && + myvisual->blue_mask==0x0000001f) + {iColDepth=16;} + else + if(myvisual->red_mask==0x00ff0000 && + myvisual->green_mask==0x0000ff00 && + myvisual->blue_mask==0x000000ff) + {iColDepth=32;} + else + { + fprintf(stderr,"COLOR DEPTH NOT SUPPORTED!\n"); + fprintf(stderr,"r: %08lx\n",myvisual->red_mask); + fprintf(stderr,"g: %08lx\n",myvisual->green_mask); + fprintf(stderr,"b: %08lx\n",myvisual->blue_mask); + DestroyDisplay(); + return; + } + + root_window_id=RootWindow(display,DefaultScreen(display)); + +#ifdef USE_DGA2 + if(!iWindowMode) + { + Xpixels = dgaDev->data; return; + } +#endif + + // pffff... much work for a simple blank cursor... oh, well... + if(iWindowMode) cursor=XCreateFontCursor(display,XC_trek); + else + { + Pixmap p1,p2;XImage * img; + XColor b,w;unsigned char * idata; + XGCValues GCv; + GC GCc; + + memset(&b,0,sizeof(XColor)); + memset(&w,0,sizeof(XColor)); + idata=(unsigned char *)malloc(8); + memset(idata,0,8); + + p1=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1); + p2=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1); + + img = XCreateImage(display,myvisual->visual, + 1,XYBitmap,0,idata,8,8,8,1); + + GCv.function = GXcopy; + GCv.foreground = ~0; + GCv.background = 0; + GCv.plane_mask = AllPlanes; + GCc = XCreateGC(display,p1, + (GCFunction|GCForeground|GCBackground|GCPlaneMask),&GCv); + + XPutImage(display, p1,GCc,img,0,0,0,0,8,8); + XPutImage(display, p2,GCc,img,0,0,0,0,8,8); + XFreeGC(display, GCc); + + cursor = XCreatePixmapCursor(display,p1,p2,&b,&w,0,0); + + XFreePixmap(display,p1); + XFreePixmap(display,p2); + XDestroyImage(img); // will free idata as well + } + + colormap=XCreateColormap(display,root_window_id, + myvisual->visual,AllocNone); + + winattr.background_pixel=0; + winattr.border_pixel=WhitePixelOfScreen(screen); + winattr.bit_gravity=ForgetGravity; + winattr.win_gravity=NorthWestGravity; + winattr.backing_store=NotUseful; + + winattr.override_redirect=False; + winattr.save_under=False; + winattr.event_mask=0; + winattr.do_not_propagate_mask=0; + winattr.colormap=colormap; + winattr.cursor=None; + + window=XCreateWindow(display,root_window_id, + 0,0,iResX,iResY, + 0,myvisual->depth, + InputOutput,myvisual->visual, + CWBorderPixel | CWBackPixel | + CWEventMask | CWDontPropagate | + CWColormap | CWCursor, + &winattr); + + if(!window) + { + fprintf(stderr,"Failed in XCreateWindow()!!!\n"); + DestroyDisplay(); + return; + } + + hints.flags=PMinSize|PMaxSize; + + if(fx) hints.flags|=USPosition|USSize; + else hints.flags|=PSize; + + hints.min_width = hints.max_width = hints.base_width = iResX; + hints.min_height= hints.max_height = hints.base_height = iResY; + + wm_hints.input=1; + wm_hints.flags=InputHint; + + XSetWMHints(display,window,&wm_hints); + XSetWMNormalHints(display,window,&hints); + if(pCaptionText) + XStoreName(display,window,pCaptionText); + else XStoreName(display,window,"P.E.Op.S SoftX PSX Gpu"); + + XDefineCursor(display,window,cursor); + + // hack to get rid of window title bar + + if(fx) + { + mwmhints.flags=MWM_HINTS_DECORATIONS; + mwmhints.decorations=0; + mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0); + XChangeProperty(display,window,mwmatom,mwmatom,32, + PropModeReplace,(unsigned char *)&mwmhints,4); + } + + // key stuff + + XSelectInput(display, + window, + FocusChangeMask | ExposureMask | + KeyPressMask | KeyReleaseMask + ); + + XMapRaised(display,window); + XClearWindow(display,window); + XWindowEvent(display,window,ExposureMask,&event); + + if(fx) // fullscreen + { + XResizeWindow(display,window,screen->width,screen->height); + + hints.min_width = hints.max_width = hints.base_width = screen->width; + hints.min_height= hints.max_height = hints.base_height = screen->height; + + XSetWMNormalHints(display,window,&hints); + } + + gcv.graphics_exposures = False; + hGC = XCreateGC(display,window, + GCGraphicsExposures, &gcv); + if(!hGC) + { + fprintf(stderr,"No gfx context!!!\n"); + DestroyDisplay(); + } + + Xpixels = (char *)malloc(230*15*4); + memset(Xpixels,255,230*15*4); + XFimage = XCreateImage(display,myvisual->visual, + depth, ZPixmap, 0, + (char *)Xpixels, + 230, 15, + depth>16 ? 32 : 16, + 0); + + Xpixels = (char *)malloc(iResY*iResX*4); + memset(Xpixels,0,iResY*iResX*4); + XCimage = XCreateImage(display,myvisual->visual, + depth, ZPixmap, 0, + (char *)Xpixels, + iResX, iResY, + depth>16 ? 32 : 16, + 0); + + Xpixels = (char *)malloc(iResY*iResX*4); + + Ximage = XCreateImage(display,myvisual->visual, + depth, ZPixmap, 0, + (char *)Xpixels, + iResX, iResY, + depth>16 ? 32 : 16, + 0); + Xpitch = Ximage->bytes_per_line; +} +#else //SDL +//////////////////////////////////////////////////////////////////////// +// SDL Stuff ^^ +//////////////////////////////////////////////////////////////////////// + +int Xpitch,depth=16; +char * Xpixels; +char * pCaptionText; + +#ifndef __GX__ +SDL_Surface *display,*XFimage,*XPimage=NULL; +#ifndef _SDL2 +SDL_Surface *Ximage=NULL,*XCimage=NULL; +#else +SDL_Surface *Ximage16,*Ximage24; +#endif +//static Uint32 sdl_mask=SDL_HWSURFACE|SDL_HWACCEL;/*place or remove some flags*/ +Uint32 sdl_mask=SDL_HWSURFACE; +SDL_Rect rectdst,rectsrc; +#else //!__GX__ +//Some GX specific variables +int iResX_Max=640; +int iResY_Max=512; +char * GXtexture; +#endif //__GX__ + + + +void DestroyDisplay(void) +{ +#ifndef __GX__ +if(display){ +#ifdef _SDL2 +if(Ximage16) SDL_FreeSurface(Ximage16); +if(Ximage24) SDL_FreeSurface(Ximage24); +#else +if(XCimage) SDL_FreeSurface(XCimage); +if(Ximage) SDL_FreeSurface(Ximage); +#endif +if(XFimage) SDL_FreeSurface(XFimage); + +SDL_FreeSurface(display);//the display is also a surface in SDL +} +SDL_QuitSubSystem(SDL_INIT_VIDEO); +#else //!__GX__ +//TODO: Free other surfaces. +free(Xpixels); +free(GXtexture); +#endif //__GX__ +} + +void SetDisplay(void){ +#ifndef __GX__//This function doesn't seem to be used anywhere. +if(iWindowMode) +display = SDL_SetVideoMode(iResX,iResY,depth,sdl_mask); +else display = SDL_SetVideoMode(iResX,iResY,depth,SDL_FULLSCREEN|sdl_mask); +#endif //!__GX__ +} + +void CreateDisplay(void) +{ +#ifndef __GX__ +if(SDL_InitSubSystem(SDL_INIT_VIDEO)<0) + { + fprintf (stderr,"(x) Failed to Init SDL!!!\n"); + return; + } + +//display = SDL_SetVideoMode(iResX,iResY,depth,sdl_mask); +display = SDL_SetVideoMode(iResX,iResY,depth,!iWindowMode*SDL_FULLSCREEN|sdl_mask); +#ifndef _SDL2 +Ximage = SDL_CreateRGBSurface(sdl_mask,iResX,iResY,depth,0x00ff0000,0x0000ff00,0x000000ff,0); +XCimage= SDL_CreateRGBSurface(sdl_mask,iResX,iResY,depth,0x00ff0000,0x0000ff00,0x000000ff,0); +#else +//Ximage16= SDL_CreateRGBSurface(sdl_mask,iResX,iResY,16,0x1f,0x1f<<5,0x1f<<10,0); + +Ximage16= SDL_CreateRGBSurfaceFrom((void*)psxVub, 1024,512,16,2048 ,0x1f,0x1f<<5,0x1f<<10,0); +Ximage24= SDL_CreateRGBSurfaceFrom((void*)psxVub, 1024*2/3,512 ,24,2048 ,0xFF0000,0xFF00,0xFF,0); +#endif + + +XFimage= SDL_CreateRGBSurface(sdl_mask,170,15,depth,0x00ff0000,0x0000ff00,0x000000ff,0); + +iColDepth=depth; +//memset(XFimage->pixels,255,170*15*4);//really needed??? +//memset(Ximage->pixels,0,ResX*ResY*4); +#ifndef _SDL2 +memset(XCimage->pixels,0,iResX*iResY*4); +#endif + +//Xpitch=iResX*32; no more use +#ifndef _SDL2 +Xpixels=(char *)Ximage->pixels; +#endif +if(pCaptionText) + SDL_WM_SetCaption(pCaptionText,NULL); + else SDL_WM_SetCaption("FPSE Display - P.E.Op.S SoftSDL PSX Gpu",NULL); +#else //!__GX__ +//TODO: Initialize more surfaces as needed. + iColDepth=depth; + printf("iColDepth = %d\n",iColDepth); + Xpixels = memalign(32,iResX_Max*iResY_Max*4); + memset(Xpixels,0,iResX_Max*iResY_Max*4); +// GXtexture = memalign(32,iResX_Max*iResY_Max*4); + GXtexture = memalign(32,1024*1024*2); + memset(GXtexture,0,iResX_Max*iResY_Max*4); +// printf("GPU_open - whichfb = %d; xfb = %x, %x\n",whichfb,xfb[0],xfb[1]); +#endif //__GX__ +} +#endif + + +//////////////////////////////////////////////////////////////////////// +#ifndef _SDL2 +void (*BlitScreen) (unsigned char *,long,long); +void (*BlitScreenNS) (unsigned char *,long,long); +void (*XStretchBlt)(unsigned char * pBB,int sdx,int sdy,int ddx,int ddy); +void (*p2XSaIFunc) (unsigned char *,DWORD,unsigned char *,int,int); +unsigned char * pBackBuffer=0; +#endif +//////////////////////////////////////////////////////////////////////// + +#ifndef _SDL2 + +void BlitScreen32(unsigned char * surf,long x,long y) +{ + unsigned char * pD; + unsigned int startxy; + unsigned long lu;unsigned short s; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + long lPitch=(dx+PreviousPSXDisplay.Range.x0)<<2; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + surf+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen32NS(unsigned char * surf,long x,long y) +{ + unsigned char * pD; + unsigned int startxy; + unsigned long lu;unsigned short s; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + long lPitch=iResX<<2; +#ifdef USE_DGA2 + if (!iWindowMode && (char*)surf == Xpixels) + lPitch = (dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth) * 4; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + surf+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen32NSSL(unsigned char * surf,long x,long y) +{ + unsigned char * pD; + unsigned int startxy; + unsigned long lu;unsigned short s; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + long lPitch=iResX<<2; +#ifdef USE_DGA2 + if (!iWindowMode && (char*)surf == Xpixels) + lPitch = (dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth) * 4; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + surf+=PreviousPSXDisplay.Range.x0<<2; + + if(PSXDisplay.RGB24) + { + for(column=0;column>7)&0xf8))&0xffffff)|0xff000000; + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen15(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*((dx+PreviousPSXDisplay.Range.x0)<<1); + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + unsigned short * DSTPtr =(unsigned short *)surf; + DSTPtr+=PreviousPSXDisplay.Range.x0; + + for(column=0;column>3); + pD+=3; + } + DSTPtr+=PreviousPSXDisplay.Range.x0; + } + } + else + { + unsigned long * SRCPtr,* DSTPtr; + + SurfOffset=PreviousPSXDisplay.Range.x0>>1; + + SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + DSTPtr = ((unsigned long *)surf) + SurfOffset; + + dx>>=1; + LineOffset = 512 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen15NS(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + long lPitch=iResX<<1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)surf == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; +#ifdef USE_DGA2 + if (DGA2fix) lPitch+= dga2Fix*2; +#endif + + for(column=0;column>3); + pD+=3; + } + } + } + else + { + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix/2; +#endif + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen15NSSL(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + long lPitch=iResX<<1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)surf == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; +#ifdef USE_DGA2 + if (DGA2fix) lPitch+= dga2Fix*2; +#endif + + for(column=0;column>3); + pD+=3; + } + } + } + else + { + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix/2; +#endif + } + else + { +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix/2; +#endif + DSTPtr+=iResX>>1; + SRCPtr+=512; + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen16(unsigned char * surf,long x,long y) // BLIT IN 16bit COLOR MODE +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*((dx+PreviousPSXDisplay.Range.x0)<<1); + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + unsigned short * DSTPtr =(unsigned short *)surf; + DSTPtr+=PreviousPSXDisplay.Range.x0; + + for(column=0;column>3); + pD+=3; + } + DSTPtr+=PreviousPSXDisplay.Range.x0; + } + } + else + { + unsigned long * SRCPtr,* DSTPtr; + + SurfOffset=PreviousPSXDisplay.Range.x0>>1; + + SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + DSTPtr = ((unsigned long *)surf) + SurfOffset; + + dx>>=1; + LineOffset = 512 - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen16NS(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + long lPitch=iResX<<1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)surf == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; +#ifdef USE_DGA2 + if (DGA2fix) lPitch+= dga2Fix*2; +#endif + + for(column=0;column>3); + pD+=3; + } + } + } + else + { + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + +#ifdef USE_DGA2 + dga2Fix/=2; +#endif + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix; +#endif + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void BlitScreen16NSSL(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + long lPitch=iResX<<1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)surf == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; +#ifdef USE_DGA2 + if (DGA2fix) lPitch+= dga2Fix*2; +#endif + + for(column=0;column>3); + pD+=3; + } + } + } + else + { + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + +#ifdef USE_DGA2 + dga2Fix/=2; +#endif + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + DSTPtr += SurfOffset; + SRCPtr += LineOffset; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix; +#endif + } + else + { + DSTPtr+=iResX>>1; + SRCPtr+=512; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix; +#endif + } + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void XStretchBlt16(unsigned char * pBB,int sdx,int sdy,int ddx,int ddy) +{ + unsigned short * pSrc=(unsigned short *)pBackBuffer; + unsigned short * pSrcR=NULL; + unsigned short * pDst=(unsigned short *)pBB; + unsigned long * pDstR=NULL; + int x,y,cyo=-1,cy; + int xpos, xinc; + int ypos, yinc,ddx2=ddx>>1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)pBB == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + // 2xsai stretching +if(iUseNoStretchBlt>=2) +{ + //p2XSaIFunc(pBackBuffer,sdx<<1,(unsigned char *)pSaIBigBuff,sdx,sdy); +#ifndef __GX__ + if(p2XSaIFunc==hq2x_16 ) + p2XSaIFunc(pBackBuffer,sdx<<2,(unsigned char *)pSaIBigBuff,sdx,sdy); + else if(p2XSaIFunc==hq3x_16) + p2XSaIFunc(pBackBuffer,sdx*6,(unsigned char *)pSaIBigBuff,sdx,sdy); + else +#endif //!__GX__ + p2XSaIFunc(pBackBuffer,sdx<<1,(unsigned char *)pSaIBigBuff,sdx,sdy); + pSrc=(unsigned short *)pSaIBigBuff; + //sdx+=sdx;sdy+=sdy; + if(iUseNoStretchBlt>=12) + { + sdx= sdx*3; + sdy=sdy*3; + } + else + sdx+=sdx;sdy+=sdy; +} + + xinc = (sdx << 16) / ddx; + + ypos=0; + yinc = (sdy << 16) / ddy; + + for(y=0;y>16); + + if(cy==cyo) + { +#ifndef USE_DGA2 + pDstR=(unsigned long *)(pDst-ddx); +#else + pDstR=(unsigned long *)(pDst-(ddx+dga2Fix)); +#endif + for(x=0;x0;--x) + { + pSrcR+= xpos>>16; + xpos -= xpos&0xffff0000; + *pDst++=*pSrcR; + xpos += xinc; + } + } +#ifdef USE_DGA2 + if (DGA2fix) pDst+= dga2Fix; +#endif + } +} + +//////////////////////////////////////////////////////////////////////// + +// non-stretched stretched 2xsai linux helper + +void XStretchBlt16NS(unsigned char * pBB,int sdx,int sdy,int ddx,int ddy) +{ + static int iOldDX=0; + static int iOldDY=0; + int iDX2, iDY2; + unsigned short * pSrc,* pDst=(unsigned short *)pBB; + + int iX,iY,iDX,iDY,x,y,iOffS,iOffD,iS; +#ifndef __GX__ +if(iUseNoStretchBlt>=12 && sdx < 341) +{ +if(p2XSaIFunc==hq2x_16) + p2XSaIFunc=hq3x_16; +if(p2XSaIFunc==Scale2x_ex6_5) + p2XSaIFunc=Scale3x_ex6_5; + iDX2=PreviousPSXDisplay.DisplayMode.x*3; + iDY2=PreviousPSXDisplay.DisplayMode.y*3; +} +else +{ + iDX2=PreviousPSXDisplay.DisplayMode.x<<1; + iDY2=PreviousPSXDisplay.DisplayMode.y<<1; +if(p2XSaIFunc==hq3x_16) + p2XSaIFunc=hq2x_16; +if(p2XSaIFunc==Scale3x_ex6_5) + p2XSaIFunc=Scale2x_ex6_5; +} +#else //!__GX__ + iDX2=PreviousPSXDisplay.DisplayMode.x<<1; + iDY2=PreviousPSXDisplay.DisplayMode.y<<1; +if(p2XSaIFunc==Scale3x_ex6_5) + p2XSaIFunc=Scale2x_ex6_5; +#endif //__GX__ +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)pBB == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + iX=iResX-iDX2; + iY=iResY-iDY2; + + iOffS=0; + iOffD=0; + + if(iX<0) {iOffS=iDX2-iResX;iX=0; iDX=iResX;} + else {iOffD=iX; iX=iX/2;iDX=iDX2;} + + if(iY<0) {iY=0;iDY=iResY;} + else {iY=iY/2;iDY=iDY2;} + + if(iOldDX!=iDX || iOldDY!=iDY) + { + memset(Xpixels,0,iResY*iResX*2); + iOldDX=iDX;iOldDY=iDY; + } + + p2XSaIFunc(pBackBuffer,sdx<<1,(unsigned char *)pSaIBigBuff,sdx,sdy); +#ifndef __GX__ + if(p2XSaIFunc==hq2x_16 ) + p2XSaIFunc(pBackBuffer,sdx<<2,(unsigned char *)pSaIBigBuff,sdx,sdy); + else if(p2XSaIFunc==hq3x_16) + p2XSaIFunc(pBackBuffer,sdx*6,(unsigned char *)pSaIBigBuff,sdx,sdy); + else + p2XSaIFunc(pBackBuffer,sdx<<1,(unsigned char *)pSaIBigBuff,sdx,sdy); +#endif //!__GX__ + pSrc=(unsigned short *)pSaIBigBuff; + + if(iUseScanLines) {iS=2;iOffD+=iResX;iOffS+=iDX2;} else iS=1; + pDst+=iX+iY*iResX; + + for(y=0;ymode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + // 2xsai stretching + + if(iUseNoStretchBlt>=2) + { +#ifndef __GX__ + if(p2XSaIFunc==hq2x_16 ) + p2XSaIFunc(pBackBuffer,sdx<<2,(unsigned char *)pSaIBigBuff,sdx,sdy); + else if(p2XSaIFunc==hq3x_16) + p2XSaIFunc(pBackBuffer,sdx*6,(unsigned char *)pSaIBigBuff,sdx,sdy); + else +#endif //!__GX__ + p2XSaIFunc(pBackBuffer,sdx<<1,(unsigned char *)pSaIBigBuff,sdx,sdy); + pSrc=(unsigned short *)pSaIBigBuff; + //sdx+=sdx;sdy+=sdy; + if(iUseNoStretchBlt>=12) + { + sdx= sdx*3; + sdy=sdy*3; + } + else + sdx+=sdx;sdy+=sdy; + } + + xinc = (sdx << 16) / ddx; + + ypos=0; + yinc = ((sdy << 16) / ddy)<<1; + + for(y=0;y>16); + pSrcR=pSrc+(cy*sdx); + xpos = 0; + for(x=ddx;x>0;--x) + { + pSrcR+= xpos>>16; + xpos -= xpos&0xffff0000; + *pDst++=*pSrcR; + xpos += xinc; + } +#ifdef USE_DGA2 + if (DGA2fix) pDst+= dga2Fix*2; +#endif + pDst+=iResX; + } +} + +//////////////////////////////////////////////////////////////////////// + +void XStretchBlt32(unsigned char * pBB,int sdx,int sdy,int ddx,int ddy) +{ + unsigned long * pSrc=(unsigned long *)pBackBuffer; + unsigned long * pSrcR=NULL; + unsigned long * pDst=(unsigned long *)pBB; + unsigned long * pDstR=NULL; + int x,y,cyo=-1,cy; + int xpos, xinc; + int ypos, yinc; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)pBB == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + dga2Fix/=2; + } else DGA2fix = dga2Fix = 0; +#endif + + //!P! + // 2xsai stretching + if(iUseNoStretchBlt>=2) + { +#ifndef __GX__ +if( p2XSaIFunc==hq3x_32) + p2XSaIFunc(pBackBuffer,sdx*12, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else if(p2XSaIFunc==hq2x_32) + p2XSaIFunc(pBackBuffer,sdx<<3, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else +#endif //!__GX__ + p2XSaIFunc(pBackBuffer,sdx<<2, + (unsigned char *)pSaIBigBuff, + sdx,sdy); + + + pSrc=(unsigned long *)pSaIBigBuff; + //sdx+=sdx;sdy+=sdy; + if(iUseNoStretchBlt>=12) + { + sdx= sdx*3;sdy=sdy*3; + //sdx+=sdx;sdy+=sdy; + } + else + sdx+=sdx;sdy+=sdy; + } + + xinc = (sdx << 16) / ddx; + + ypos=0; + yinc = (sdy << 16) / ddy; + + for(y=0;y>16); + + if(cy==cyo) + { +#ifndef USE_DGA2 + pDstR=pDst-ddx; +#else + pDstR=pDst-(ddx+dga2Fix); +#endif + for(x=0;x0;--x) + { + pSrcR+= xpos>>16; + xpos -= xpos&0xffff0000; + *pDst++=*pSrcR; + xpos += xinc; + } + } +#ifdef USE_DGA2 + if (DGA2fix) pDst+= dga2Fix; +#endif + } +} + +//////////////////////////////////////////////////////////////////////// + +// new linux non-stretched 2xSaI helper + +void XStretchBlt32NS(unsigned char * pBB,int sdx,int sdy,int ddx,int ddy) +{ + static int iOldDX=0; + static int iOldDY=0; + + unsigned long * pSrc,* pDst=(unsigned long *)pBB; + + int iX,iY,iDX,iDY,x,y,iOffS,iOffD,iS; +#ifndef __GX__ + int iDX2; + int iDY2; +if(iUseNoStretchBlt>=12 && sdx < 341) +{ +if(p2XSaIFunc==hq2x_32) + p2XSaIFunc=hq3x_32; + if(p2XSaIFunc==Scale2x_ex8) + p2XSaIFunc=Scale3x_ex8; + iDX2=PreviousPSXDisplay.DisplayMode.x*3; + iDY2=PreviousPSXDisplay.DisplayMode.y*3; +} +else +{ + iDX2=PreviousPSXDisplay.DisplayMode.x<<1; + iDY2=PreviousPSXDisplay.DisplayMode.y<<1; +if(p2XSaIFunc==hq3x_32) + p2XSaIFunc=hq2x_32; + if(p2XSaIFunc==Scale3x_ex8) + p2XSaIFunc=Scale2x_ex8; +} +#else //!__GX__ + int iDX2=PreviousPSXDisplay.DisplayMode.x<<1; + int iDY2=PreviousPSXDisplay.DisplayMode.y<<1; + if(p2XSaIFunc==Scale3x_ex8) + p2XSaIFunc=Scale2x_ex8; +#endif //__GX__ +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)pBB == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + dga2Fix/=2; + } else DGA2fix = dga2Fix = 0; +#endif + + iX=iResX-iDX2; + iY=iResY-iDY2; + + iOffS=0; + iOffD=0; + + if(iX<0) {iOffS=iDX2-iResX;iX=0; iDX=iResX;} + else {iOffD=iX; iX=iX/2;iDX=iDX2;} + + if(iY<0) {iY=0;iDY=iResY;} + else {iY=iY/2;iDY=iDY2;} + + if(iOldDX!=iDX || iOldDY!=iDY) + { + memset(Xpixels,0,iResY*iResX*4); + iOldDX=iDX;iOldDY=iDY; + } + +#ifndef __GX__ +if( p2XSaIFunc==hq3x_32) + p2XSaIFunc(pBackBuffer,sdx*12, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else if(p2XSaIFunc==hq2x_32) + p2XSaIFunc(pBackBuffer,sdx<<3, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else +#endif //!__GX__ + p2XSaIFunc(pBackBuffer,sdx<<2, + (unsigned char *)pSaIBigBuff, + sdx,sdy); + pSrc=(unsigned long *)pSaIBigBuff; + + if(iUseScanLines) {iS=2;iOffD+=iResX;iOffS+=iDX2;} else iS=1; + pDst+=iX+iY*iResX; + + for(y=0;ymode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + // 2xsai stretching + if(iUseNoStretchBlt>=2) + { +#ifndef __GX__ +if( p2XSaIFunc==hq3x_32) + p2XSaIFunc(pBackBuffer,sdx*12, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else if(p2XSaIFunc==hq2x_32) + p2XSaIFunc(pBackBuffer,sdx<<3, + (unsigned char *)pSaIBigBuff, + sdx,sdy); +else +#endif //!__GX__ + p2XSaIFunc(pBackBuffer,sdx<<2, + (unsigned char *)pSaIBigBuff, + sdx,sdy); + pSrc=(unsigned long *)pSaIBigBuff; +// sdx+=sdx;sdy+=sdy; + if(iUseNoStretchBlt>=12) + { + sdx= sdx*3; + sdy=sdy*3; + } + else + sdx+=sdx;sdy+=sdy; + } + + xinc = (sdx << 16) / ddx; + + ypos=0; + yinc = ((sdy << 16) / ddy)<<1; + + for(y=0;y>16); + pSrcR=pSrc+(cy*sdx); + xpos = 0; + for(x=ddx;x>0;--x) + { + pSrcR+= xpos>>16; + xpos -= xpos&0xffff0000; + *pDst++=*pSrcR; + xpos += xinc; + } +#ifdef USE_DGA2 + if (DGA2fix) pDst+= dga2Fix; +#endif + pDst+=iResX; + } +} + +/////////////////////////////////////////////////////////////////////// +#ifdef USE_DGA2 + +void XDGABlit(unsigned char *pSrc, int sw, int sh, int dx, int dy) +{ + unsigned char *pDst; + int bytesPerPixel = dgaDev->mode.bitsPerPixel / 8; + + for(;dydata + dgaDev->mode.imageWidth * dy * bytesPerPixel + dx * bytesPerPixel; + memcpy(pDst, pSrc, sw * bytesPerPixel); + pSrc+= sw * bytesPerPixel; + } +} + +#endif +#endif //SDL2 + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +void ShowGunCursor(unsigned char * surf,int iPitch) +{ + unsigned short dx=(unsigned short)PreviousPSXDisplay.Range.x1; + unsigned short dy=(unsigned short)PreviousPSXDisplay.DisplayMode.y; + int x,y,iPlayer,sx,ex,sy,ey; + + if(iColDepth==32) iPitch=iPitch<<2; + else iPitch=iPitch<<1; + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*iPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(iColDepth==32) // 32 bit color depth + { + const unsigned long crCursorColor32[8]={0xffff0000,0xff00ff00,0xff0000ff,0xffff00ff,0xffffff00,0xff00ffff,0xffffffff,0xff7f7f7f}; + + surf+=PreviousPSXDisplay.Range.x0<<2; // -> add x left border + + for(iPlayer=0;iPlayer<8;iPlayer++) // -> loop all possible players + { + if(usCursorActive&(1< player active? + { + const int ty=(ptCursorPoint[iPlayer].y*dy)/256; // -> calculate the cursor pos in the current display + const int tx=(ptCursorPoint[iPlayer].x*dx)/512; + sx=tx-5;if(sx<0) {if(sx&1) sx=1; else sx=0;} + sy=ty-5;if(sy<0) {if(sy&1) sy=1; else sy=0;} + ex=tx+6;if(ex>dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y do dotted y line + *((unsigned long *)((surf)+(y*iPitch)+x*4))=crCursorColor32[iPlayer]; + for(y=ty,x=sx;x do dotted x line + *((unsigned long *)((surf)+(y*iPitch)+x*4))=crCursorColor32[iPlayer]; + } + } + } + else // 16 bit color depth + { + const unsigned short crCursorColor16[8]={0xf800,0x07c0,0x001f,0xf81f,0xffc0,0x07ff,0xffff,0x7bdf}; + + surf+=PreviousPSXDisplay.Range.x0<<1; // -> same stuff as above + + for(iPlayer=0;iPlayer<8;iPlayer++) + { + if(usCursorActive&(1<dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y +extern time_t tStart; + +void NoStretchSwap(void) +{ + static int iOldDX=0; + static int iOldDY=0; + + int iDX,iDY,iODX=0,iODY=0; + int iX=iResX-(PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0); + int iY=iResY-PreviousPSXDisplay.DisplayMode.y; + + if(iX<0) + { + iX=0;iDX=iResX; + iODX=PreviousPSXDisplay.Range.x1; + PreviousPSXDisplay.Range.x1=iResX-PreviousPSXDisplay.Range.x0; + } + else {iX=iX/2;iDX=PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0;} + + if(iY<0) + { + iY=0;iDY=iResY; + iODY=PreviousPSXDisplay.DisplayMode.y; + PreviousPSXDisplay.DisplayMode.y=iResY; + } + else {iY=iY/2;iDY=PreviousPSXDisplay.DisplayMode.y;} + + if(iOldDX!=iDX || iOldDY!=iDY) + { +#ifndef _SDL2 + memset(Xpixels,0,iResY*iResX*4); +#endif +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) +#endif + XPutImage(display,window,hGC, XCimage, + 0, 0, 0, 0, iResX,iResY); +#else +#ifndef __GX__ + rectdst.x=iX; + rectdst.y=iY; + rectdst.w=iDX; + rectdst.h=iDY; +// SDL_BlitSurface(XCimage,NULL,display,NULL); + + SDL_FillRect(display,NULL,0); +#endif //!__GX__ +#endif + + iOldDX=iDX;iOldDY=iDY; + } +#ifndef _SDL2 + BlitScreenNS((unsigned char *)Xpixels, + PSXDisplay.DisplayPosition.x, + PSXDisplay.DisplayPosition.y); + + if(usCursorActive) ShowGunCursor((unsigned char *)Xpixels,iResX); + + + +#else + rectsrc.x=PSXDisplay.DisplayPosition.x; + rectsrc.y=PSXDisplay.DisplayPosition.y; + rectsrc.h=PreviousPSXDisplay.DisplayMode.y; + if(PSXDisplay.RGB24) + { + + rectsrc.w=PreviousPSXDisplay.Range.x1/*2/3*/; + SDL_BlitSurface(Ximage24,&rectsrc,display,&rectdst); + } + else + { + + rectsrc.w=PreviousPSXDisplay.Range.x1; + SDL_BlitSurface(Ximage16,&rectsrc,display,&rectdst); + } +#endif + if(iODX) PreviousPSXDisplay.Range.x1=iODX; + if(iODY) PreviousPSXDisplay.DisplayMode.y=iODY; + +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) +#endif + XPutImage(display,window,hGC, Ximage, + 0, 0, iX, iY, iDX,iDY); +#else + +#ifndef __GX__ +#ifndef _SDL2 + SDL_BlitSurface(Ximage,NULL,display,&rectdst); +#endif +#endif //!__GX__ + +#endif + + if(ulKeybits&KEY_SHOWFPS) //DisplayText(); // paint menu text + { + if(szDebugText[0] && ((time(NULL) - tStart) < 2)) + { + strcpy(szDispBuf,szDebugText); + } + else + { + szDebugText[0]=0; + strcat(szDispBuf,szMenuBuf); + } +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) + { +#endif + XPutImage(display,window,hGC, XFimage, + 0, 0, 0, 0, 230,15); + XDrawString(display,window,hGC,2,13,szDispBuf,strlen(szDispBuf)); +#ifdef USE_DGA2 + } + else + { + DrawString(dgaDev->data, dgaDev->mode.imageWidth * (dgaDev->mode.bitsPerPixel / 8) + , dgaDev->mode.bitsPerPixel, 0, 0, iResX, 15, szDispBuf, strlen(szDispBuf), DSM_NORMAL); + } +#endif +#else +#ifndef __GX__ + SDL_WM_SetCaption(szDispBuf,NULL); //just a quick fix, +#endif //!__GX__ +#endif + } + +#ifndef __GX__ + if(XPimage) DisplayPic(); +#endif //!__GX__ + +#ifndef _SDL + XSync(display,False); +#else +#ifndef __GX__ + SDL_Flip(display); +#else //!__GX__ +// GX_blit(iResX, iResY, Xpixels, int pitch) +#endif //__GX__ +#endif + +} + +//////////////////////////////////////////////////////////////////////// +#ifdef __GX__ + +void BlitScreenNS_GX(unsigned char * surf,long x,long y) +{ + unsigned long lu; + unsigned short row,column; + unsigned short dx=PreviousPSXDisplay.Range.x1; + unsigned short dy=PreviousPSXDisplay.DisplayMode.y; + unsigned short LineOffset,SurfOffset; + long lPitch=iResX_Max<<1; +// long lPitch=iResX<<1; +#ifdef USE_DGA2 + int DGA2fix; + int dga2Fix; + if (!iWindowMode) + { + DGA2fix = (char*)surf == Xpixels; + dga2Fix = dgaDev->mode.imageWidth - dgaDev->mode.viewportWidth; + } else DGA2fix = dga2Fix = 0; +#endif + + if(PreviousPSXDisplay.Range.y0) // centering needed? + { + surf+=PreviousPSXDisplay.Range.y0*lPitch; + dy-=PreviousPSXDisplay.Range.y0; + } + + if(PSXDisplay.RGB24) + { + unsigned char * pD;unsigned int startxy; + + surf+=PreviousPSXDisplay.Range.x0<<1; +#ifdef USE_DGA2 + if (DGA2fix) lPitch+= dga2Fix*2; +#endif + + for(column=0;column>3); + pD+=3; + } + } + } + else + { + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + +#ifdef USE_DGA2 + dga2Fix/=2; +#endif + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; +#ifdef USE_DGA2 + if (DGA2fix) DSTPtr+= dga2Fix; +#endif + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void GX_Flip(int width, int height, u8 * buffer, int pitch) +{ + int h, w; +// int h, w, hh; + static int oldwidth=0; + static int oldheight=0; + static GXTexObj GXtexobj; +// short *dst1 = (short *) GXtexture; +// short *src = (short *) buffer; + long long int *dst = (long long int *) GXtexture; + long long int *src1 = (long long int *) buffer; + long long int *src2 = (long long int *) (buffer + pitch); + long long int *src3 = (long long int *) (buffer + (pitch * 2)); + long long int *src4 = (long long int *) (buffer + (pitch * 3)); + int rowpitch = (pitch >> 3) * 3; + int rowadjust = ( pitch % 8 ) * 4; + char *ra = NULL; + +// short *vbuffer = (short *) psxVuw; + +/* char *dump_filename = "dev0:\\PSXROMS\\vmem.txt"; + FILE* f = NULL; + char string[100];*/ + + if((width == 0) || (height == 0)) + return; + +/* f = fopen( dump_filename, "wb" ); + for (w = 0; w<1024;w++) + { + for (h = 0; h> 2); h++) + { + *dst++ = *src1++; + *dst++ = *src2++; + *dst++ = *src3++; + *dst++ = *src4++; + } + + src1 += rowpitch; + src2 += rowpitch; + src3 += rowpitch; + src4 += rowpitch; + + if ( rowadjust ) + { + ra = (char *)src1; + src1 = (long long int *)(ra + rowadjust); + ra = (char *)src2; + src2 = (long long int *)(ra + rowadjust); + ra = (char *)src3; + src3 = (long long int *)(ra + rowadjust); + ra = (char *)src4; + src4 = (long long int *)(ra + rowadjust); + } + } + + DCFlushRange(GXtexture, width*height*2); + GX_LoadTexObj(&GXtexobj, GX_TEXMAP0); + + Mtx44 GXprojIdent; + Mtx GXmodelIdent; + guMtxIdentity(GXprojIdent); + guMtxIdentity(GXmodelIdent); + GXprojIdent[2][2] = 0.5; + GXprojIdent[2][3] = -0.5; + GX_LoadProjectionMtx(GXprojIdent, GX_ORTHOGRAPHIC); + GX_LoadPosMtxImm(GXmodelIdent,GX_PNMTX0); + + GX_SetCullMode(GX_CULL_NONE); + GX_SetZMode(GX_ENABLE,GX_ALWAYS,GX_TRUE); + + GX_InvalidateTexAll(); + GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL); + + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_IDENTITY); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + +// GX_SetNumChans(1); + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2f32(-1.0, 1.0); + GX_TexCoord2f32( 0.0, 0.0); + GX_Position2f32( 1.0, 1.0); + GX_TexCoord2f32( 1.0, 0.0); + GX_Position2f32( 1.0,-1.0); + GX_TexCoord2f32( 1.0, 1.0); + GX_Position2f32(-1.0,-1.0); + GX_TexCoord2f32( 0.0, 1.0); +/* GX_Position2f32(-1.0, 1.0); + GX_TexCoord2f32( 0.0, 0.0); + GX_Position2f32( 1.0, 1.0); + GX_TexCoord2f32( 0.0, 1.0); + GX_Position2f32( 1.0,-1.0); + GX_TexCoord2f32( 1.0, 1.0); + GX_Position2f32(-1.0,-1.0); + GX_TexCoord2f32( 1.0, 0.0);*/ + GX_End(); + +//Temporary: draw a primitive to make sure something is displaying +/* GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); +// GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_IDENTITY); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT); +// GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); +// GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_SetNumTexGens(0); +// GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + GX_SetNumChans(1); +// GX_LoadTexObj(&GXtexobj, GX_TEXMAP0); + + GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0); + GXColor GXcolorR = (GXColor) {255, 0, 0,255}; + GXColor GXcolorG = (GXColor) { 0,255, 0,255}; + GXColor GXcolorB = (GXColor) { 0, 0,255,255}; + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2f32(-0.5, 0.5); + GX_Color4u8(GXcolorR.r, GXcolorR.g, GXcolorR.b, GXcolorR.a); +// GX_TexCoord2f32( 0.0, 0.0); + GX_Position2f32( 0.5, 0.5); + GX_Color4u8(GXcolorG.r, GXcolorG.g, GXcolorG.b, GXcolorG.a); +// GX_TexCoord2f32( 1.0, 0.0); + GX_Position2f32( 0.5,-0.5); + GX_Color4u8(GXcolorB.r, GXcolorB.g, GXcolorB.b, GXcolorB.a); +// GX_TexCoord2f32( 1.0, 1.0); + GX_Position2f32(-0.5,-0.5); + GX_Color4u8(GXcolorB.r, GXcolorB.g, GXcolorB.b, GXcolorB.a); +// GX_TexCoord2f32( 0.0, 1.0); + GX_End();*/ +//End test + + GX_DrawDone(); + +// GX_SetZMode(GX_TRUE, GX_LEQUAL, GX_TRUE); +// GX_SetColorUpdate(GX_TRUE); + + whichfb ^= 1; + GX_CopyDisp(xfb[0], GX_TRUE); +// GX_Flush(); + GX_DrawDone(); +// printf("blit - whichfb = %d; xfb = %x, %x\n",whichfb,xfb[0],xfb[1]); +// printf("Prv.Rng.x0,x1,y0 = %d, %d, %d, Prv.Mode.y = %d,DispPos.x,y = %d, %d, RGB24 = %x\n",PreviousPSXDisplay.Range.x0,PreviousPSXDisplay.Range.x1,PreviousPSXDisplay.Range.y0,PreviousPSXDisplay.DisplayMode.y,PSXDisplay.DisplayPosition.x,PSXDisplay.DisplayPosition.y,PSXDisplay.RGB24); + VIDEO_SetNextFramebuffer(xfb[0]); + VIDEO_Flush(); +// VIDEO_WaitVSync(); + +} + +//////////////////////////////////////////////////////////////////////// + +void NoStretchSwap_GX(void) +{ + static int iOldDX=0; + static int iOldDY=0; + +/* int iDX,iDY,iODX=0,iODY=0; + int iX=iResX-(PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0); + int iY=iResY-PreviousPSXDisplay.DisplayMode.y;*/ + +// int iDX = PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0; + int iDX = PreviousPSXDisplay.Range.x1; + int iDY = PreviousPSXDisplay.DisplayMode.y; + //int iX=0,iY=0; //no top or left border + //int iODX=0,iODY=0; + +/* if(iX<0) + { + iX=0;iDX=iResX; + iODX=PreviousPSXDisplay.Range.x1; + PreviousPSXDisplay.Range.x1=iResX-PreviousPSXDisplay.Range.x0; + } + else {iX=iX/2;iDX=PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0;} + + if(iY<0) + { + iY=0;iDY=iResY; + iODY=PreviousPSXDisplay.DisplayMode.y; + PreviousPSXDisplay.DisplayMode.y=iResY; + } + else {iY=iY/2;iDY=PreviousPSXDisplay.DisplayMode.y;}*/ + + if(!Xpixels) + { + printf("Xpixels is NULL\n"); + return; + } + if(iOldDX!=iDX || iOldDY!=iDY) + { + memset(Xpixels,0,iResY_Max*iResX_Max*4); + iOldDX=iDX;iOldDY=iDY; +/*#ifndef _SDL2 + memset(Xpixels,0,iResY_Max*iResX_Max*4); +#endif +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) +#endif + XPutImage(display,window,hGC, XCimage, + 0, 0, 0, 0, iResX,iResY); +#else +#ifndef __GX__ + rectdst.x=iX; + rectdst.y=iY; + rectdst.w=iDX; + rectdst.h=iDY; +// SDL_BlitSurface(XCimage,NULL,display,NULL); + + SDL_FillRect(display,NULL,0); +#endif //!__GX__ +#endif + iOldDX=iDX;iOldDY=iDY;*/ + } +//#ifndef _SDL2 + BlitScreenNS_GX((unsigned char *)Xpixels, + PSXDisplay.DisplayPosition.x, + PSXDisplay.DisplayPosition.y); + +// if(usCursorActive) ShowGunCursor((unsigned char *)Xpixels,iResX_Max); + + + +/*#else + rectsrc.x=PSXDisplay.DisplayPosition.x; + rectsrc.y=PSXDisplay.DisplayPosition.y; + rectsrc.h=PreviousPSXDisplay.DisplayMode.y; + if(PSXDisplay.RGB24) + { + + rectsrc.w=PreviousPSXDisplay.Range.x1// 2/3; + SDL_BlitSurface(Ximage24,&rectsrc,display,&rectdst); + } + else + { + + rectsrc.w=PreviousPSXDisplay.Range.x1; + SDL_BlitSurface(Ximage16,&rectsrc,display,&rectdst); + } +#endif + if(iODX) PreviousPSXDisplay.Range.x1=iODX; + if(iODY) PreviousPSXDisplay.DisplayMode.y=iODY;*/ + +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) +#endif + XPutImage(display,window,hGC, Ximage, + 0, 0, iX, iY, iDX,iDY); +#else + +#ifndef __GX__ +#ifndef _SDL2 + SDL_BlitSurface(Ximage,NULL,display,&rectdst); +#endif +#endif //!__GX__ + +#endif + + //TODO: This isn't implemented properly for SDL, anyway... +/* if(ulKeybits&KEY_SHOWFPS) //DisplayText(); // paint menu text + { + if(szDebugText[0] && ((time(NULL) - tStart) < 2)) + { + strcpy(szDispBuf,szDebugText); + } + else + { + szDebugText[0]=0; + strcat(szDispBuf,szMenuBuf); + } +#ifndef _SDL +#ifdef USE_DGA2 + if(iWindowMode) + { +#endif + XPutImage(display,window,hGC, XFimage, + 0, 0, 0, 0, 230,15); + XDrawString(display,window,hGC,2,13,szDispBuf,strlen(szDispBuf)); +#ifdef USE_DGA2 + } + else + { + DrawString(dgaDev->data, dgaDev->mode.imageWidth * (dgaDev->mode.bitsPerPixel / 8) + , dgaDev->mode.bitsPerPixel, 0, 0, iResX, 15, szDispBuf, strlen(szDispBuf), DSM_NORMAL); + } +#endif +#else +#ifndef __GX__ + SDL_WM_SetCaption(szDispBuf,NULL); //just a quick fix, +#endif //!__GX__ +#endif + }*/ + +/*#ifndef __GX__ + //TODO: Implement this feature + if(XPimage) DisplayPic(); +#endif //!__GX__*/ + +/*#ifndef _SDL + XSync(display,False); +#else +#ifndef __GX__ + SDL_Flip(display); +#else //!__GX__ + GX_blit(iResX, iResY, Xpixels, int pitch) +#endif //__GX__ +#endif*/ +// GX_Flip(iDX, iDY,(unsigned char *) Xpixels, iResX_Max*2); + GX_Flip(1024, 1024,(unsigned char *) psxVuw, 1024*2); +} +#endif //__GX__ +//////////////////////////////////////////////////////////////////////// + +void DoBufferSwap(void) // SWAP BUFFERS +{ // (we don't swap... we blit only) + + // TODO: visual rumble + +/* + if(iRumbleTime) + { + ScreenRect.left+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.right+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.top+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.bottom+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + iRumbleTime--; + } +*/ + +#ifdef __GX__ + // For now stretch only using GX + // TODO: Also show menu text. + printf("DoBufferSwap\n"); + NoStretchSwap_GX(); + return; +#endif // __GX__ + + #ifdef _SDL2 + SDL_Surface *buf; + #endif + + if(iUseNoStretchBlt<2) + { + if(iUseNoStretchBlt || + (PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0 == iResX && + PreviousPSXDisplay.DisplayMode.y == iResY)) + {NoStretchSwap();return;} + } + +#ifndef _SDL2 + BlitScreen(pBackBuffer, + PSXDisplay.DisplayPosition.x, + PSXDisplay.DisplayPosition.y); + + if(usCursorActive) ShowGunCursor(pBackBuffer,PreviousPSXDisplay.Range.x0+PreviousPSXDisplay.Range.x1); + + //----------------------------------------------------// + + XStretchBlt((unsigned char *)Xpixels, + PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0, + PreviousPSXDisplay.DisplayMode.y, + iResX,iResY); + + //----------------------------------------------------// +#else + + rectdst.x=0; + rectdst.y=0; + rectdst.w=iResX; + rectdst.h=iResY; + + rectsrc.x=PSXDisplay.DisplayPosition.x; + rectsrc.y=PSXDisplay.DisplayPosition.y; + rectsrc.h=PreviousPSXDisplay.DisplayMode.y; + rectsrc.w=PreviousPSXDisplay.Range.x1; + if(PSXDisplay.RGB24) + { + + SDL_SoftStretch(buf=SDL_DisplayFormat(Ximage24), &rectsrc, + display, &rectdst); + } + else + { + SDL_SoftStretch(buf=SDL_DisplayFormat(Ximage16), &rectsrc, + display, &rectdst); + } +SDL_FreeSurface(buf); +#endif +#ifndef _SDL2 +#ifndef _SDL +#ifdef USE_DGA2 + if (iWindowMode) +#endif + XPutImage(display,window,hGC, Ximage, + 0, 0, 0, 0, + iResX, iResY); +#else +#ifndef __GX__ + SDL_BlitSurface(Ximage,NULL,display,NULL); +#endif //!__GX__ +#endif +#endif + if(ulKeybits&KEY_SHOWFPS) //DisplayText(); // paint menu text + { + if(szDebugText[0] && ((time(NULL) - tStart) < 2)) + { + strcpy(szDispBuf,szDebugText); + } + else + { + szDebugText[0]=0; + strcat(szDispBuf,szMenuBuf); + } +#ifndef _SDL +#ifdef USE_DGA2 + if (iWindowMode) + { +#endif + XPutImage(display,window,hGC, XFimage, + 0, 0, 0, 0, 230,15); + XDrawString(display,window,hGC,2,13,szDispBuf,strlen(szDispBuf)); +#ifdef USE_DGA2 + } + else + { + DrawString(dgaDev->data, dgaDev->mode.imageWidth * (dgaDev->mode.bitsPerPixel / 8) + , dgaDev->mode.bitsPerPixel, 0, 0, iResX, 15, szDispBuf, strlen(szDispBuf), DSM_NORMAL); + } +#endif +#else +#ifndef __GX__ + SDL_WM_SetCaption(szDispBuf,NULL); //just a quick fix, +#endif //!__GX__ +#endif + } + +#ifndef __GX__ + if(XPimage) DisplayPic(); +#endif //!__GX__ + +#ifndef _SDL + XSync(display,False); +#else +#ifndef __GX__ + SDL_Flip(display); +#endif //!__GX__ +#endif + +} + +//////////////////////////////////////////////////////////////////////// + +void DoClearScreenBuffer(void) // CLEAR DX BUFFER +{ +#ifndef _SDL +#ifdef USE_DGA2 + if (iWindowMode) + { +#endif + XPutImage(display,window,hGC, XCimage, + 0, 0, 0, 0, iResX, iResY); + XSync(display,False); +#ifdef USE_DGA2 + } +#endif +#else + /* + SDL_BlitSurface(XCimage,NULL,display,NULL);*/ +#ifndef __GX__ + SDL_FillRect(display,NULL,0); + SDL_Flip(display); +#else //!__GX__ + printf("DoClearScreenBuffer\n"); + whichfb ^= 1; +// GX_CopyDisp(xfb[1], GX_TRUE); +// GX_Flush(); +// VIDEO_SetNextFramebuffer(xfb[0]); +// VIDEO_Flush(); +// VIDEO_WaitVSync(); +#endif //__GX__ +#endif +} + +//////////////////////////////////////////////////////////////////////// + + +void DoClearFrontBuffer(void) // CLEAR DX BUFFER +{ +#ifndef _SDL +#ifdef USE_DGA2 + if (iWindowMode) + { +#endif + XPutImage(display,window,hGC, XCimage, + 0, 0, 0, 0, iResX, iResY); + XSync(display,False); +#ifdef USE_DGA2 + } +#endif +#else +#ifndef __GX__ + SDL_FillRect(display,NULL,0); + SDL_Flip(display); +#else //!__GX__ + printf("DoClearFrontBuffer\n"); + whichfb ^= 1; +// GX_CopyDisp(xfb[1], GX_TRUE); +// GX_Flush(); +// VIDEO_SetNextFramebuffer(xfb[0]); +// VIDEO_Flush(); +// VIDEO_WaitVSync(); +#endif //__GX__ +#endif +} + + +//////////////////////////////////////////////////////////////////////// + +int Xinitialize() +{ +#ifndef _SDL2 + +#ifndef __GX__ //I don't think we need this buffer + pBackBuffer=(unsigned char *)malloc(640*512*sizeof(unsigned long)); + memset(pBackBuffer,0,640*512*sizeof(unsigned long)); +#endif //!__GX__ + + if(iColDepth==16) + { + BlitScreen=BlitScreen16;iDesktopCol=16; + if(iUseScanLines) XStretchBlt=XStretchBlt16SL; + else XStretchBlt=XStretchBlt16; + if(iUseScanLines) BlitScreenNS=BlitScreen16NSSL; + else BlitScreenNS=BlitScreen16NS; + } + else + if(iColDepth==15) + { + BlitScreen=BlitScreen15;iDesktopCol=15; + if(iUseScanLines) XStretchBlt=XStretchBlt16SL; + else XStretchBlt=XStretchBlt16; + if(iUseScanLines) BlitScreenNS=BlitScreen15NSSL; + else BlitScreenNS=BlitScreen15NS; + } + else + { + BlitScreen=BlitScreen32;iDesktopCol=32; + if(iUseScanLines) XStretchBlt=XStretchBlt32SL; + else XStretchBlt=XStretchBlt32; + if(iUseScanLines) BlitScreenNS=BlitScreen32NSSL; + else BlitScreenNS=BlitScreen32NS; + } + +#ifndef __GX__ //I don't think we need this buffer + pSaIBigBuff=malloc(1280*1024*sizeof(unsigned long)); + memset(pSaIBigBuff,0,1280*1024*sizeof(unsigned long)); +#endif //!__GX__ + + p2XSaIFunc=NULL; + + if(iUseNoStretchBlt==2 || iUseNoStretchBlt==3) + { + if (iDesktopCol==15) p2XSaIFunc=Std2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Std2xSaI_ex6; + else p2XSaIFunc=Std2xSaI_ex8; + } + + if(iUseNoStretchBlt==4 || iUseNoStretchBlt==5) + { + if (iDesktopCol==15) p2XSaIFunc=Super2xSaI_ex5; + else if(iDesktopCol==16) p2XSaIFunc=Super2xSaI_ex6; + else p2XSaIFunc=Super2xSaI_ex8; + } + + if(iUseNoStretchBlt==6 || iUseNoStretchBlt==7) + { + if (iDesktopCol==15) p2XSaIFunc=SuperEagle_ex5; + else if(iDesktopCol==16) p2XSaIFunc=SuperEagle_ex6; + else p2XSaIFunc=SuperEagle_ex8; + } + + if(iUseNoStretchBlt==8 || iUseNoStretchBlt==9) + { + if (iDesktopCol==15) p2XSaIFunc=Scale2x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale2x_ex6_5; + else p2XSaIFunc=Scale2x_ex8; + } +#ifndef __GX__ + if(iUseNoStretchBlt==10 || iUseNoStretchBlt==11) + { + InitLUTs(); + if (iDesktopCol==15) p2XSaIFunc=hq2x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq2x_16; + else + { + BlitScreen=BlitScreen16; + p2XSaIFunc=hq2x_32; + } + } + if(iUseNoStretchBlt==12 || iUseNoStretchBlt==13) + { + if (iDesktopCol==15) p2XSaIFunc=Scale3x_ex6_5; + else if(iDesktopCol==16) p2XSaIFunc=Scale3x_ex6_5; + else p2XSaIFunc=Scale3x_ex8; + } + if(iUseNoStretchBlt==14 || iUseNoStretchBlt==15) + { + InitLUTs(); + if (iDesktopCol==15) p2XSaIFunc=hq3x_16; + else if(iDesktopCol==16) p2XSaIFunc=hq3x_16; + else + { + BlitScreen=BlitScreen16; + p2XSaIFunc=hq3x_32; + } + } +#endif //!__GX__ + + if(iUseNoStretchBlt==3 || + iUseNoStretchBlt==5 || + iUseNoStretchBlt==7 || +#ifndef __GX__ + iUseNoStretchBlt==9 || + iUseNoStretchBlt==11 || + iUseNoStretchBlt==13 || + iUseNoStretchBlt==15) +#else //!__GX__ + iUseNoStretchBlt==9) +#endif // __GX__ + { + if(iDesktopCol<=16) + { + XStretchBlt=XStretchBlt16NS; + } + else + { + XStretchBlt=XStretchBlt32NS; + } + } + + +#endif + bUsingTWin=FALSE; + + InitMenu(); + + bIsFirstFrame = FALSE; // done + + if(iShowFPS) + { + iShowFPS=0; + ulKeybits|=KEY_SHOWFPS; + szDispBuf[0]=0; + BuildDispMenu(0); + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////// + +void Xcleanup() // X CLEANUP +{ + CloseMenu(); +#ifndef _SDL2 + if(pBackBuffer) free(pBackBuffer); + pBackBuffer=0; + if(iUseNoStretchBlt>=2) + { + if(pSaIBigBuff) free(pSaIBigBuff); + pSaIBigBuff=0; + } + +#endif +} + +//////////////////////////////////////////////////////////////////////// + +unsigned long ulInitDisplay(void) +{ + CreateDisplay(); // x stuff + Xinitialize(); // init x +#ifndef __GX__ + return (unsigned long)display; +#else //!__GX__ + return (unsigned long)Xpixels; //This isn't right, but didn't want to return 0.. +#endif // __GX__ +} + +//////////////////////////////////////////////////////////////////////// + +void CloseDisplay(void) +{ + Xcleanup(); // cleanup dx + DestroyDisplay(); +} + +//////////////////////////////////////////////////////////////////////// + +void CreatePic(unsigned char * pMem) +{ + unsigned char * p=(unsigned char *)malloc(128*96*4); + unsigned char * ps; int x,y; + + ps=p; + + if(iDesktopCol==16) + { + unsigned short s; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + s=(*(pMem+0))>>3; + s|=((*(pMem+1))&0xfc)<<3; + s|=((*(pMem+2))&0xf8)<<8; + pMem+=3; + *((unsigned short *)(ps+y*256+x*2))=s; + } + } + } + else + if(iDesktopCol==15) + { + unsigned short s; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + s=(*(pMem+0))>>3; + s|=((*(pMem+1))&0xfc)<<2; + s|=((*(pMem+2))&0xf8)<<7; + pMem+=3; + *((unsigned short *)(ps+y*256+x*2))=s; + } + } + } + else + if(iDesktopCol==32) + { + unsigned long l; + for(y=0;y<96;y++) + { + for(x=0;x<128;x++) + { + l= *(pMem+0); + l|=(*(pMem+1))<<8; + l|=(*(pMem+2))<<16; + pMem+=3; + *((unsigned long *)(ps+y*512+x*4))=l; + } + } + } + +#ifndef _SDL +#ifdef USE_DGA2 + if (!iWindowMode) { Xpic = p; XPimage = (XImage*)1; } + else +#endif + XPimage = XCreateImage(display,myvisual->visual, + depth, ZPixmap, 0, + (char *)p, + 128, 96, + depth>16 ? 32 : 16, + 0); +#else +#ifndef __GX__ + XPimage = SDL_CreateRGBSurfaceFrom((void *)p,128,96, + depth,depth*16, + 0x00ff0000,0x0000ff00,0x000000ff, + 0);/*hmm what about having transparency? + *Set a nonzero value here. + *and set the ALPHA flag ON + */ +#endif //!__GX__ +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void DestroyPic(void) +{ +#ifndef __GX__ + if(XPimage) + { +#ifndef _SDL +#ifdef USE_DGA2 + if (iWindowMode) + { +#endif + XPutImage(display,window,hGC, XCimage, + 0, 0, 0, 0, iResX, iResY); + XDestroyImage(XPimage); +#ifdef USE_DGA2 + } +#endif +#else + SDL_FillRect(display,NULL,0); + SDL_FreeSurface(XPimage); +#endif + XPimage=0; + } +#endif //!__GX__ +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void DisplayPic(void) +{ +#ifndef _SDL +#ifdef USE_DGA2 + if (!iWindowMode) XDGABlit(Xpic, 128, 96, iResX-128, 0); + else + { +#endif + XPutImage(display,window,hGC, XPimage, + 0, 0, iResX-128, 0,128,96); +#ifdef USE_DGA2 + } +#endif +#else +#ifndef __GX__ + rectdst.x=iResX-128; + rectdst.y=0; + rectdst.w=128; + rectdst.h=96; + SDL_BlitSurface(XPimage,NULL,display,&rectdst); +#endif //!__GX__ +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void ShowGpuPic(void) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////// + +void ShowTextGpuPic(void) +{ +} + +#endif + +/////////////////////////////////////////////////////////////////////// diff --git a/PeopsSoftGPU/draw.h b/PeopsSoftGPU/draw.h new file mode 100644 index 0000000..1825386 --- /dev/null +++ b/PeopsSoftGPU/draw.h @@ -0,0 +1,43 @@ +/*************************************************************************** + draw.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_DRAW_H_ +#define _GPU_DRAW_H_ + +void DoBufferSwap(void); +void DoClearScreenBuffer(void); +void DoClearFrontBuffer(void); +unsigned long ulInitDisplay(void); +void CloseDisplay(void); +void CreatePic(unsigned char * pMem); +void DestroyPic(void); +void DisplayPic(void); +void ShowGpuPic(void); +void ShowTextGpuPic(void); + +/////////////////////////////////////////////////////////////////////// + +#endif // _GPU_DRAW_H_ diff --git a/PeopsSoftGPU/drawGX.c b/PeopsSoftGPU/drawGX.c new file mode 100644 index 0000000..2a4540c --- /dev/null +++ b/PeopsSoftGPU/drawGX.c @@ -0,0 +1,546 @@ +/*************************************************************************** + drawGX.m + PeopsSoftGPU for cubeSX/wiiSX + + Created by sepp256 on Thur Jun 26 2008. + Copyright (c) 2008 Gil Pedersen. + Adapted from draw.c by Pete Bernet and drawgl.m by Gil Pedersen. + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +#include +#include +#include +#include "stdafx.h" +#define _IN_DRAW +#include "externals.h" +#include "gpu.h" +#include "draw.h" +#include "prim.h" +#include "menu.h" +#include "swap.h" +#include "../Gamecube/libgui/IPLFontC.h" +#include "../Gamecube/DEBUG.h" +#include "../Gamecube/wiiSXconfig.h" + +//////////////////////////////////////////////////////////////////////////////////// +// misc globals +//////////////////////////////////////////////////////////////////////////////////// +int iResX; +int iResY; +long lLowerpart; +BOOL bIsFirstFrame = TRUE; +BOOL bCheckMask=FALSE; +unsigned short sSetMask=0; +unsigned long lSetMask=0; +int iDesktopCol=16; +int iShowFPS=1; +int iWinSize; +int iUseScanLines=0; +int iUseNoStretchBlt=0; +int iFastFwd=0; +int iDebugMode=0; +int iFVDisplay=0; +PSXPoint_t ptCursorPoint[8]; +unsigned short usCursorActive=0; + +//Some GX specific variables +#define RESX_MAX 1024 //Vmem width +#define RESY_MAX 512 //Vmem height +//int iResX_Max=640; //Max FB Width +int iResX_Max=RESX_MAX; +int iResY_Max=RESY_MAX; +//char * GXtexture; +static unsigned char GXtexture[RESX_MAX*RESY_MAX*2] __attribute__((aligned(32))); +//char * Xpixels; +static unsigned char Xpixels[RESX_MAX*RESY_MAX*2] __attribute__((aligned(32))); +char * pCaptionText; + +extern u32* xfb[2]; /*** Framebuffers ***/ +extern int whichfb; /*** Frame buffer toggle ***/ +extern time_t tStart; +extern char text[DEBUG_TEXT_HEIGHT][DEBUG_TEXT_WIDTH]; /*** DEBUG textbuffer ***/ +extern char menuActive; +extern char screenMode; + +// prototypes +void BlitScreenNS_GX(unsigned char * surf,long x,long y, short dx, short dy); +void GX_Flip(short width, short height, u8 * buffer, int pitch); + +void DoBufferSwap(void) // SWAP BUFFERS +{ // (we don't swap... we blit only) + static int iOldDX=0; + static int iOldDY=0; + long x = PSXDisplay.DisplayPosition.x; + long y = PSXDisplay.DisplayPosition.y; +// int iDX = PreviousPSXDisplay.Range.x1+PreviousPSXDisplay.Range.x0; + short iDX = PreviousPSXDisplay.Range.x1; + short iDY = PreviousPSXDisplay.DisplayMode.y; + + if (menuActive) return; + + //Uncomment the following line to render all of vmem on screen. + //Note: may break when PSX is in true color mode... + //x = 0; y = 0; iDX = 1024; iDY = 512; + + // TODO: visual rumble + +/* + if(iRumbleTime) + { + ScreenRect.left+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.right+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.top+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + ScreenRect.bottom+=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2); + iRumbleTime--; + } +*/ + +// For now stretch only using GX +// printf("DoBufferSwap\n"); + + if(iOldDX!=iDX || iOldDY!=iDY) + { + memset(Xpixels,0,iResY_Max*iResX_Max*2); + iOldDX=iDX;iOldDY=iDY; + } + + BlitScreenNS_GX((unsigned char *)Xpixels, x, y, iDX, iDY); + +// TODO: Show Gun cursor +// if(usCursorActive) ShowGunCursor(pBackBuffer,PreviousPSXDisplay.Range.x0+PreviousPSXDisplay.Range.x1); + +// TODO: Show menu text + if(ulKeybits&KEY_SHOWFPS) //DisplayText(); // paint menu text + { + if(szDebugText[0] && ((time(NULL) - tStart) < 2)) + { + strcpy(szDispBuf,szDebugText); + } + else + { + szDebugText[0]=0; + strcat(szDispBuf,szMenuBuf); + } + } + +// This isn't implemented, yet. I'm not sure what it's for. +// if(XPimage) DisplayPic(); + + GX_Flip(iDX, iDY,(unsigned char *) Xpixels, iResX_Max*2); +// GX_Flip(1024, iGPUHeight,(unsigned char *) psxVuw, 1024*2); +} + +//////////////////////////////////////////////////////////////////////// + +void DoClearScreenBuffer(void) // CLEAR DX BUFFER +{ + // clear the screen, and DON'T flush it + DEBUG_print("DoClearScreenBuffer",DBG_GPU1); +// printf("DoClearScreenBuffer\n"); +// whichfb ^= 1; +// GX_CopyDisp(xfb[1], GX_TRUE); +// GX_Flush(); +// VIDEO_SetNextFramebuffer(xfb[0]); +// VIDEO_Flush(); +// VIDEO_WaitVSync(); +} + +//////////////////////////////////////////////////////////////////////// + +void DoClearFrontBuffer(void) // CLEAR DX BUFFER +{ + if (menuActive) return; + + // clear the screen, and flush it + DEBUG_print("DoClearFrontBuffer",DBG_GPU1); +// printf("DoClearFrontBuffer\n"); + + //Write menu/debug text on screen + GXColor fontColor = {150,255,150,255}; + IplFont_drawInit(fontColor); + if((ulKeybits&KEY_SHOWFPS)&&showFPSonScreen) + IplFont_drawString(10,35,szDispBuf, 1.0, false); + + int i = 0; + DEBUG_update(); + for (i=0;i>3); + pD+=3; + } + } + } + else + { + unsigned short LineOffset,SurfOffset; + unsigned long * SRCPtr = (unsigned long *)(psxVuw + + (y<<10) + x); + + unsigned long * DSTPtr = + ((unsigned long *)surf)+(PreviousPSXDisplay.Range.x0>>1); + + dx>>=1; + + LineOffset = 512 - dx; + SurfOffset = (lPitch>>2) - dx; + + for(column=0;column>10)&0x1f001f); + } + SRCPtr += LineOffset; + DSTPtr += SurfOffset; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void GX_Flip(short width, short height, u8 * buffer, int pitch) +{ + int h, w; +// int h, w, hh; + static int oldwidth=0; + static int oldheight=0; + static GXTexObj GXtexobj; +// short *dst1 = (short *) GXtexture; +// short *src = (short *) buffer; + long long int *dst = (long long int *) GXtexture; + long long int *src1 = (long long int *) buffer; + long long int *src2 = (long long int *) (buffer + pitch); + long long int *src3 = (long long int *) (buffer + (pitch * 2)); + long long int *src4 = (long long int *) (buffer + (pitch * 3)); + int rowpitch = (pitch >> 3) * 4 - (width >> 2); + int rowadjust = ( pitch % 8 ) * 4; + char *ra = NULL; + + + if((width == 0) || (height == 0)) + return; + + if ((oldwidth != width) || (oldheight != height)) + { //adjust texture conversion + oldwidth = width; + oldheight = height; + memset(GXtexture,0,iResX_Max*iResY_Max*2); + GX_InitTexObj(&GXtexobj, GXtexture, width, height, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); + } +/* + for (h = 0; h < height; h += 4) + { + for (w = 0; w < width ; w += 4) + { + for (hh = 0; hh < 4; h++) + { + *dst1++ = src[(h+hh)*1024 + w]; + *dst1++ = src[(h+hh)*1024 + w + 1]; + *dst1++ = src[(h+hh)*1024 + w + 2]; + *dst1++ = src[(h+hh)*1024 + w + 3]; +// *dst++ = src[(h+hh)*iResX_Max + w]; +// *dst++ = src[(h+hh)*iResX_Max + w + 1]; +// *dst++ = src[(h+hh)*iResX_Max + w + 2]; +// *dst++ = src[(h+hh)*iResX_Max + w + 3]; + } + } + } +*/ + + for (h = 0; h < height; h += 4) + { + + for (w = 0; w < (width >> 2); w++) + { + *dst++ = *src1++; + *dst++ = *src2++; + *dst++ = *src3++; + *dst++ = *src4++; + } + + src1 += rowpitch; + src2 += rowpitch; + src3 += rowpitch; + src4 += rowpitch; + + if ( rowadjust ) + { + ra = (char *)src1; + src1 = (long long int *)(ra + rowadjust); + ra = (char *)src2; + src2 = (long long int *)(ra + rowadjust); + ra = (char *)src3; + src3 = (long long int *)(ra + rowadjust); + ra = (char *)src4; + src4 = (long long int *)(ra + rowadjust); + } + } + + DCFlushRange(GXtexture, width*height*2); + GX_LoadTexObj(&GXtexobj, GX_TEXMAP0); + + Mtx44 GXprojIdent; + Mtx GXmodelIdent; + guMtxIdentity(GXprojIdent); + guMtxIdentity(GXmodelIdent); + GXprojIdent[2][2] = 0.5; + GXprojIdent[2][3] = -0.5; + GX_LoadProjectionMtx(GXprojIdent, GX_ORTHOGRAPHIC); + GX_LoadPosMtxImm(GXmodelIdent,GX_PNMTX0); + + GX_SetCullMode(GX_CULL_NONE); + GX_SetZMode(GX_ENABLE,GX_ALWAYS,GX_TRUE); + + GX_InvalidateTexAll(); + GX_SetTevOp(GX_TEVSTAGE0, GX_REPLACE); + GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLORNULL); + + + GX_ClearVtxDesc(); + GX_SetVtxDesc(GX_VA_PTNMTXIDX, GX_PNMTX0); + GX_SetVtxDesc(GX_VA_TEX0MTXIDX, GX_IDENTITY); + GX_SetVtxDesc(GX_VA_POS, GX_DIRECT); + GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT); + + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0); + GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); + + GX_SetNumTexGens(1); + GX_SetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); + + float xcoord = 1.0; + float ycoord = 1.0; + if(screenMode == SCREENMODE_16x9_PILLARBOX) xcoord = 640.0/848.0; + + GX_Begin(GX_QUADS, GX_VTXFMT0, 4); + GX_Position2f32(-xcoord, ycoord); + GX_TexCoord2f32( 0.0, 0.0); + GX_Position2f32( xcoord, ycoord); + GX_TexCoord2f32( 1.0, 0.0); + GX_Position2f32( xcoord,-ycoord); + GX_TexCoord2f32( 1.0, 1.0); + GX_Position2f32(-xcoord,-ycoord); + GX_TexCoord2f32( 0.0, 1.0); + GX_End(); + + //Write menu/debug text on screen + GXColor fontColor = {150,255,150,255}; + IplFont_drawInit(fontColor); + if((ulKeybits&KEY_SHOWFPS)&&showFPSonScreen) + IplFont_drawString(10,35,szDispBuf, 1.0, false); + + int i = 0; + DEBUG_update(); + for (i=0;i add x left border + + for(iPlayer=0;iPlayer<8;iPlayer++) // -> loop all possible players + { + if(usCursorActive&(1< player active? + { + const int ty=(ptCursorPoint[iPlayer].y*dy)/256; // -> calculate the cursor pos in the current display + const int tx=(ptCursorPoint[iPlayer].x*dx)/512; + sx=tx-5;if(sx<0) {if(sx&1) sx=1; else sx=0;} + sy=ty-5;if(sy<0) {if(sy&1) sy=1; else sy=0;} + ex=tx+6;if(ex>dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y do dotted y line + *((unsigned long *)((surf)+(y*iPitch)+x*4))=crCursorColor32[iPlayer]; + for(y=ty,x=sx;x do dotted x line + *((unsigned long *)((surf)+(y*iPitch)+x*4))=crCursorColor32[iPlayer]; + } + } + } + else // 16 bit color depth + { + const unsigned short crCursorColor16[8]={0xf800,0x07c0,0x001f,0xf81f,0xffc0,0x07ff,0xffff,0x7bdf}; + + surf+=PreviousPSXDisplay.Range.x0<<1; // -> same stuff as above + + for(iPlayer=0;iPlayer<8;iPlayer++) + { + if(usCursorActive&(1<dx) ex=dx; + ey=ty+6;if(ey>dy) ey=dy; + + for(x=tx,y=sy;y>24) & 0x1) +#define SEMITRANSBIT(x) ((x>>25) & 0x1) +#define PSXRGB(r,g,b) ((g<<10)|(b<<5)|r) + +#define DATAREGISTERMODES unsigned short + +#define DR_NORMAL 0 +#define DR_VRAMTRANSFER 1 + + +#define GPUSTATUS_ODDLINES 0x80000000 +#define GPUSTATUS_DMABITS 0x60000000 // Two bits +#define GPUSTATUS_READYFORCOMMANDS 0x10000000 +#define GPUSTATUS_READYFORVRAM 0x08000000 +#define GPUSTATUS_IDLE 0x04000000 +#define GPUSTATUS_DISPLAYDISABLED 0x00800000 +#define GPUSTATUS_INTERLACED 0x00400000 +#define GPUSTATUS_RGB24 0x00200000 +#define GPUSTATUS_PAL 0x00100000 +#define GPUSTATUS_DOUBLEHEIGHT 0x00080000 +#define GPUSTATUS_WIDTHBITS 0x00070000 // Three bits +#define GPUSTATUS_MASKENABLED 0x00001000 +#define GPUSTATUS_MASKDRAWN 0x00000800 +#define GPUSTATUS_DRAWINGALLOWED 0x00000400 +#define GPUSTATUS_DITHER 0x00000200 + +#define GPUIsBusy (lGPUstatusRet &= ~GPUSTATUS_IDLE) +#define GPUIsIdle (lGPUstatusRet |= GPUSTATUS_IDLE) + +#define GPUIsNotReadyForCommands (lGPUstatusRet &= ~GPUSTATUS_READYFORCOMMANDS) +#define GPUIsReadyForCommands (lGPUstatusRet |= GPUSTATUS_READYFORCOMMANDS) + +///////////////////////////////////////////////////////////////////////////// + +typedef struct VRAMLOADTTAG +{ + short x; + short y; + short Width; + short Height; + short RowsRemaining; + short ColsRemaining; + unsigned short *ImagePtr; +} VRAMLoad_t; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct PSXPOINTTAG +{ + long x; + long y; +} PSXPoint_t; + +typedef struct PSXSPOINTTAG +{ + short x; + short y; +} PSXSPoint_t; + +typedef struct PSXRECTTAG +{ + short x0; + short x1; + short y0; + short y1; +} PSXRect_t; + + +// linux defines for some windows stuff + +#define FALSE 0 +#define TRUE 1 +#define BOOL unsigned short +#define LOWORD(l) ((unsigned short)(l)) +#define HIWORD(l) ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define DWORD unsigned long +#define __int64 long long int + +typedef struct RECTTAG +{ + int left; + int top; + int right; + int bottom; +}RECT; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct TWINTAG +{ + PSXRect_t Position; +} TWin_t; + +///////////////////////////////////////////////////////////////////////////// + +typedef struct PSXDISPLAYTAG +{ + PSXPoint_t DisplayModeNew; + PSXPoint_t DisplayMode; + PSXPoint_t DisplayPosition; + PSXPoint_t DisplayEnd; + + long Double; + long Height; + long PAL; + long InterlacedNew; + long Interlaced; + long RGB24New; + long RGB24; + PSXSPoint_t DrawOffset; + long Disabled; + PSXRect_t Range; + +} PSXDisplay_t; + +///////////////////////////////////////////////////////////////////////////// + +// draw.c + +#ifndef _IN_DRAW + + +extern char * pCaptionText; + +extern int iResX; +extern int iResY; +extern long GlobalTextAddrX,GlobalTextAddrY,GlobalTextTP; +extern long GlobalTextREST,GlobalTextABR,GlobalTextPAGE; +extern short ly0,lx0,ly1,lx1,ly2,lx2,ly3,lx3; +extern long lLowerpart; +extern BOOL bIsFirstFrame; +extern int iWinSize; +extern BOOL bCheckMask; +extern unsigned short sSetMask; +extern unsigned long lSetMask; +extern BOOL bDeviceOK; +extern short g_m1; +extern short g_m2; +extern short g_m3; +extern short DrawSemiTrans; +extern int iUseGammaVal; +extern int iUseScanLines; +extern int iDesktopCol; +extern int iUseNoStretchBlt; +extern int iShowFPS; +extern int iFastFwd; +extern int iDebugMode; +extern int iFVDisplay; +extern PSXPoint_t ptCursorPoint[]; +extern unsigned short usCursorActive; + +#endif + +// prim.c + +#ifndef _IN_PRIMDRAW + +extern BOOL bUsingTWin; +extern TWin_t TWin; +extern unsigned long clutid; +extern void (*primTableJ[256])(unsigned char *); +extern void (*primTableSkip[256])(unsigned char *); +extern unsigned short usMirror; +extern int iDither; +extern unsigned long dwCfgFixes; +extern unsigned long dwActFixes; +extern unsigned long dwEmuFixes; +extern int iUseFixes; +extern int iUseDither; +extern BOOL bDoVSyncUpdate; +extern long drawX; +extern long drawY; +extern long drawW; +extern long drawH; + +#endif + +// gpu.c + +#ifndef _IN_GPU + +extern VRAMLoad_t VRAMWrite; +extern VRAMLoad_t VRAMRead; +extern DATAREGISTERMODES DataWriteMode; +extern DATAREGISTERMODES DataReadMode; +extern int iColDepth; +extern int iWindowMode; +extern char szDispBuf[]; +extern char szMenuBuf[]; +extern char szDebugText[]; +extern short sDispWidths[]; +extern BOOL bDebugText; +//extern unsigned int iMaxDMACommandCounter; +//extern unsigned long dwDMAChainStop; +extern PSXDisplay_t PSXDisplay; +extern PSXDisplay_t PreviousPSXDisplay; +extern BOOL bSkipNextFrame; +extern long lGPUstatusRet; +extern long drawingLines; +extern unsigned char * psxVSecure; +extern unsigned char * psxVub; +extern signed char * psxVsb; +extern unsigned short * psxVuw; +extern signed short * psxVsw; +extern unsigned long * psxVul; +extern signed long * psxVsl; +extern unsigned short * psxVuw_eom; +extern BOOL bChangeWinMode; +extern long lSelectedSlot; +extern DWORD dwLaceCnt; +extern unsigned long lGPUInfoVals[]; +extern unsigned long ulStatusControl[]; +extern int iRumbleVal; +extern int iRumbleTime; + +#endif + +// menu.c + +#ifndef _IN_MENU + +extern unsigned long dwCoreFlags; + +#endif + +// key.c + +#ifndef _IN_KEY + +extern unsigned long ulKeybits; + +#endif + +// fps.c + +#ifndef _IN_FPS + +extern BOOL bInitCap; +extern int UseFrameLimit; +extern int UseFrameSkip; +extern float fFrameRate; +extern int iFrameLimit; +extern float fFrameRateHz; +extern float fps_skip; +extern float fps_cur; +extern BOOL bSSSPSXLimit; + +#endif + +// key.c + +#ifndef _IN_KEY + +#endif + +// cfg.c + +#ifndef _IN_CFG + +extern char * pConfigFile; + +#endif + +// zn.c + +#ifndef _IN_ZN + +#define dwGPUVersion 0 +#define iGPUHeight 512 +#define iGPUHeightMask 511 +#define GlobalTextIL 0 +#define iTileCheat 0 + +#endif + + diff --git a/PeopsSoftGPU/filemap.txt b/PeopsSoftGPU/filemap.txt new file mode 100644 index 0000000..501d63e --- /dev/null +++ b/PeopsSoftGPU/filemap.txt @@ -0,0 +1,61 @@ +######################################################################### + +- gpu.c / gpu.h + plugin interface functions and main dma/register emulation + +- draw.c / draw.h + directdraw/X windows funcs + +- fps.c / fps.h + framerate calculation/limitation + +- fpsewp.c / fpsewp.h + basic fpse plugin interface + +- key.c / key.h + key handling + +- menu.c / menu.h + gpu in-game menu handlers + +- prim.c / prim.h + psx primitives handlers + +- soft.c / soft.h + software rendering funcs + +- cfg.c / cfg.h / conf.c + configuration dialogs/file reading funcs + +- callbacks.c / callbacks.h / interface.c / interface.h / support.c / support.h + additional Glade Linux cfg files + +- record.c / record.h + avi recording funcs (Windows only) + +- i386.asm / macros.inc + nasm files (used on __i386__ define) + +- DrawString.c / DrawString.h / DrawStringFont.h + Linux DGA2 fps display + +- gpuPeopsSoft.* + Windows dll related files (including msvc project files) + +- Makefile + Linux makefile... just do a "make" command to build the plugin + +- stdafx.h + main include file + +- externals.h + generic defines/external vars + +- psemu.h + psemu pro plugin interface definitions + +- resource.h + Windows resource header + +######################################################################### + diff --git a/PeopsSoftGPU/fps.c b/PeopsSoftGPU/fps.c new file mode 100644 index 0000000..01f476f --- /dev/null +++ b/PeopsSoftGPU/fps.c @@ -0,0 +1,482 @@ +/*************************************************************************** + fps.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2007/10/27 - Pete +// - Added Nagisa's changes for SSSPSX as a special gpu config option +// +// 2005/04/15 - Pete +// - Changed user frame limit to floating point value +// +// 2003/07/30 - Pete +// - fixed frame limitation if "old skipping method" is used +// +// 2002/12/14 - Pete +// - improved skipping and added some skipping security code +// +// 2002/11/24 - Pete +// - added new frameskip func +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_FPS + +#include "externals.h" +#include "fps.h" +#include "gpu.h" + +#include "../Gamecube/DEBUG.h" + +//////////////////////////////////////////////////////////////////////// +// FPS stuff +//////////////////////////////////////////////////////////////////////// + +#include + +float fFrameRateHz=0; +DWORD dwFrameRateTicks=16; +float fFrameRate; +int iFrameLimit; +int UseFrameLimit=0; +int UseFrameSkip=0; +BOOL bSSSPSXLimit=FALSE; + +//////////////////////////////////////////////////////////////////////// +// FPS skipping / limit +//////////////////////////////////////////////////////////////////////// + +BOOL bInitCap = TRUE; +float fps_skip = 0; +float fps_cur = 0; + +//////////////////////////////////////////////////////////////////////// + +#define MAXLACE 16 + +void CheckFrameRate(void) +{ +#ifdef PROFILE + start_section(IDLE_SECTION); +#endif + if(UseFrameSkip) // skipping mode? + { + if(!(dwActFixes&0x80)) // not old skipping mode? + { + dwLaceCnt++; // -> store cnt of vsync between frames + if(dwLaceCnt>=MAXLACE && UseFrameLimit) // -> if there are many laces without screen toggling, + { // do std frame limitation + if(dwLaceCnt==MAXLACE) bInitCap=TRUE; + + if(bSSSPSXLimit) FrameCapSSSPSX(); + else FrameCap(); + } + } + else + if(UseFrameLimit) + { + if(bSSSPSXLimit) FrameCapSSSPSX(); + else FrameCap(); + } + calcfps(); // -> calc fps display in skipping mode + } + else // non-skipping mode: + { + if(UseFrameLimit) FrameCap(); // -> do it + if(ulKeybits&KEY_SHOWFPS) calcfps(); // -> and calc fps display + } +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif +} + +//////////////////////////////////////////////////////////////////////// + +#define TIMEBASE 100000 + +// prototypes + long long gettime(void); + unsigned int diff_usec(long long start,long long end); + +unsigned long timeGetTime() +{ + long long nowTick = gettime(); + return diff_usec(0,nowTick)/10; +} + +void FrameCap (void) +{ + static unsigned long curticks, lastticks, _ticks_since_last_update; + static unsigned long TicksToWait = 0; + + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + + if((_ticks_since_last_update > TicksToWait) || + (curticks dwFrameRateTicks) + TicksToWait=0; + else TicksToWait=dwFrameRateTicks-(_ticks_since_last_update-TicksToWait); +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: No Wait; dwFrameRateTicks %i; TicksToWait %i",(int)dwFrameRateTicks, (int)TicksToWait); +// DEBUG_print(txtbuffer,DBG_GPU2); +#endif //SHOW_DEBUG + } + else + { +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: Wait; dwFRTicks %i; TicksWait %i; TicksSince %i",(int)dwFrameRateTicks, (int)TicksToWait, (int)_ticks_since_last_update); +// DEBUG_print(txtbuffer,DBG_GPU3); +#endif //SHOW_DEBUG + BOOL Waiting = TRUE; + while (Waiting) + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + if ((_ticks_since_last_update > TicksToWait) || + (curticks < lastticks)) + { +#ifdef SHOW_DEBUG +// sprintf(txtbuffer, "FrameCap: Done Wait; TicksWait %i; TicksSince %i; cur %i; last %i",(int)TicksToWait, (int)_ticks_since_last_update, (int)curticks, (int)lastticks); +// DEBUG_print(txtbuffer,DBG_GPU3+1); +#endif //SHOW_DEBUG + Waiting = FALSE; + lastticks = curticks; + TicksToWait = dwFrameRateTicks; + } + } + } +} + +void FrameCapSSSPSX(void) // frame limit func SSSPSX +{ + static DWORD reqticks, curticks; + static float offset; + +//--------------------------------------------------------- + if(bInitCap) + { + bInitCap=FALSE; + reqticks = curticks = timeGetTime(); + offset = 0; + return; + } +//--------------------------------------------------------- + offset+=1000/fFrameRateHz; + reqticks+=(DWORD)offset; + offset-=(DWORD)offset; + + curticks = timeGetTime(); + if ((signed int)(reqticks - curticks) > 60) + usleep((reqticks - curticks) * 500L); // pete: a simple Sleep doesn't burn 100% cpu cycles, but it isn't as exact as a brute force loop + + if ((signed int)(curticks - reqticks) > 60) + reqticks += (curticks - reqticks) / 2; +} + +//////////////////////////////////////////////////////////////////////// + +#define MAXSKIP 120 + +void FrameSkip(void) +{ + static int iNumSkips=0; + static DWORD dwLastLace=0; // helper var for frame limitation + + if(!dwLaceCnt) return; // important: if no updatelace happened, we ignore it completely + +#ifdef PROFILE + start_section(IDLE_SECTION); +#endif + + if(iNumSkips) // we are in skipping mode? + { + dwLastLace+=dwLaceCnt; // -> calc frame limit helper (number of laces) + bSkipNextFrame = TRUE; // -> we skip next frame + iNumSkips--; // -> ok, one done + } + else // ok, no additional skipping has to be done... + { // we check now, if some limitation is needed, or a new skipping has to get started + DWORD dwWaitTime; + static DWORD curticks, lastticks, _ticks_since_last_update; + + if(bInitCap || bSkipNextFrame) // first time or we skipped before? + { + static int iAdditionalSkip=0; // number of additional frames to skip + + if(UseFrameLimit && !bInitCap) // frame limit wanted and not first time called? + { + DWORD dwT=_ticks_since_last_update; // -> that's the time of the last drawn frame + dwLastLace+=dwLaceCnt; // -> and that's the number of updatelace since the start of the last drawn frame + + curticks = timeGetTime(); // -> now we calc the time of the last drawn frame + the time we spent skipping + _ticks_since_last_update= dwT+curticks - lastticks; + + dwWaitTime=dwLastLace*dwFrameRateTicks; // -> and now we calc the time the real psx would have needed + + if(_ticks_since_last_update we were too fast? + { + if((dwWaitTime-_ticks_since_last_update)> // -> some more security, to prevent + (60*dwFrameRateTicks)) // wrong waiting times + _ticks_since_last_update=dwWaitTime; + + while(_ticks_since_last_update loop until we have reached the real psx time + { // (that's the additional limitation, yup) + curticks = timeGetTime(); + _ticks_since_last_update = dwT+curticks - lastticks; + } + } + else // we were still too slow ?!!? + { + if(iAdditionalSkip well, somewhen we really have to stop skipping on very slow systems + { + iAdditionalSkip++; // -> inc our watchdog var + dwLaceCnt=0; // -> reset lace count + lastticks = timeGetTime(); +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif + return; // -> done, we will skip next frame to get more speed + } + } + } + + bInitCap=FALSE; // -> ok, we have inited the frameskip func + iAdditionalSkip=0; // -> init additional skip + bSkipNextFrame=FALSE; // -> we don't skip the next frame + lastticks = timeGetTime(); // -> we store the start time of the next frame + dwLaceCnt=0; // -> and we start to count the laces + dwLastLace=0; + _ticks_since_last_update=0; +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif + return; // -> done, the next frame will get drawn + } + + bSkipNextFrame=FALSE; // init the frame skip signal to 'no skipping' first + + curticks = timeGetTime(); // get the current time (we are now at the end of one drawn frame) + _ticks_since_last_update = curticks - lastticks; + + dwLastLace=dwLaceCnt; // store curr count (frame limitation helper) + dwWaitTime=dwLaceCnt*dwFrameRateTicks; // calc the 'real psx lace time' + + if(_ticks_since_last_update>dwWaitTime) // hey, we needed way too long for that frame... + { + if(UseFrameLimit) // if limitation, we skip just next frame, + { // and decide after, if we need to do more + iNumSkips=0; + } + else + { + iNumSkips=_ticks_since_last_update/dwWaitTime; // -> calc number of frames to skip to catch up + iNumSkips--; // -> since we already skip next frame, one down + if(iNumSkips>MAXSKIP) iNumSkips=MAXSKIP; // -> well, somewhere we have to draw a line + } + bSkipNextFrame = TRUE; // -> signal for skipping the next frame + } + else // we were faster than real psx? fine :) + if(UseFrameLimit) // frame limit used? so we wait til the 'real psx time' has been reached + { + if(dwLaceCnt>MAXLACE) // -> security check + _ticks_since_last_update=dwWaitTime; + + while(_ticks_since_last_update just do a waiting loop... + { + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + } + } + + lastticks = timeGetTime(); // ok, start time of the next frame + } + + dwLaceCnt=0; // init lace counter +#ifdef PROFILE + end_section(IDLE_SECTION); +#endif +} + +//////////////////////////////////////////////////////////////////////// + +void calcfps(void) +{ + static unsigned long _ticks_since_last_update; + static unsigned long fps_cnt = 0; + static unsigned long fps_tck = 1; + { + static unsigned long lastticks; + static unsigned long curticks; + + curticks= timeGetTime(); + _ticks_since_last_update=curticks-lastticks; + + if(UseFrameSkip && !UseFrameLimit && _ticks_since_last_update) + fps_skip=min(fps_skip,((float)TIMEBASE/(float)_ticks_since_last_update+1.0f)); + + lastticks = curticks; + } + + if(UseFrameSkip && UseFrameLimit) + { + static unsigned long fpsskip_cnt = 0; + static unsigned long fpsskip_tck = 1; + + fpsskip_tck += _ticks_since_last_update; + + if(++fpsskip_cnt==2) + { + fps_skip = (float)2000/(float)fpsskip_tck; + fps_skip +=6.0f; + fpsskip_cnt = 0; + fpsskip_tck = 1; + } + } + + fps_tck += _ticks_since_last_update; + + if(++fps_cnt==10) + { + fps_cur = (float)(TIMEBASE*10)/(float)fps_tck; + + fps_cnt = 0; + fps_tck = 1; + + if(UseFrameLimit && fps_cur>fFrameRateHz) // optical adjust ;) avoids flickering fps display + fps_cur=fFrameRateHz; + } + +} + +void PCFrameCap (void) +{ + static unsigned long lastticks; + static unsigned long TicksToWait = 0; + BOOL Waiting = TRUE; + + while (Waiting) + { + static unsigned long curticks, _ticks_since_last_update; + curticks = timeGetTime(); + _ticks_since_last_update = curticks - lastticks; + if ((_ticks_since_last_update > TicksToWait) || + (curticks < lastticks)) + { + Waiting = FALSE; + lastticks = curticks; + TicksToWait = (TIMEBASE/ (unsigned long)fFrameRateHz); + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void PCcalcfps(void) +{ + static unsigned long curticks,_ticks_since_last_update,lastticks; + static long fps_cnt = 0; + static float fps_acc = 0; + float CurrentFPS=0; + + curticks = timeGetTime(); + _ticks_since_last_update=curticks-lastticks; + if(_ticks_since_last_update) + CurrentFPS=(float)TIMEBASE/(float)_ticks_since_last_update; + else CurrentFPS = 0; + lastticks = curticks; + + fps_acc += CurrentFPS; + + if(++fps_cnt==10) + { + fps_cur = fps_acc / 10; + fps_acc = 0; + fps_cnt = 0; + } + + fps_skip=CurrentFPS+1.0f; +} + +//////////////////////////////////////////////////////////////////////// + +void SetAutoFrameCap(void) +{ + if(iFrameLimit==1) + { + fFrameRateHz = fFrameRate; + dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); + return; + } + + if(dwActFixes&32) + { + if (PSXDisplay.Interlaced) + fFrameRateHz = PSXDisplay.PAL?50.0f:60.0f; + else fFrameRateHz = PSXDisplay.PAL?25.0f:30.0f; + } + else + { + //fFrameRateHz = PSXDisplay.PAL?50.0f:59.94f; + if(PSXDisplay.PAL) + { + if (lGPUstatusRet&GPUSTATUS_INTERLACED) + fFrameRateHz=33868800.0f/677343.75f; // 50.00238 + else fFrameRateHz=33868800.0f/680595.00f; // 49.76351 + } + else + { + if (lGPUstatusRet&GPUSTATUS_INTERLACED) + fFrameRateHz=33868800.0f/565031.25f; // 59.94146 + else fFrameRateHz=33868800.0f/566107.50f; // 59.82750 + } +// dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); + dwFrameRateTicks=(unsigned long) (TIMEBASE / fFrameRateHz); + } +} + +//////////////////////////////////////////////////////////////////////// + +void SetFPSHandler(void) +{ +} + +//////////////////////////////////////////////////////////////////////// + +void InitFPS(void) +{ + if(!fFrameRate) fFrameRate=200.0f; + + if(fFrameRateHz==0) + { + if(iFrameLimit==2) fFrameRateHz=59.94f; // auto framerate? set some init val (no pal/ntsc known yet) + else fFrameRateHz=fFrameRate; // else set user framerate + } + + dwFrameRateTicks=(TIMEBASE / (unsigned long)fFrameRateHz); +} + diff --git a/PeopsSoftGPU/fps.h b/PeopsSoftGPU/fps.h new file mode 100644 index 0000000..9e35a75 --- /dev/null +++ b/PeopsSoftGPU/fps.h @@ -0,0 +1,41 @@ +/*************************************************************************** + fps.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _FPS_INTERNALS_H +#define _FPS_INTERNALS_H + +void FrameCap(void); +void FrameCapSSSPSX (void); +void FrameSkip(void); +void calcfps(void); +void PCFrameCap (void); +void PCcalcfps(void); +void SetAutoFrameCap(void); +void SetFPSHandler(void); +void InitFPS(void); +void CheckFrameRate(void); + +#endif // _FPS_INTERNALS_H diff --git a/PeopsSoftGPU/gpu.c b/PeopsSoftGPU/gpu.c new file mode 100644 index 0000000..3440118 --- /dev/null +++ b/PeopsSoftGPU/gpu.c @@ -0,0 +1,1924 @@ +/*************************************************************************** + gpu.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2008/05/17 - Pete +// - added GPUvisualVibration and "visual rumble" stuff +// +// 2008/02/03 - Pete +// - added GPUsetframelimit and GPUsetfix ("fake gpu busy states") +// +// 2007/11/03 - Pete +// - new way to create save state picture (Vista) +// +// 2004/01/31 - Pete +// - added zn bits +// +// 2003/01/04 - Pete +// - the odd/even bit hack (CronoCross status screen) is now a special game fix +// +// 2003/01/04 - Pete +// - fixed wrapped y display position offset - Legend of Legaia +// +// 2002/11/24 - Pete +// - added new frameskip func support +// +// 2002/11/02 - Farfetch'd & Pete +// - changed the y display pos handling +// +// 2002/10/03 - Farfetch'd & Pete +// - added all kind of tiny stuff (gpureset, gpugetinfo, dmachain align, polylines...) +// +// 2002/10/03 - Pete +// - fixed gpuwritedatamem & now doing every data processing with it +// +// 2002/08/31 - Pete +// - delayed odd/even toggle for FF8 intro scanlines +// +// 2002/08/03 - Pete +// - "Sprite 1" command count added +// +// 2002/08/03 - Pete +// - handles "screen disable" correctly +// +// 2002/07/28 - Pete +// - changed dmachain handler (monkey hero) +// +// 2002/06/15 - Pete +// - removed dmachain fixes, added dma endless loop detection instead +// +// 2002/05/31 - Lewpy +// - Win95/NT "disable screensaver" fix +// +// 2002/05/30 - Pete +// - dmawrite/read wrap around +// +// 2002/05/15 - Pete +// - Added dmachain "0" check game fix +// +// 2002/04/20 - linuzappz +// - added iFastFwd stuff +// +// 2002/02/18 - linuzappz +// - Added DGA2 support to PIC stuff +// +// 2002/02/10 - Pete +// - Added dmacheck for The Mummy and T'ai Fu +// +// 2002/01/13 - linuzappz +// - Added timing in the GPUdisplayText func +// +// 2002/01/06 - lu +// - Added some #ifdef for the linux configurator +// +// 2002/01/05 - Pete +// - fixed unwanted screen clearing on horizontal centering (causing +// flickering in linux version) +// +// 2001/12/10 - Pete +// - fix for Grandia in ChangeDispOffsetsX +// +// 2001/12/05 - syo (syo68k@geocities.co.jp) +// - added disable screen saver for "stop screen saver" option +// +// 2001/11/20 - linuzappz +// - added Soft and About DlgProc calls in GPUconfigure and +// GPUabout, for linux +// +// 2001/11/09 - Darko Matesic +// - added recording frame in updateLace and stop recording +// in GPUclose (if it is still recording) +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + + +#include "stdafx.h" + +#include "../Gamecube/DEBUG.h" +#include "../Gamecube/wiiSXconfig.h" + +#define _IN_GPU + +#include "externals.h" +#include "gpu.h" +#include "draw.h" +#include "cfg.h" +#include "prim.h" +#include "psemu.h" +#include "menu.h" +#include "key.h" +#include "fps.h" +#include "swap.h" + +//#define SMALLDEBUG +//#include + + +//////////////////////////////////////////////////////////////////////// +// PPDK developer must change libraryName field and can change revision and build +//////////////////////////////////////////////////////////////////////// + +const unsigned char version = 1; // do not touch - library for PSEmu 1.x +const unsigned char revision = 1; +const unsigned char build = 18; // increase that with each version + + + +static char *libraryName = "P.E.Op.S. SoftGPU Driver"; +static char *libraryInfo = "P.E.Op.S. SoftGPU Driver V1.18\nCoded by Pete Bernert and the P.E.Op.S. team\n"; + +static char *PluginAuthor = "Pete Bernert and the P.E.Op.S. team"; + +//////////////////////////////////////////////////////////////////////// +// memory image of the PSX vram +//////////////////////////////////////////////////////////////////////// + +unsigned char psxVSecure[(iGPUHeight*2)*1024 + (1024*1024)]; +unsigned char *psxVub; +signed char *psxVsb; +unsigned short *psxVuw; +unsigned short *psxVuw_eom; +signed short *psxVsw; +unsigned long *psxVul; +signed long *psxVsl; + +//////////////////////////////////////////////////////////////////////// +// GPU globals +//////////////////////////////////////////////////////////////////////// + +static long lGPUdataRet; +long lGPUstatusRet; +char szDispBuf[64]; +char szMenuBuf[36]; +char szDebugText[512]; +unsigned long ulStatusControl[256]; + +static unsigned long gpuDataM[256]; +static unsigned char gpuCommand = 0; +static long gpuDataC = 0; +static long gpuDataP = 0; + +VRAMLoad_t VRAMWrite; +VRAMLoad_t VRAMRead; +DATAREGISTERMODES DataWriteMode; +DATAREGISTERMODES DataReadMode; + +BOOL bSkipNextFrame = FALSE; +DWORD dwLaceCnt=0; +int iColDepth; +int iWindowMode; +short sDispWidths[8] = {256,320,512,640,368,384,512,640}; +PSXDisplay_t PSXDisplay; +PSXDisplay_t PreviousPSXDisplay; +long lSelectedSlot=0; +BOOL bChangeWinMode=FALSE; +BOOL bDoLazyUpdate=FALSE; +unsigned long lGPUInfoVals[16]; +int iFakePrimBusy=0; +int iRumbleVal=0; +int iRumbleTime=0; + +//////////////////////////////////////////////////////////////////////// +// some misc external display funcs +//////////////////////////////////////////////////////////////////////// + +/* +unsigned long PCADDR; +void CALLBACK GPUdebugSetPC(unsigned long addr) +{ + PCADDR=addr; +} +*/ + +#include +time_t tStart; + +void PEOPS_GPUdisplayText(char * pText) // some debug func +{ + if(!pText) {szDebugText[0]=0;return;} + if(strlen(pText)>511) return; + time(&tStart); + strcpy(szDebugText,pText); +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUdisplayFlags(unsigned long dwFlags) // some info func +{ + dwCoreFlags=dwFlags; + BuildDispMenu(0); +} + +//////////////////////////////////////////////////////////////////////// +// stuff to make this a true PDK module +//////////////////////////////////////////////////////////////////////// + +char * CALLBACK PSEgetLibName(void) +{ + return libraryName; +} + +unsigned long CALLBACK PSEgetLibType(void) +{ + return PSE_LT_GPU; +} + +unsigned long CALLBACK PSEgetLibVersion(void) +{ + return version<<16|revision<<8|build; +} + +char * GPUgetLibInfos(void) +{ + return libraryInfo; +} + +//////////////////////////////////////////////////////////////////////// +// Snapshot func +//////////////////////////////////////////////////////////////////////// + +char * pGetConfigInfos(int iCfg) +{ + char szO[2][4]={"off","on "}; + char szTxt[256]; + char * pB=(char *)malloc(32767); + + if(!pB) return NULL; + *pB=0; + //----------------------------------------------------// + sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build); + strcat(pB,szTxt); + sprintf(szTxt,"Author: %s\r\n\r\n",PluginAuthor); + strcat(pB,szTxt); + //----------------------------------------------------// + if(iCfg && iWindowMode) + sprintf(szTxt,"Resolution/Color:\r\n- %ux%u ",LOWORD(iWinSize),HIWORD(iWinSize)); + else + sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY); + strcat(pB,szTxt); + if(iWindowMode && iCfg) + strcpy(szTxt,"Window mode\r\n"); + else + if(iWindowMode) + sprintf(szTxt,"Window mode - [%d Bit]\r\n",iDesktopCol); + else + sprintf(szTxt,"Fullscreen - [%d Bit]\r\n",iColDepth); + strcat(pB,szTxt); + + sprintf(szTxt,"Stretch mode: %d\r\n",iUseNoStretchBlt); + strcat(pB,szTxt); + sprintf(szTxt,"Dither mode: %d\r\n\r\n",iUseDither); + strcat(pB,szTxt); + //----------------------------------------------------// + sprintf(szTxt,"Framerate:\r\n- FPS limit: %s\r\n",szO[UseFrameLimit]); + strcat(pB,szTxt); + sprintf(szTxt,"- Frame skipping: %s",szO[UseFrameSkip]); + strcat(pB,szTxt); + if(iFastFwd) strcat(pB," (fast forward)"); + strcat(pB,"\r\n"); + if(iFrameLimit==2) + strcpy(szTxt,"- FPS limit: Auto\r\n\r\n"); + else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate); + strcat(pB,szTxt); + //----------------------------------------------------// + strcpy(szTxt,"Misc:\r\n- Scanlines: "); + if(iUseScanLines==0) strcat(szTxt,"disabled"); + else + if(iUseScanLines==1) strcat(szTxt,"standard"); + else + if(iUseScanLines==2) strcat(szTxt,"double blitting"); + strcat(szTxt,"\r\n"); + strcat(pB,szTxt); + sprintf(szTxt,"- Game fixes: %s [%08lx]\r\n",szO[iUseFixes],dwCfgFixes); + strcat(pB,szTxt); + //----------------------------------------------------// + return pB; +} + +void DoTextSnapShot(int iNum) +{ + FILE *txtfile;char szTxt[256];char * pB; + + sprintf(szTxt,"%s/peopssoft%03d.txt",getenv("HOME"),iNum); + + if((txtfile=fopen(szTxt,"wb"))==NULL) + return; + //----------------------------------------------------// + pB=pGetConfigInfos(0); + if(pB) + { + fwrite(pB,strlen(pB),1,txtfile); + free(pB); + } + fclose(txtfile); +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUmakeSnapshot(void) // snapshot of whole vram +{ + FILE *bmpfile; + char filename[256]; + unsigned char header[0x36]; + long size,height; + unsigned char line[1024*3]; + short i,j; + unsigned char empty[2]={0,0}; + unsigned short color; + unsigned long snapshotnr = 0; + + height=iGPUHeight; + + size=height*1024*3+0x38; + + // fill in proper values for BMP + + // hardcoded BMP header + memset(header,0,0x36); + header[0]='B'; + header[1]='M'; + header[2]=size&0xff; + header[3]=(size>>8)&0xff; + header[4]=(size>>16)&0xff; + header[5]=(size>>24)&0xff; + header[0x0a]=0x36; + header[0x0e]=0x28; + header[0x12]=1024%256; + header[0x13]=1024/256; + header[0x16]=height%256; + header[0x17]=height/256; + header[0x1a]=0x01; + header[0x1c]=0x18; + header[0x26]=0x12; + header[0x27]=0x0B; + header[0x2A]=0x12; + header[0x2B]=0x0B; + + // increment snapshot value & try to get filename + do + { + snapshotnr++; + sprintf(filename,"%s/peopssoft%03lu.bmp",getenv("HOME"),snapshotnr); + + bmpfile=fopen(filename,"rb"); + if (bmpfile == NULL) break; + fclose(bmpfile); + } + while(TRUE); + + // try opening new snapshot file + if((bmpfile=fopen(filename,"wb"))==NULL) + return; + + fwrite(header,0x36,1,bmpfile); + for(i=height-1;i>=0;i--) + { + for(j=0;j<1024;j++) + { + color=psxVuw[i*1024+j]; + line[j*3+2]=(color<<3)&0xf1; + line[j*3+1]=(color>>2)&0xf1; + line[j*3+0]=(color>>7)&0xf1; + } + fwrite(line,1024*3,1,bmpfile); + } + fwrite(empty,0x2,1,bmpfile); + fclose(bmpfile); + + DoTextSnapShot(snapshotnr); +} + +//////////////////////////////////////////////////////////////////////// +// INIT, will be called after lib load... well, just do some var init... +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUinit() // GPU INIT +{ + memset(ulStatusControl,0,256*sizeof(unsigned long)); // init save state scontrol field + + szDebugText[0]=0; // init debug text buffer + + //psxVSecure=(unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security + //if(!psxVSecure) return -1; + + //!!! ATTENTION !!! + psxVub=psxVSecure+512*1024; // security offset into double sized psx vram! + + psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM + psxVsw=(signed short *)psxVub; + psxVsl=(signed long *)psxVub; + psxVuw=(unsigned short *)psxVub; + psxVul=(unsigned long *)psxVub; + + psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram + + memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024)); + memset(lGPUInfoVals,0x00,16*sizeof(unsigned long)); + + SetFPSHandler(); + + PSXDisplay.RGB24 = FALSE; // init some stuff + PSXDisplay.Interlaced = FALSE; + PSXDisplay.DrawOffset.x = 0; + PSXDisplay.DrawOffset.y = 0; + PSXDisplay.DisplayMode.x= 320; + PSXDisplay.DisplayMode.y= 240; + PreviousPSXDisplay.DisplayMode.x= 320; + PreviousPSXDisplay.DisplayMode.y= 240; + PSXDisplay.Disabled = FALSE; + PreviousPSXDisplay.Range.x0 =0; + PreviousPSXDisplay.Range.y0 =0; + PSXDisplay.Range.x0=0; + PSXDisplay.Range.x1=0; + PreviousPSXDisplay.DisplayModeNew.y=0; + PSXDisplay.Double=1; + lGPUdataRet=0x400; + + DataWriteMode = DR_NORMAL; + + // Reset transfer values, to prevent mis-transfer of data + memset(&VRAMWrite,0,sizeof(VRAMLoad_t)); + memset(&VRAMRead,0,sizeof(VRAMLoad_t)); + + // device initialised already ! + lGPUstatusRet = 0x14802000; + GPUIsIdle; + GPUIsReadyForCommands; + bDoVSyncUpdate=TRUE; + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Here starts all... +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUopen(unsigned long * disp,char * CapText,char * CfgFile) +{ + unsigned long d; + + pCaptionText=CapText; + +#ifndef _FPSE + pConfigFile=CfgFile; +#endif + + ReadConfig(); // read registry + + iShowFPS=1; //Default config turns this off.. + + InitFPS(); + + bIsFirstFrame = TRUE; // we have to init later + bDoVSyncUpdate = TRUE; + + d=ulInitDisplay(); // setup x + + if(disp) *disp=d; // wanna x pointer? ok + + if(d) return 0; + return -1; +} + +//////////////////////////////////////////////////////////////////////// +// time to leave... +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUclose() +{ + + ReleaseKeyHandler(); // de-subclass window + + CloseDisplay(); // shutdown direct draw + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// I shot the sheriff +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUshutdown() +{ + +// free(psxVSecure); + + return 0; // nothinh to do +} + +//////////////////////////////////////////////////////////////////////// +// Update display (swap buffers) +//////////////////////////////////////////////////////////////////////// + +void updateDisplay(void) // UPDATE DISPLAY +{ + if(PSXDisplay.Disabled) // disable? + { + DoClearFrontBuffer(); // -> clear frontbuffer + return; // -> and bye + } + + if(dwActFixes&32) // pc fps calculation fix + { + if(UseFrameLimit) PCFrameCap(); // -> brake + if(UseFrameSkip || ulKeybits&KEY_SHOWFPS) + PCcalcfps(); + } + + if(ulKeybits&KEY_SHOWFPS) // make fps display buf + { + sprintf(szDispBuf,"FPS %06.2f",fps_cur); + } + + if(iFastFwd) // fastfwd ? + { + static int fpscount; UseFrameSkip=1; + + if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip + if(fpscount%6) // -> skip 6/7 frames + bSkipNextFrame = TRUE; + else bSkipNextFrame = FALSE; + fpscount++; + if(fpscount >= (int)fFrameRateHz) fpscount = 0; + return; + } + + if(UseFrameSkip) // skip ? + { + if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip + if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix + { + if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) // -> skip max one in a row + {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;} + else bSkipNextFrame = FALSE; + } + else FrameSkip(); + } + else // no skip ? + { + DoBufferSwap(); // -> swap + } +} + +//////////////////////////////////////////////////////////////////////// +// roughly emulated screen centering bits... not complete !!! +//////////////////////////////////////////////////////////////////////// + +void ChangeDispOffsetsX(void) // X CENTER +{ + long lx,l; + + if(!PSXDisplay.Range.x1) return; + + l=PreviousPSXDisplay.DisplayMode.x; + + l*=(long)PSXDisplay.Range.x1; + l/=2560;lx=l;l&=0xfffffff8; + + if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for + PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test + + if(lx>=PreviousPSXDisplay.DisplayMode.x) + { + PreviousPSXDisplay.Range.x1= + (short)PreviousPSXDisplay.DisplayMode.x; + PreviousPSXDisplay.Range.x0=0; + } + else + { + PreviousPSXDisplay.Range.x1=(short)l; + + PreviousPSXDisplay.Range.x0= + (PSXDisplay.Range.x0-500)/8; + + if(PreviousPSXDisplay.Range.x0<0) + PreviousPSXDisplay.Range.x0=0; + + if((PreviousPSXDisplay.Range.x0+lx)> + PreviousPSXDisplay.DisplayMode.x) + { + PreviousPSXDisplay.Range.x0= + (short)(PreviousPSXDisplay.DisplayMode.x-lx); + PreviousPSXDisplay.Range.x0+=2; //??? + + PreviousPSXDisplay.Range.x1+=(short)(lx-l); + PreviousPSXDisplay.Range.x1-=2; // makes stretching easier + } + + // some alignment security + PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1; + PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1; + PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1; + PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1; + + DoClearScreenBuffer(); + } + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// + +void ChangeDispOffsetsY(void) // Y CENTER +{ + int iT,iO=PreviousPSXDisplay.Range.y0; + int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y; + +// new + + if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight) + { + int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x; + int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight; + + if(dy1>=dy2) + { + PreviousPSXDisplay.DisplayModeNew.y=-dy2; + } + else + { + PSXDisplay.DisplayPosition.y=0; + PreviousPSXDisplay.DisplayModeNew.y=-dy1; + } + } + else PreviousPSXDisplay.DisplayModeNew.y=0; + +// eon + + if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height + { + PSXDisplay.Height = PSXDisplay.Range.y1 - + PSXDisplay.Range.y0 + + PreviousPSXDisplay.DisplayModeNew.y; + PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double; + } + +// + + if(PSXDisplay.PAL) iT=48; else iT=28; + + if(PSXDisplay.Range.y0>=iT) + { + PreviousPSXDisplay.Range.y0= + (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double); + if(PreviousPSXDisplay.Range.y0<0) + PreviousPSXDisplay.Range.y0=0; + PSXDisplay.DisplayModeNew.y+= + PreviousPSXDisplay.Range.y0; + } + else + PreviousPSXDisplay.Range.y0=0; + + if(iO!=PreviousPSXDisplay.Range.y0) + { + DoClearScreenBuffer(); + } +} + +//////////////////////////////////////////////////////////////////////// +// check if update needed +//////////////////////////////////////////////////////////////////////// + +void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED +{ + if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) && + (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x)) + { + if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) && + (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return; + } + + PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos + + PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y; + PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x; + PreviousPSXDisplay.DisplayMode.x= // previous will hold + min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's + PreviousPSXDisplay.DisplayMode.y= // the size of my + min(512,PSXDisplay.DisplayMode.y); // back buffer surface + PSXDisplay.Interlaced = PSXDisplay.InterlacedNew; + + PSXDisplay.DisplayEnd.x= // calc end of display + PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x; + PSXDisplay.DisplayEnd.y= + PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y; + PreviousPSXDisplay.DisplayEnd.x= + PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x; + PreviousPSXDisplay.DisplayEnd.y= + PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y; + + ChangeDispOffsetsX(); + + if(iFrameLimit==2) SetAutoFrameCap(); // -> set it + + if(UseFrameSkip) updateDisplay(); // stupid stuff when frame skipping enabled +} + +//////////////////////////////////////////////////////////////////////// +// gun cursor func: player=0-7, x=0-511, y=0-255 +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUcursor(int iPlayer,int x,int y) +{ + if(iPlayer<0) return; + if(iPlayer>7) return; + + usCursorActive|=(1<511) x=511; + if(y<0) y=0; + if(y>255) y=255; + + ptCursorPoint[iPlayer].x=x; + ptCursorPoint[iPlayer].y=y; +} + +//////////////////////////////////////////////////////////////////////// +// update lace is called evry VSync +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUupdateLace(void) +{ +#ifdef PEOPS_SDLOG + DEBUG_print("append",DBG_SDGECKOAPPEND); + sprintf(txtbuffer,"Calling GPUupdateLace()\r\n"); + DEBUG_print(txtbuffer,DBG_SDGECKOPRINT); + DEBUG_print("close",DBG_SDGECKOCLOSE); +#endif //PEOPS_SDLOG + if(!(dwActFixes&1)) + lGPUstatusRet^=0x80000000; // odd/even bit + + if(!(dwActFixes&32)) // std fps limitation? + CheckFrameRate(); + + if(PSXDisplay.Interlaced) // interlaced mode? + { + if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0) + { + updateDisplay(); + } + } + else // non-interlaced? + { + if(dwActFixes&64) // lazy screen update fix + { + if(bDoLazyUpdate && !UseFrameSkip) + updateDisplay(); + bDoLazyUpdate=FALSE; + } + else + { + if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn? + updateDisplay(); // -> update display + } + } + + bDoVSyncUpdate=FALSE; // vsync done +} + +//////////////////////////////////////////////////////////////////////// +// process read request from GPU status register +//////////////////////////////////////////////////////////////////////// + +unsigned long PEOPS_GPUreadStatus(void) +{ + if(dwActFixes&1) + { + static int iNumRead=0; // odd/even hack + if((iNumRead++)==2) + { + iNumRead=0; + lGPUstatusRet^=0x80000000; // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older) + } + } + +// if(GetAsyncKeyState(VK_SHIFT)&32768) auxprintf("1 %08x\n",lGPUstatusRet); + + if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff + { + iFakePrimBusy--; + + if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims + { + GPUIsBusy; + GPUIsNotReadyForCommands; + } + else + { + GPUIsIdle; + GPUIsReadyForCommands; + } +// auxprintf("2 %08x\n",lGPUstatusRet); + } + + return lGPUstatusRet; +} + +//////////////////////////////////////////////////////////////////////// +// processes data send to GPU status register +// these are always single packet commands. +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUwriteStatus(unsigned long gdata) +{ + unsigned long lCommand=(gdata>>24)&0xff; + + ulStatusControl[lCommand]=gdata; // store command for freezing + + switch(lCommand) + { + //--------------------------------------------------// + // reset gpu + case 0x00: + memset(lGPUInfoVals,0x00,16*sizeof(unsigned long)); + lGPUstatusRet=0x14802000; + PSXDisplay.Disabled=1; + DataWriteMode=DataReadMode=DR_NORMAL; + PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0; + drawX=drawY=0;drawW=drawH=0; + sSetMask=0;lSetMask=0;bCheckMask=FALSE; + usMirror=0; + GlobalTextAddrX=0;GlobalTextAddrY=0; + GlobalTextTP=0;GlobalTextABR=0; + PSXDisplay.RGB24=FALSE; + PSXDisplay.Interlaced=FALSE; + bUsingTWin = FALSE; + return; + //--------------------------------------------------// + // dis/enable display + case 0x03: + + PreviousPSXDisplay.Disabled = PSXDisplay.Disabled; + PSXDisplay.Disabled = (gdata & 1); + + if(PSXDisplay.Disabled) + lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED; + else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED; + return; + + //--------------------------------------------------// + // setting transfer mode + case 0x04: + gdata &= 0x03; // Only want the lower two bits + + DataWriteMode=DataReadMode=DR_NORMAL; + if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER; + if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER; + lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits + lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data + + return; + //--------------------------------------------------// + // setting display position + case 0x05: + { + PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x; + PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y; + +//////// +/* + PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff); + if (PSXDisplay.DisplayPosition.y & 0x200) + PSXDisplay.DisplayPosition.y |= 0xfffffc00; + if(PSXDisplay.DisplayPosition.y<0) + { + PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double; + PSXDisplay.DisplayPosition.y=0; + } + else PreviousPSXDisplay.DisplayModeNew.y=0; +*/ + +// new + if(iGPUHeight==1024) + { + if(dwGPUVersion==2) + PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff); + else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff); + } + else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff); + + // store the same val in some helper var, we need it on later compares + PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y; + + if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight) + { + int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y; + int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight; + + if(dy1>=dy2) + { + PreviousPSXDisplay.DisplayModeNew.y=-dy2; + } + else + { + PSXDisplay.DisplayPosition.y=0; + PreviousPSXDisplay.DisplayModeNew.y=-dy1; + } + } + else PreviousPSXDisplay.DisplayModeNew.y=0; +// eon + + PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff); + PSXDisplay.DisplayEnd.x= + PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x; + PSXDisplay.DisplayEnd.y= + PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y; + PreviousPSXDisplay.DisplayEnd.x= + PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x; + PreviousPSXDisplay.DisplayEnd.y= + PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y; + + bDoVSyncUpdate=TRUE; + + if (!(PSXDisplay.Interlaced)) // stupid frame skipping option + { + if(UseFrameSkip) updateDisplay(); + if(dwActFixes&64) bDoLazyUpdate=TRUE; + } + }return; + //--------------------------------------------------// + // setting width + case 0x06: + + PSXDisplay.Range.x0=(short)(gdata & 0x7ff); + PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff); + + PSXDisplay.Range.x1-=PSXDisplay.Range.x0; + + ChangeDispOffsetsX(); + + return; + //--------------------------------------------------// + // setting height + case 0x07: + { + + PSXDisplay.Range.y0=(short)(gdata & 0x3ff); + PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff); + + PreviousPSXDisplay.Height = PSXDisplay.Height; + + PSXDisplay.Height = PSXDisplay.Range.y1 - + PSXDisplay.Range.y0 + + PreviousPSXDisplay.DisplayModeNew.y; + + if(PreviousPSXDisplay.Height!=PSXDisplay.Height) + { + PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double; + + ChangeDispOffsetsY(); + + updateDisplayIfChanged(); + } + return; + } + //--------------------------------------------------// + // setting display infos + case 0x08: + + PSXDisplay.DisplayModeNew.x = + sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)]; + + if (gdata&0x04) PSXDisplay.Double=2; + else PSXDisplay.Double=1; + + PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double; + + ChangeDispOffsetsY(); + + PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC + PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor + PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace + + lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits + lGPUstatusRet|= + (((gdata & 0x03) << 17) | + ((gdata & 0x40) << 10)); // Set the width bits + + if(PSXDisplay.InterlacedNew) + { + if(!PSXDisplay.Interlaced) + { + PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x; + PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y; + } + lGPUstatusRet|=GPUSTATUS_INTERLACED; + } + else lGPUstatusRet&=~GPUSTATUS_INTERLACED; + + if (PSXDisplay.PAL) + lGPUstatusRet|=GPUSTATUS_PAL; + else lGPUstatusRet&=~GPUSTATUS_PAL; + + if (PSXDisplay.Double==2) + lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT; + else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT; + + if (PSXDisplay.RGB24New) + lGPUstatusRet|=GPUSTATUS_RGB24; + else lGPUstatusRet&=~GPUSTATUS_RGB24; + + updateDisplayIfChanged(); + + return; + //--------------------------------------------------// + // ask about GPU version and other stuff + case 0x10: + + gdata&=0xff; + + switch(gdata) + { + case 0x02: + lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos + return; + case 0x03: + lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start + return; + case 0x04: + lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end + return; + case 0x05: + case 0x06: + lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset + return; + case 0x07: + if(dwGPUVersion==2) + lGPUdataRet=0x01; + else lGPUdataRet=0x02; // gpu type + return; + case 0x08: + case 0x0F: // some bios addr? + lGPUdataRet=0xBFC03720; + return; + } + return; + //--------------------------------------------------// + } +} + +//////////////////////////////////////////////////////////////////////// +// vram read/write helpers, needed by LEWPY's optimized vram read/write :) +//////////////////////////////////////////////////////////////////////// + +__inline void FinishedVRAMWrite(void) +{ +/* +// NEWX + if(!PSXDisplay.Interlaced && UseFrameSkip) // stupid frame skipping + { + VRAMWrite.Width +=VRAMWrite.x; + VRAMWrite.Height+=VRAMWrite.y; + if(VRAMWrite.x=PSXDisplay.DisplayPosition.x && + VRAMWrite.y=PSXDisplay.DisplayPosition.y) + updateDisplay(); + } +*/ + + // Set register to NORMAL operation + DataWriteMode = DR_NORMAL; + // Reset transfer values, to prevent mis-transfer of data + VRAMWrite.x = 0; + VRAMWrite.y = 0; + VRAMWrite.Width = 0; + VRAMWrite.Height = 0; + VRAMWrite.ColsRemaining = 0; + VRAMWrite.RowsRemaining = 0; +} + +__inline void FinishedVRAMRead(void) +{ + // Set register to NORMAL operation + DataReadMode = DR_NORMAL; + // Reset transfer values, to prevent mis-transfer of data + VRAMRead.x = 0; + VRAMRead.y = 0; + VRAMRead.Width = 0; + VRAMRead.Height = 0; + VRAMRead.ColsRemaining = 0; + VRAMRead.RowsRemaining = 0; + + // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER + lGPUstatusRet&=~GPUSTATUS_READYFORVRAM; +} + +//////////////////////////////////////////////////////////////////////// +// core read from vram +//////////////////////////////////////////////////////////////////////// + +void PEOPS_GPUreadDataMem(unsigned long * pMem, int iSize) +{ + int i; + + if(DataReadMode!=DR_VRAMTRANSFER) return; + + GPUIsBusy; + + // adjust read ptr, if necessary + while(VRAMRead.ImagePtr>=psxVuw_eom) + VRAMRead.ImagePtr-=iGPUHeight*1024; + while(VRAMRead.ImagePtr 0) && (VRAMRead.RowsRemaining > 0)) + { + // lower 16 bit + lGPUdataRet=(unsigned long)GETLE16(VRAMRead.ImagePtr); + + VRAMRead.ImagePtr++; + if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024; + VRAMRead.RowsRemaining --; + + if(VRAMRead.RowsRemaining<=0) + { + VRAMRead.RowsRemaining = VRAMRead.Width; + VRAMRead.ColsRemaining--; + VRAMRead.ImagePtr += 1024 - VRAMRead.Width; + if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024; + } + + // higher 16 bit (always, even if it's an odd width) + lGPUdataRet|=(unsigned long)GETLE16(VRAMRead.ImagePtr)<<16; + PUTLE32(pMem, lGPUdataRet); pMem++; + + if(VRAMRead.ColsRemaining <= 0) + {FinishedVRAMRead();goto ENDREAD;} + + VRAMRead.ImagePtr++; + if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024; + VRAMRead.RowsRemaining--; + if(VRAMRead.RowsRemaining<=0) + { + VRAMRead.RowsRemaining = VRAMRead.Width; + VRAMRead.ColsRemaining--; + VRAMRead.ImagePtr += 1024 - VRAMRead.Width; + if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024; + } + if(VRAMRead.ColsRemaining <= 0) + {FinishedVRAMRead();goto ENDREAD;} + } + else {FinishedVRAMRead();goto ENDREAD;} + } + +ENDREAD: + GPUIsIdle; +} + + +//////////////////////////////////////////////////////////////////////// + +unsigned long PEOPS_GPUreadData(void) +{ + unsigned long l; + PEOPS_GPUreadDataMem(&l,1); + return lGPUdataRet; +} + +//////////////////////////////////////////////////////////////////////// +// processes data send to GPU data register +// extra table entries for fixing polyline troubles +//////////////////////////////////////////////////////////////////////// + +const unsigned char primTableCX[256] = +{ + // 00 + 0,0,3,0,0,0,0,0, + // 08 + 0,0,0,0,0,0,0,0, + // 10 + 0,0,0,0,0,0,0,0, + // 18 + 0,0,0,0,0,0,0,0, + // 20 + 4,4,4,4,7,7,7,7, + // 28 + 5,5,5,5,9,9,9,9, + // 30 + 6,6,6,6,9,9,9,9, + // 38 + 8,8,8,8,12,12,12,12, + // 40 + 3,3,3,3,0,0,0,0, + // 48 +// 5,5,5,5,6,6,6,6, // FLINE + 254,254,254,254,254,254,254,254, + // 50 + 4,4,4,4,0,0,0,0, + // 58 +// 7,7,7,7,9,9,9,9, // GLINE + 255,255,255,255,255,255,255,255, + // 60 + 3,3,3,3,4,4,4,4, + // 68 + 2,2,2,2,3,3,3,3, // 3=SPRITE1??? + // 70 + 2,2,2,2,3,3,3,3, + // 78 + 2,2,2,2,3,3,3,3, + // 80 + 4,0,0,0,0,0,0,0, + // 88 + 0,0,0,0,0,0,0,0, + // 90 + 0,0,0,0,0,0,0,0, + // 98 + 0,0,0,0,0,0,0,0, + // a0 + 3,0,0,0,0,0,0,0, + // a8 + 0,0,0,0,0,0,0,0, + // b0 + 0,0,0,0,0,0,0,0, + // b8 + 0,0,0,0,0,0,0,0, + // c0 + 3,0,0,0,0,0,0,0, + // c8 + 0,0,0,0,0,0,0,0, + // d0 + 0,0,0,0,0,0,0,0, + // d8 + 0,0,0,0,0,0,0,0, + // e0 + 0,1,1,1,1,1,1,0, + // e8 + 0,0,0,0,0,0,0,0, + // f0 + 0,0,0,0,0,0,0,0, + // f8 + 0,0,0,0,0,0,0,0 +}; + +void PEOPS_GPUwriteDataMem(unsigned long * pMem, int iSize) +{ + unsigned char command; + unsigned long gdata=0; + int i=0; + +#ifdef PEOPS_SDLOG + int jj,jjmax; + DEBUG_print("append",DBG_SDGECKOAPPEND); + sprintf(txtbuffer,"Calling GPUwriteDataMem(): mode = %d, *pmem = 0x%8p, iSize = %d\r\n",DataWriteMode,GETLE32(pMem),iSize); + DEBUG_print(txtbuffer,DBG_SDGECKOPRINT); + DEBUG_print("close",DBG_SDGECKOCLOSE); +#endif //PEOPS_SDLOG + + GPUIsBusy; + GPUIsNotReadyForCommands; + +STARTVRAM: + + if(DataWriteMode==DR_VRAMTRANSFER) + { + BOOL bFinished=FALSE; + + // make sure we are in vram + while(VRAMWrite.ImagePtr>=psxVuw_eom) + VRAMWrite.ImagePtr-=iGPUHeight*1024; + while(VRAMWrite.ImagePtr0) + { + while(VRAMWrite.RowsRemaining>0) + { + if(i>=iSize) {goto ENDVRAM;} + i++; + + gdata=GETLE32(pMem); pMem++; + + PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++; + if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024; + VRAMWrite.RowsRemaining --; + + if(VRAMWrite.RowsRemaining <= 0) + { + VRAMWrite.ColsRemaining--; + if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width + { + gdata=(gdata&0xFFFF)|(((unsigned long)GETLE16(VRAMWrite.ImagePtr))<<16); + FinishedVRAMWrite(); + bDoVSyncUpdate=TRUE; + goto ENDVRAM; + } + VRAMWrite.RowsRemaining = VRAMWrite.Width; + VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width; + } + + PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++; + if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024; + VRAMWrite.RowsRemaining --; + } + + VRAMWrite.RowsRemaining = VRAMWrite.Width; + VRAMWrite.ColsRemaining--; + VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width; + bFinished=TRUE; + } + + FinishedVRAMWrite(); + if(bFinished) bDoVSyncUpdate=TRUE; + } + +ENDVRAM: + + if(DataWriteMode==DR_NORMAL) + { + void (* *primFunc)(unsigned char *); + if(bSkipNextFrame) primFunc=primTableSkip; + else primFunc=primTableJ; + + for(;i>24) & 0xff); + +//if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command); + + if(primTableCX[command]) + { + gpuDataC = primTableCX[command]; + gpuCommand = command; + PUTLE32(&gpuDataM[0], gdata); + gpuDataP = 1; + } + else continue; + } + else + { + PUTLE32(&gpuDataM[gpuDataP], gdata); + if(gpuDataC>128) + { + if((gpuDataC==254 && gpuDataP>=3) || + (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1))) + { + if((gdata & 0xF000F000) == 0x50005000) + gpuDataP=gpuDataC-1; + } + } + gpuDataP++; + } + + if(gpuDataP == gpuDataC) + { +#ifdef PEOPS_SDLOG + DEBUG_print("append",DBG_SDGECKOAPPEND); + sprintf(txtbuffer," primeFunc[%d](",gpuCommand); + DEBUG_print(txtbuffer,DBG_SDGECKOPRINT); + jjmax = (gpuDataC>128) ? 6 : gpuDataP; + for(jj = 0; jj 2000000) break; + if(CheckForEndlessLoop(addr)) break; + + short count = baseAddrB[addr+3]; + + unsigned long dmaMem=addr+4; + + if(count>0) PEOPS_GPUwriteDataMem(&baseAddrL[dmaMem>>2],count); + + addr = GETLE32(&baseAddrL[addr>>2])&0xffffff; + } + while (addr != 0xffffff); + + GPUIsIdle; + + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// show about dlg +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUabout(void) // ABOUT +{ + +#ifndef _FPSE + AboutDlgProc(); +#endif + return; +} + +//////////////////////////////////////////////////////////////////////// +// We are ever fine ;) +//////////////////////////////////////////////////////////////////////// + +long CALLBACK GPUtest(void) +{ + // if test fails this function should return negative value for error (unable to continue) + // and positive value for warning (can continue but output might be crappy) + return 0; +} + +//////////////////////////////////////////////////////////////////////// +// Freeze +//////////////////////////////////////////////////////////////////////// + +typedef struct GPUFREEZETAG +{ + unsigned long ulFreezeVersion; // should be always 1 for now (set by main emu) + unsigned long ulStatus; // current gpu status + unsigned long ulControl[256]; // latest control register values + //unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN) +} GPUFreeze_t; + +//////////////////////////////////////////////////////////////////////// + +long PEOPS_GPUfreeze(unsigned long ulGetFreezeData,GPUFreeze_t * pF) +{ + //----------------------------------------------------// + if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display) + { + long lSlotNum=*((long *)pF); + if(lSlotNum<0) return 0; + if(lSlotNum>8) return 0; + lSelectedSlot=lSlotNum+1; + BuildDispMenu(0); + return 1; + } + //----------------------------------------------------// + if(!pF) return 0; // some checks + if(pF->ulFreezeVersion!=1) return 0; + + if(ulGetFreezeData==1) // 1: get data (Save State) + { + pF->ulStatus=lGPUstatusRet; + memcpy(pF->ulControl,ulStatusControl,256*sizeof(unsigned long)); + //memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2); //done in Misc.c + + return 1; + } + + if(ulGetFreezeData!=0) return 0; // 0: set data (Load State) + + lGPUstatusRet=pF->ulStatus; + memcpy(ulStatusControl,pF->ulControl,256*sizeof(unsigned long)); + //memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2); //done in Misc.c + +// RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT + + PEOPS_GPUwriteStatus(ulStatusControl[0]); + PEOPS_GPUwriteStatus(ulStatusControl[1]); + PEOPS_GPUwriteStatus(ulStatusControl[2]); + PEOPS_GPUwriteStatus(ulStatusControl[3]); + PEOPS_GPUwriteStatus(ulStatusControl[8]); // try to repair things + PEOPS_GPUwriteStatus(ulStatusControl[6]); + PEOPS_GPUwriteStatus(ulStatusControl[7]); + PEOPS_GPUwriteStatus(ulStatusControl[5]); + PEOPS_GPUwriteStatus(ulStatusControl[4]); + + return 1; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// SAVE STATE DISPLAY STUFF +//////////////////////////////////////////////////////////////////////// + +// font 0-9, 24x20 pixels, 1 byte = 4 dots +// 00 = black +// 01 = white +// 10 = red +// 11 = transparent + +unsigned char cFont[10][120]= +{ +// 0 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 1 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 2 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 3 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 4 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x14,0x00,0x00, + 0x80,0x00,0x14,0x14,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 5 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 6 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x15,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 7 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 8 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 9 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x15,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +} +}; + +//////////////////////////////////////////////////////////////////////// + +void PaintPicDot(unsigned char * p,unsigned char c) +{ + + if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black + if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white + if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red + // transparent +} + +//////////////////////////////////////////////////////////////////////// +// the main emu allocs 128x96x3 bytes, and passes a ptr +// to it in pMem... the plugin has to fill it with +// 8-8-8 bit BGR screen data (Win 24 bit BMP format +// without header). +// Beware: the func can be called at any time, +// so you have to use the frontbuffer to get a fully +// rendered picture + +extern char * Xpixels; + +void GPUgetScreenPic(unsigned char * pMem) +{ + //Unsupported +} + +//////////////////////////////////////////////////////////////////////// +// func will be called with 128x96x3 BGR data. +// the plugin has to store the data and display +// it in the upper right corner. +// If the func is called with a NULL ptr, you can +// release your picture data and stop displaying +// the screen pic + +void CALLBACK GPUshowScreenPic(unsigned char * pMem) +{ + DestroyPic(); // destroy old pic data + if(pMem==0) return; // done + CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUsetfix(unsigned long dwFixBits) +{ + dwEmuFixes=dwFixBits; +} + +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUsetframelimit(unsigned long option) +{ + bInitCap = TRUE; + +if (frameLimit == FRAMELIMIT_AUTO) + { + UseFrameLimit=1; + iFrameLimit=2; + SetAutoFrameCap(); + } + else + { + UseFrameLimit=0; + iFrameLimit=0; + } + UseFrameSkip = frameSkip; + BuildDispMenu(0); +} diff --git a/PeopsSoftGPU/gpu.h b/PeopsSoftGPU/gpu.h new file mode 100644 index 0000000..030c64e --- /dev/null +++ b/PeopsSoftGPU/gpu.h @@ -0,0 +1,72 @@ +/*************************************************************************** + gpu.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_INTERNALS_H +#define _GPU_INTERNALS_H + +///////////////////////////////////////////////////////////////////////////// + +#define OPAQUEON 10 +#define OPAQUEOFF 11 + +#define KEY_RESETTEXSTORE 1 +#define KEY_SHOWFPS 2 +#define KEY_RESETOPAQUE 4 +#define KEY_RESETDITHER 8 +#define KEY_RESETFILTER 16 +#define KEY_RESETADVBLEND 32 +//#define KEY_BLACKWHITE 64 +#define KEY_BADTEXTURES 128 +#define KEY_CHECKTHISOUT 256 + +#ifndef _BIG_ENDIAN +#ifndef _FPSE +#define RED(x) (x & 0xff) +#define BLUE(x) ((x>>16) & 0xff) +#define GREEN(x) ((x>>8) & 0xff) +#define COLOR(x) (x & 0xffffff) +#else +#define BLUE(x) (x & 0xff) +#define RED(x) ((x>>16) & 0xff) +#define GREEN(x) ((x>>8) & 0xff) +#define COLOR(x) (x & 0xffffff) +#endif +#else //!_BIG_ENDIAN +#define RED(x) ((x>>24) & 0xff) +#define BLUE(x) ((x>>8) & 0xff) +#define GREEN(x) ((x>>16) & 0xff) +#define COLOR(x) SWAP32(x & 0xffffff) +#endif //_BIG_ENDIAN + +///////////////////////////////////////////////////////////////////////////// + +void updateDisplay(void); +void SetAutoFrameCap(void); +void SetFixes(void); + +///////////////////////////////////////////////////////////////////////////// + +#endif // _GPU_INTERNALS_H diff --git a/PeopsSoftGPU/gpuPeopsSoft.aps b/PeopsSoftGPU/gpuPeopsSoft.aps new file mode 100644 index 0000000..8028fb9 Binary files /dev/null and b/PeopsSoftGPU/gpuPeopsSoft.aps differ diff --git a/PeopsSoftGPU/gpuPeopsSoft.dsp b/PeopsSoftGPU/gpuPeopsSoft.dsp new file mode 100644 index 0000000..24ce5fa --- /dev/null +++ b/PeopsSoftGPU/gpuPeopsSoft.dsp @@ -0,0 +1,352 @@ +# Microsoft Developer Studio Project File - Name="gpuPeopsSoft" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=gpuPeopsSoft - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "gpuPeopsSoft.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "gpuPeopsSoft.mak" CFG="gpuPeopsSoft - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "gpuPeopsSoft - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "gpuPeopsSoft - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=xicl6.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /G5 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "__i386__" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "NDEBUG" +# ADD RSC /l 0x407 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 user32.lib gdi32.lib ddraw.lib winmm.lib advapi32.lib vfw32.lib d3dx.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Special Build Tool +SOURCE="$(InputPath)" +PostBuild_Cmds=copy release\gpuPeopsSoft.dll d:\emus\epsxe\plugins rem copy release\gpuPeopsSoft.dll d:\emus\zinc\renderer.znc +# End Special Build Tool + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x407 /d "_DEBUG" +# ADD RSC /l 0x407 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=xilink6.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 user32.lib gdi32.lib ddraw.lib dxguid.lib d3dim.lib winmm.lib advapi32.lib vfw32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "gpuPeopsSoft - Win32 Release" +# Name "gpuPeopsSoft - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\cfg.c +# End Source File +# Begin Source File + +SOURCE=.\draw.c +# End Source File +# Begin Source File + +SOURCE=.\fps.c +# End Source File +# Begin Source File + +SOURCE=.\fpsewp.c +# End Source File +# Begin Source File + +SOURCE=.\gpu.c +# End Source File +# Begin Source File + +SOURCE=.\gpuPeopsSoft.c +# End Source File +# Begin Source File + +SOURCE=.\gpuPeopsSoft.def +# End Source File +# Begin Source File + +SOURCE=.\hq2x16.asm + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=.\hq2x16.asm +InputName=hq2x16 + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(MSVCDIR)\bin\nasmw.exe -O9999 -f win32 -D__WIN32__ -D__i386__ hq2x16.asm -o "$(OutDir)"\hq2x16.obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\hq2x32.asm + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=.\hq2x32.asm +InputName=hq2x32 + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(MSVCDIR)\bin\nasmw.exe -O9999 -f win32 -D__WIN32__ -D__i386__ hq2x32.asm -o "$(OutDir)"\hq2x32.obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\hq3x16.asm + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=.\hq3x16.asm +InputName=hq3x16 + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(MSVCDIR)\bin\nasmw.exe -O9999 -f win32 -D__WIN32__ -D__i386__ hq3x16.asm -o "$(OutDir)"\hq3x16.obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\hq3x32.asm + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=.\hq3x32.asm +InputName=hq3x32 + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(MSVCDIR)\bin\nasmw.exe -O9999 -f win32 -D__WIN32__ -D__i386__ hq3x32.asm -o "$(OutDir)"\hq3x32.obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\i386.asm + +!IF "$(CFG)" == "gpuPeopsSoft - Win32 Release" + +# Begin Custom Build +OutDir=.\Release +InputPath=.\i386.asm +InputName=i386 + +"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(MSVCDIR)\bin\nasmw.exe -f win32 -D__WIN32__ -D__i386__ $(InputPath) -o $(OutDir)\$(InputName).obj + +# End Custom Build + +!ELSEIF "$(CFG)" == "gpuPeopsSoft - Win32 Debug" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\key.c +# End Source File +# Begin Source File + +SOURCE=.\menu.c +# End Source File +# Begin Source File + +SOURCE=.\prim.c +# End Source File +# Begin Source File + +SOURCE=.\record.c +# End Source File +# Begin Source File + +SOURCE=.\soft.c +# End Source File +# Begin Source File + +SOURCE=.\zn.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\cfg.h +# End Source File +# Begin Source File + +SOURCE=.\draw.h +# End Source File +# Begin Source File + +SOURCE=.\externals.h +# End Source File +# Begin Source File + +SOURCE=.\fps.h +# End Source File +# Begin Source File + +SOURCE=.\fpsewp.h +# End Source File +# Begin Source File + +SOURCE=.\gpu.h +# End Source File +# Begin Source File + +SOURCE=.\key.h +# End Source File +# Begin Source File + +SOURCE=.\macros.inc +# End Source File +# Begin Source File + +SOURCE=.\menu.h +# End Source File +# Begin Source File + +SOURCE=.\prim.h +# End Source File +# Begin Source File + +SOURCE=.\psemu.h +# End Source File +# Begin Source File + +SOURCE=.\record.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\soft.h +# End Source File +# Begin Source File + +SOURCE=.\stdafx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\res\gpu.bmp +# End Source File +# Begin Source File + +SOURCE=.\gpuPeopsSoft.rc +# End Source File +# Begin Source File + +SOURCE=.\res\gpuPeopsSoft.rc2 +# End Source File +# End Group +# Begin Group "Documentation Files" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\changelog.txt +# End Source File +# Begin Source File + +SOURCE=.\filemap.txt +# End Source File +# Begin Source File + +SOURCE=.\license.txt +# End Source File +# End Group +# End Target +# End Project diff --git a/PeopsSoftGPU/gpuPeopsSoftX.cfg b/PeopsSoftGPU/gpuPeopsSoftX.cfg new file mode 100644 index 0000000..09d621f --- /dev/null +++ b/PeopsSoftGPU/gpuPeopsSoftX.cfg @@ -0,0 +1,27 @@ +# +# Linux config file/Windows ZN config file for the Peops Soft psx gpu plugin +# only certain 15 bit, 16 bit and 32 bit desktop color depths are supported! +# + +[screen] +ResX = 640 # X resolution (def=640) +ResY = 480 # Y resolution (def=480) +NoStretch = 0 # stretching to ResX/Y (0=hw/accel, 1=none,2-9: 2x modes; def=1) +FullScreen = 0 # fullscreen (0/1, def=0), still needs correct ResX/Y +UseDither = 0 # dithering (0-2, def=0) + +[framerate] +ShowFPS = 1 # show fps menu on startup (0/1, def=1) +UseFrameLimit = 1 # fps limitation (0/1, def=0) +UseFrameSkip = 0 # frame skipping (0/1, def=0) +FPSDetection = 2 # rate detection (1:user val,def=2:auto) +FrameRate = 100 # user value for frame rate (1-1000) + +[misc] +ScanLines = 0 # show scanlines (0/1, def=0) + +[fixes] +UseFixes = 0 # use CfgFixes (0/1, def=0) +CfgFixes = 0 # fix bits (0=none,1=odd/even,2=screen width,4=no brightness,8=no coord check,16=unused,32=PC fps,64=lazy screen update,128=old skipping) + + diff --git a/PeopsSoftGPU/gpupeopssoft.c b/PeopsSoftGPU/gpupeopssoft.c new file mode 100644 index 0000000..cfd93e1 --- /dev/null +++ b/PeopsSoftGPU/gpupeopssoft.c @@ -0,0 +1,27 @@ +/*************************************************************************** + gpuPeopsSoft.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup (well... not much in this file) for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" diff --git a/PeopsSoftGPU/gpupeopssoft.def b/PeopsSoftGPU/gpupeopssoft.def new file mode 100644 index 0000000..ec2b079 --- /dev/null +++ b/PeopsSoftGPU/gpupeopssoft.def @@ -0,0 +1,75 @@ +; gpuPeopsSoft.def : Declares the module parameters for the DLL. + +LIBRARY "gpuPeopsSoft" +DESCRIPTION 'gpuPeopsSoft GPU Windows Dynamic Link Library' +EXPORTS + ; Explicit exports can go here + PSEgetLibType @2 + PSEgetLibName @3 + PSEgetLibVersion @4 + GPUinit @5 + GPUshutdown @6 + GPUopen @7 + GPUclose @8 + GPUconfigure @9 + GPUabout @10 + GPUtest @11 + GPUwriteData @12 + GPUwriteStatus @13 + GPUreadData @14 + GPUreadStatus @15 + GPUdmaChain @16 + GPUgetMode @17 + GPUsetMode @18 + GPUupdateLace @19 + GPUmakeSnapshot @20 + GPUwriteDataMem @21 + GPUreadDataMem @22 + GPUdisplayText @23 + GPUdisplayFlags @24 + GPUfreeze @25 + GPUshowScreenPic @26 + GPUgetScreenPic @27 + + GPU_Update @28 + GP1_Read @29 + GP0_Read @30 + GP0_Write @31 + GP1_Write @32 + GPU_Open @33 + GPU_Close @34 + GPU_ScreenShot @35 + GPU_DmaExec @36 + GPU_Configure @37 + GPU_LoadState @38 + GPU_SaveState @39 + GPU_About @40 + + GPUcursor @41 + + ZN_GPUdisplayFlags @42 + ZN_GPUmakeSnapshot @43 + ZN_GPUinit @44 + ZN_GPUopen @45 + ZN_GPUclose @46 + ZN_GPUshutdown @47 + ZN_GPUupdateLace @48 + ZN_GPUreadStatus @49 + ZN_GPUwriteStatus @50 + ZN_GPUdmaSliceOut @51 + ZN_GPUreadData @52 + ZN_GPUsetMode @53 + ZN_GPUgetMode @54 + ZN_GPUdmaSliceIn @55 + ZN_GPUwriteData @56 + ZN_GPUdmaChain @57 + ZN_GPUtest @58 + ZN_GPUfreeze @59 + ZN_GPUgetScreenPic @61 + ZN_GPUshowScreenPic @62 + + GPUsetfix @63 + GPUsetframelimit @64 + GPUvisualVibration @65 + ;GPUdebugSetPC @6x + diff --git a/PeopsSoftGPU/gpupeopssoft.dsw b/PeopsSoftGPU/gpupeopssoft.dsw new file mode 100644 index 0000000..29a8657 --- /dev/null +++ b/PeopsSoftGPU/gpupeopssoft.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "gpuPeopsSoft"=.\gpuPeopsSoft.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/PeopsSoftGPU/gpupeopssoft.ncb b/PeopsSoftGPU/gpupeopssoft.ncb new file mode 100644 index 0000000..5069cbc Binary files /dev/null and b/PeopsSoftGPU/gpupeopssoft.ncb differ diff --git a/PeopsSoftGPU/gpupeopssoft.opt b/PeopsSoftGPU/gpupeopssoft.opt new file mode 100644 index 0000000..69aa76f Binary files /dev/null and b/PeopsSoftGPU/gpupeopssoft.opt differ diff --git a/PeopsSoftGPU/interp.h b/PeopsSoftGPU/interp.h new file mode 100644 index 0000000..21df48a --- /dev/null +++ b/PeopsSoftGPU/interp.h @@ -0,0 +1,294 @@ +/* + * This file is part of the Advance project. + * + * Copyright (C) 2003 Andrea Mazzoleni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * In addition, as a special exception, Andrea Mazzoleni + * gives permission to link the code of this program with + * the MAME library (or with modified versions of MAME that use the + * same license as MAME), and distribute linked combinations including + * the two. You must obey the GNU General Public License in all + * respects for all of the code used other than MAME. If you modify + * this file, you may extend this exception to your version of the + * file, but you are not obligated to do so. If you do not wish to + * do so, delete this exception statement from your version. + */ + +#ifndef __INTERP_H +#define __INTERP_H + +/***************************************************************************/ +/* Basic types */ + +/***************************************************************************/ +/* interpolation */ + +static unsigned interp_mask[2]; +static unsigned interp_bits_per_pixel; + +#define INTERP_16_MASK_1(v) (v & interp_mask[0]) +#define INTERP_16_MASK_2(v) (v & interp_mask[1]) + +static __inline unsigned short interp_16_521(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*2 + INTERP_16_MASK_1(p3)*1) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*2 + INTERP_16_MASK_2(p3)*1) / 8); +} + +static __inline unsigned short interp_16_332(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)*2) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)*2) / 8); +} + +static __inline unsigned short interp_16_611(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*6 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*6 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 8); +} + +static __inline unsigned short interp_16_71(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*7 + INTERP_16_MASK_1(p2)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*7 + INTERP_16_MASK_2(p2)) / 8); +} + +static __inline unsigned short interp_16_211(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*2 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 4) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*2 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 4); +} + +static __inline unsigned short interp_16_772(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1(((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2))*7 + INTERP_16_MASK_1(p3)*2) / 16) + | INTERP_16_MASK_2(((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2))*7 + INTERP_16_MASK_2(p3)*2) / 16); +} + +static __inline unsigned short interp_16_11(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1) + INTERP_16_MASK_1(p2)) / 2) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1) + INTERP_16_MASK_2(p2)) / 2); +} + +static __inline unsigned short interp_16_31(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*3 + INTERP_16_MASK_1(p2)) / 4) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*3 + INTERP_16_MASK_2(p2)) / 4); +} + +static __inline unsigned short interp_16_1411(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*14 + INTERP_16_MASK_1(p2) + INTERP_16_MASK_1(p3)) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*14 + INTERP_16_MASK_2(p2) + INTERP_16_MASK_2(p3)) / 16); +} + +static __inline unsigned short interp_16_431(unsigned short p1, unsigned short p2, unsigned short p3) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*4 + INTERP_16_MASK_1(p2)*3 + INTERP_16_MASK_1(p3)) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*4 + INTERP_16_MASK_2(p2)*3 + INTERP_16_MASK_2(p3)) / 8); +} + +static __inline unsigned short interp_16_53(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*5 + INTERP_16_MASK_1(p2)*3) / 8) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*5 + INTERP_16_MASK_2(p2)*3) / 8); +} + +static __inline unsigned short interp_16_151(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*15 + INTERP_16_MASK_1(p2)) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*15 + INTERP_16_MASK_2(p2)) / 16); +} + +static __inline unsigned short interp_16_97(unsigned short p1, unsigned short p2) +{ + return INTERP_16_MASK_1((INTERP_16_MASK_1(p1)*9 + INTERP_16_MASK_1(p2)*7) / 16) + | INTERP_16_MASK_2((INTERP_16_MASK_2(p1)*9 + INTERP_16_MASK_2(p2)*7) / 16); +} + +#define INTERP_32_MASK_1(v) (v & 0xFF00FF) +#define INTERP_32_MASK_2(v) (v & 0x00FF00) + +static __inline unsigned long interp_32_521(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*2 + INTERP_32_MASK_1(p3)*1) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*2 + INTERP_32_MASK_2(p3)*1) / 8); +} + +static __inline unsigned long interp_32_332(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)*2) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)*2) / 8); +} + +static __inline unsigned long interp_32_211(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*2 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 4) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*2 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 4); +} + +static __inline unsigned long interp_32_611(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*6 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*6 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 8); +} + +static __inline unsigned long interp_32_71(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*7 + INTERP_32_MASK_1(p2)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*7 + INTERP_32_MASK_2(p2)) / 8); +} + +static __inline unsigned long interp_32_772(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1(((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2))*7 + INTERP_32_MASK_1(p3)*2) / 16) + | INTERP_32_MASK_2(((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2))*7 + INTERP_32_MASK_2(p3)*2) / 16); +} + +static __inline unsigned long interp_32_11(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1) + INTERP_32_MASK_1(p2)) / 2) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1) + INTERP_32_MASK_2(p2)) / 2); +} + +static __inline unsigned long interp_32_31(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*3 + INTERP_32_MASK_1(p2)) / 4) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*3 + INTERP_32_MASK_2(p2)) / 4); +} + +static __inline unsigned long interp_32_1411(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*14 + INTERP_32_MASK_1(p2) + INTERP_32_MASK_1(p3)) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*14 + INTERP_32_MASK_2(p2) + INTERP_32_MASK_2(p3)) / 16); +} + +static __inline unsigned long interp_32_431(unsigned long p1, unsigned long p2, unsigned long p3) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*4 + INTERP_32_MASK_1(p2)*3 + INTERP_32_MASK_1(p3)) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*4 + INTERP_32_MASK_2(p2)*3 + INTERP_32_MASK_2(p3)) / 8); +} + +static __inline unsigned long interp_32_53(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*5 + INTERP_32_MASK_1(p2)*3) / 8) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*5 + INTERP_32_MASK_2(p2)*3) / 8); +} + +static __inline unsigned long interp_32_151(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*15 + INTERP_32_MASK_1(p2)) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*15 + INTERP_32_MASK_2(p2)) / 16); +} + +static __inline unsigned long interp_32_97(unsigned long p1, unsigned long p2) +{ + return INTERP_32_MASK_1((INTERP_32_MASK_1(p1)*9 + INTERP_32_MASK_1(p2)*7) / 16) + | INTERP_32_MASK_2((INTERP_32_MASK_2(p1)*9 + INTERP_32_MASK_2(p2)*7) / 16); +} + +/***************************************************************************/ +/* diff */ + +#define INTERP_Y_LIMIT (0x30*4) +#define INTERP_U_LIMIT (0x07*4) +#define INTERP_V_LIMIT (0x06*8) + +static int interp_16_diff(unsigned short p1, unsigned short p2) +{ + int r, g, b; + int y, u, v; + + if (p1 == p2) + return 0; + + if (interp_bits_per_pixel == 16) { + b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; + g = (int)((p1 & 0x7E0) - (p2 & 0x7E0)) >> 3; + r = (int)((p1 & 0xF800) - (p2 & 0xF800)) >> 8; + } else { + b = (int)((p1 & 0x1F) - (p2 & 0x1F)) << 3; + g = (int)((p1 & 0x3E0) - (p2 & 0x3E0)) >> 2; + r = (int)((p1 & 0x7C00) - (p2 & 0x7C00)) >> 7; + } + + y = r + g + b; + u = r - b; + v = -r + 2*g - b; + + if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) + return 1; + + if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) + return 1; + + if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) + return 1; + + return 0; +} + +static int interp_32_diff(unsigned long p1, unsigned long p2) +{ + int r, g, b; + int y, u, v; + + if ((p1 & 0xF8F8F8) == (p2 & 0xF8F8F8)) + return 0; + + b = (int)((p1 & 0xFF) - (p2 & 0xFF)); + g = (int)((p1 & 0xFF00) - (p2 & 0xFF00)) >> 8; + r = (int)((p1 & 0xFF0000) - (p2 & 0xFF0000)) >> 16; + + y = r + g + b; + u = r - b; + v = -r + 2*g - b; + + if (y < -INTERP_Y_LIMIT || y > INTERP_Y_LIMIT) + return 1; + + if (u < -INTERP_U_LIMIT || u > INTERP_U_LIMIT) + return 1; + + if (v < -INTERP_V_LIMIT || v > INTERP_V_LIMIT) + return 1; + + return 0; +} + +static void interp_set(unsigned bits_per_pixel) +{ + interp_bits_per_pixel = bits_per_pixel; + + switch (bits_per_pixel) { + case 15 : + interp_mask[0] = 0x7C1F; + interp_mask[1] = 0x03E0; + break; + case 16 : + interp_mask[0] = 0xF81F; + interp_mask[1] = 0x07E0; + break; + case 32 : + interp_mask[0] = 0xFF00FF; + interp_mask[1] = 0x00FF00; + break; + } +} + +#endif diff --git a/PeopsSoftGPU/key.c b/PeopsSoftGPU/key.c new file mode 100644 index 0000000..3a57aaf --- /dev/null +++ b/PeopsSoftGPU/key.c @@ -0,0 +1,80 @@ +/*************************************************************************** + key.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/04/15 - Pete +// - Changed user frame limit to floating point value +// +// 2002/10/04 - Pete +// - added Full vram view toggle key +// +// 2002/04/20 - linuzappz +// - added iFastFwd key +// +// 2002/02/23 - Pete +// - added toggle capcom fighter game fix +// +// 2001/12/22 - syo +// - added toggle wait VSYNC key handling +// (Pete: added 'V' display in the fps menu) +// +// 2001/12/15 - lu +// - Yet another keyevent handling... +// +// 2001/11/09 - Darko Matesic +// - replaced info key with recording key (sorry Pete) +// (Pete: added new recording key... sorry Darko ;) +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_KEY + +#include "externals.h" +#include "menu.h" +#include "gpu.h" +#include "draw.h" +#include "key.h" + +//////////////////////////////////////////////////////////////////////// + +void GPUmakeSnapshot(void); + +unsigned long ulKeybits=0; + +void GPUkeypressed(int keycode) +{ +} + +//////////////////////////////////////////////////////////////////////// + +void SetKeyHandler(void) +{ +} + +//////////////////////////////////////////////////////////////////////// + +void ReleaseKeyHandler(void) +{ +} diff --git a/PeopsSoftGPU/key.c.bak b/PeopsSoftGPU/key.c.bak new file mode 100644 index 0000000..ec605b0 --- /dev/null +++ b/PeopsSoftGPU/key.c.bak @@ -0,0 +1,302 @@ +/*************************************************************************** + key.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/04/15 - Pete +// - Changed user frame limit to floating point value +// +// 2002/10/04 - Pete +// - added Full vram view toggle key +// +// 2002/04/20 - linuzappz +// - added iFastFwd key +// +// 2002/02/23 - Pete +// - added toggle capcom fighter game fix +// +// 2001/12/22 - syo +// - added toggle wait VSYNC key handling +// (Pete: added 'V' display in the fps menu) +// +// 2001/12/15 - lu +// - Yet another keyevent handling... +// +// 2001/11/09 - Darko Matesic +// - replaced info key with recording key (sorry Pete) +// (Pete: added new recording key... sorry Darko ;) +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_KEY + +#include "externals.h" +#include "menu.h" +#include "gpu.h" +#include "draw.h" +#include "key.h" + +#ifdef _WINDOWS + +#include "record.h" + +//////////////////////////////////////////////////////////////////////// +// KeyBoard handler stuff +//////////////////////////////////////////////////////////////////////// + +WNDPROC wpOrgWndProc=0; +unsigned long ulKeybits=0; +char szGPUKeys[11]; + +//////////////////////////////////////////////////////////////////////// +// keyboard handler +//////////////////////////////////////////////////////////////////////// + +void CALLBACK GPUshowScreenPic(unsigned char * pMem); +void CALLBACK GPUgetScreenPic(unsigned char * pMem); + +LRESULT CALLBACK KeyWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) +{ + switch(message) + { + //--------------------------------------------------// + case WM_ACTIVATE: // some scanline window mode fixing stuff + case WM_MOVE: + { + if(!iUseScanLines) break; + if(!iWindowMode) break; + if(bIsFirstFrame) break; + MoveScanLineArea(hwnd); + }break; + //--------------------------------------------------// + case WM_KEYDOWN: // keydown + if(wParam==(WPARAM)szGPUKeys[2]) ulKeybits|=KEY_RESETTEXSTORE; + break; + //--------------------------------------------------// + case WM_SYSKEYUP: // alt+enter + if(wParam==VK_RETURN) bChangeWinMode=TRUE; + break; + //--------------------------------------------------// + case WM_KEYUP: // key up + + if(iDebugMode && wParam==(WPARAM)szGPUKeys[9]) + iFVDisplay=!iFVDisplay; + + if(wParam==(WPARAM)szGPUKeys[0]) + { + if(ulKeybits&KEY_SHOWFPS) + { + DestroyPic(); + ulKeybits&=~KEY_SHOWFPS; + DoClearScreenBuffer(); + } + else + { + ulKeybits|=KEY_SHOWFPS; + szDispBuf[0]=0; + BuildDispMenu(0); + } + break; + } + if(wParam==(WPARAM)szGPUKeys[1]) {ShowGpuPic();break;} + + if(wParam==(WPARAM)szGPUKeys[6]) + { + if(RECORD_RECORDING==TRUE) + {RECORD_RECORDING=FALSE;RECORD_Stop();} + else + {RECORD_RECORDING=TRUE;RECORD_Start();} + BuildDispMenu(0); + break; + } + + if(wParam==(WPARAM)szGPUKeys[2]) {SwitchDispMenu(-1); break;} + if(wParam==(WPARAM)szGPUKeys[3]) {SwitchDispMenu(1); break;} + if(wParam==(WPARAM)szGPUKeys[4]) {BuildDispMenu(-1); break;} + if(wParam==(WPARAM)szGPUKeys[5]) {BuildDispMenu( 1); break;} + if(wParam==(WPARAM)szGPUKeys[7]) {bVsync_Key = bVsync_Key==TRUE ? FALSE : TRUE; BuildDispMenu(0);break;} + if(wParam==(WPARAM)szGPUKeys[8]) + { + iFastFwd = 1 - iFastFwd; + bSkipNextFrame = FALSE; + UseFrameSkip=iFastFwd; + BuildDispMenu(0); + break; + } + break; + //--------------------------------------------------// + } + return wpOrgWndProc( hwnd, message, wParam, lParam ); +} + +//////////////////////////////////////////////////////////////////////// + +void SetKeyHandler(void) +{ + if(!wpOrgWndProc) // setup keyhandler + { + wpOrgWndProc = (WNDPROC)GetWindowLong(hWGPU, GWL_WNDPROC ); + SetWindowLong(hWGPU, GWL_WNDPROC, (long)KeyWndProc); + } +} + +//////////////////////////////////////////////////////////////////////// + +void ReleaseKeyHandler(void) +{ + if(wpOrgWndProc) + SetWindowLong(hWGPU,GWL_WNDPROC, // set old proc + (long)wpOrgWndProc); + wpOrgWndProc = 0; +} + +#else + +//////////////////////////////////////////////////////////////////////// +// LINUX VERSION +//////////////////////////////////////////////////////////////////////// + +#ifndef _SDL + //X11 +#define VK_INSERT 65379 +#define VK_HOME 65360 +#define VK_PRIOR 65365 +#define VK_NEXT 65366 +#define VK_END 65367 +#define VK_DEL 65535 +#define VK_F5 65474 +#else //SDL +#define VK_INSERT SDLK_INSERT +#define VK_HOME SDLK_HOME +#define VK_PRIOR SDLK_PAGEUP +#define VK_NEXT SDLK_PAGEDOWN +#define VK_END SDLK_END +#define VK_DEL SDLK_DELETE +#define VK_F5 SDLK_F5 +#endif + +//////////////////////////////////////////////////////////////////////// + +void GPUmakeSnapshot(void); + +unsigned long ulKeybits=0; + +void GPUkeypressed(int keycode) +{ +#ifdef _FPSE +char *keystate; + + keystate=SDL_GetKeyState(NULL); + + + if(keystate[SDLK_F5]) + GPUmakeSnapshot(); + + + if(keystate[SDLK_INSERT]) + { + if(iUseFixes) {iUseFixes=0;dwActFixes=0;} + else {iUseFixes=1;dwActFixes=dwCfgFixes;} + SetFixes(); + if(iFrameLimit==2) SetAutoFrameCap(); + } + + if(keystate[SDLK_DELETE]) + { + if(ulKeybits&KEY_SHOWFPS) + { + ulKeybits&=~KEY_SHOWFPS; + DoClearScreenBuffer(); + } + else + { + ulKeybits|=KEY_SHOWFPS; + szDispBuf[0]=0; + BuildDispMenu(0); + } + } + + if(keystate[SDLK_PAGEUP]) BuildDispMenu(-1); + if(keystate[SDLK_PAGEDOWN]) BuildDispMenu( 1); + if(keystate[SDLK_END]) SwitchDispMenu(1); + if(keystate[SDLK_HOME]) SwitchDispMenu(-1); + + +#else + switch(keycode) + { + case VK_F5: + GPUmakeSnapshot(); + break; + + case VK_INSERT: + if(iUseFixes) {iUseFixes=0;dwActFixes=0;} + else {iUseFixes=1;dwActFixes=dwCfgFixes;} + SetFixes(); + if(iFrameLimit==2) SetAutoFrameCap(); + break; + + case VK_DEL: + if(ulKeybits&KEY_SHOWFPS) + { + ulKeybits&=~KEY_SHOWFPS; + DoClearScreenBuffer(); + } + else + { + ulKeybits|=KEY_SHOWFPS; + szDispBuf[0]=0; + BuildDispMenu(0); + } + break; + + case VK_PRIOR: BuildDispMenu(-1); break; + case VK_NEXT: BuildDispMenu( 1); break; + case VK_END: SwitchDispMenu(1); break; + case VK_HOME: SwitchDispMenu(-1); break; + case 0x60: + { + iFastFwd = 1 - iFastFwd; + bSkipNextFrame = FALSE; + UseFrameSkip=iFastFwd; + BuildDispMenu(0); + break; + } + } +#endif +} + +//////////////////////////////////////////////////////////////////////// + +void SetKeyHandler(void) +{ +} + +//////////////////////////////////////////////////////////////////////// + +void ReleaseKeyHandler(void) +{ +} + +#endif diff --git a/PeopsSoftGPU/key.h b/PeopsSoftGPU/key.h new file mode 100644 index 0000000..2798c65 --- /dev/null +++ b/PeopsSoftGPU/key.h @@ -0,0 +1,33 @@ +/*************************************************************************** + key.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _KEY_INTERNALS_H +#define _KEY_INTERNALS_H + +void SetKeyHandler(void); +void ReleaseKeyHandler(void); + +#endif // _KEY_INTERNALS_H diff --git a/PeopsSoftGPU/license.txt b/PeopsSoftGPU/license.txt new file mode 100644 index 0000000..1ecbc8f --- /dev/null +++ b/PeopsSoftGPU/license.txt @@ -0,0 +1,298 @@ +######################################################################### + + Psx Emulation OPen Source SOFT GPU LIBRARY + +The license of this library is GPL, as described below. + +Still I don't want to force any freeware coder to go Open Source +himself, if he is using parts of the soft gpu source in his work. +So, I will allow the usage of the soft gpu funcs in closed source +projects, too, if + + a) the project is freeware + b) credits are given + c) any improvements in the open source funcs are reported back + to the P.E.Op.S project. + +######################################################################### + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/PeopsSoftGPU/linuxdef.h b/PeopsSoftGPU/linuxdef.h new file mode 100644 index 0000000..4ecdd96 --- /dev/null +++ b/PeopsSoftGPU/linuxdef.h @@ -0,0 +1,48 @@ +#ifndef _GNUDEF_H_ +#define _GNUDEF_H_ + +// Type of Plugins returned by *_About functions. +#define FPSE_GPU 1 +#define FPSE_SPU 2 +#define FPSE_JOY0 3 +#define FPSE_JOY1 4 +#define FPSE_CDROM 5 +#define FPSE_PAR 6 + +// Bit masks for Flags field +#define GPU_USE_DIB_UPDATE 0x00000001 +#define GPU_USE_NEW_MDEC 0x00000002 + +// New MDEC from GPU plugin. +typedef struct { + int (*MDEC0_Read)(); + int (*MDEC0_Write)(); + int (*MDEC1_Read)(); + int (*MDEC1_Write)(); + int (*MDEC0_DmaExec)(); + int (*MDEC1_DmaExec)(); +} MDEC_Export; + +// Main Struct for initialization +typedef struct { + UINT8 *SystemRam; // Pointer to the PSX system ram + UINT32 Flags; // Flags to plugins + UINT32 *IrqPulsePtr; // Pointer to interrupt pending reg + MDEC_Export MDecAltern; // Use another MDEC engine + int (*ReadCfg)(); // Read an item from INI + int (*WriteCfg)(); // Write an item to INI + void (*FlushRec)(); // Tell where the RAM is changed +} FPSElinux; + +// Info about a plugin +typedef struct { + UINT8 PlType; // Plugin type: GPU, SPU or Controllers + UINT8 VerLo; // Version High + UINT8 VerHi; // Version Low + UINT8 TestResult; // Returns if it'll work or not + char Author[64]; // Name of the author + char Name[64]; // Name of plugin + char Description[1024]; // Description to put in the edit box +} FPSElinuxAbout; + +#endif diff --git a/PeopsSoftGPU/macros.inc b/PeopsSoftGPU/macros.inc new file mode 100644 index 0000000..4782928 --- /dev/null +++ b/PeopsSoftGPU/macros.inc @@ -0,0 +1,40 @@ +; macros.inc - description +; ------------------- +; begin : Sun Nov 08 2001 +; based on ZSNES macros.mac +; email : linuzappz@pcsx.net + +; This program is free software; you can redistribute it and/or modify * +; it under the terms of the GNU General Public License as published by * +; the Free Software Foundation; either version 2 of the License, or * +; (at your option) any later version. See also the license.txt file for * +; additional informations. * + + +%ifdef __WIN32__ + +%imacro EXTSYM 1-* +%rep %0 + extern _%1 + %define %1 _%1 +%rotate 1 +%endrep +%endmacro + +%imacro NEWSYM 1 + global _%1 + _%1: + %1: +%endmacro + +%else + +%define EXTSYM extern + +%imacro NEWSYM 1 + global %1 + %1: +%endmacro + +%endif + diff --git a/PeopsSoftGPU/makedep b/PeopsSoftGPU/makedep new file mode 100644 index 0000000..de57dbd --- /dev/null +++ b/PeopsSoftGPU/makedep @@ -0,0 +1 @@ +( cat Makefile.nodep && gcc -MM --makedep -I./fpse `gtk-config --cflags` *.c) > Makefile diff --git a/PeopsSoftGPU/makes/plg.mk b/PeopsSoftGPU/makes/plg.mk new file mode 100644 index 0000000..7988545 --- /dev/null +++ b/PeopsSoftGPU/makes/plg.mk @@ -0,0 +1,12 @@ +# +# plugin specific makefile +# + +PLUGIN = libgpuPeops$(VERSION).so +PLUGINTYPE = libgpu.so +CFLAGS = -g -Wall -fPIC -O4 -fomit-frame-pointer -ffast-math $(INCLUDE) +#CFLAGS = -g -Wall -fPIC -O3 -mpentium -fomit-frame-pointer -ffast-math $(INCLUDE) +INCLUDE = -I/usr/local/include +OBJECTS = gpu.o cfg.o draw.o fps.o key.o menu.o prim.o soft.o zn.o +#hq3x32.o hq2x32.o hq3x16.o hq2x16.o +LIBS = diff --git a/PeopsSoftGPU/menu.c b/PeopsSoftGPU/menu.c new file mode 100644 index 0000000..c514c8f --- /dev/null +++ b/PeopsSoftGPU/menu.c @@ -0,0 +1,220 @@ +/*************************************************************************** + menu.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/04/15 - Pete +// - Changed user frame limit to floating point value +// +// 2003/07/27 - Pete +// - Added pad core flags display +// +// 2002/12/14 - Pete +// - Added dithering menu item +// +// 2002/05/25 - Pete +// - Added menu support for linuzappz's fast forward skipping +// +// 2002/01/13 - linuzappz +// - Added timing for the szDebugText (to 2 secs) +// +// 2001/12/22 - syo +// - modified for "transparent menu" +// (Pete: added 'V' display for WaitVBlank) +// +// 2001/11/09 - Darko Matesic +// - added recording status +// (Pete: added terminate zero to the menu buffer ;) +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_MENU + +#include "externals.h" +#include "draw.h" +#include "menu.h" +#include "gpu.h" + +unsigned long dwCoreFlags=0; + +//////////////////////////////////////////////////////////////////////// +// create lists/stuff for fonts (actually there are no more lists, but I am too lazy to change the func names ;) +//////////////////////////////////////////////////////////////////////// + +void InitMenu(void) +{ +} + +//////////////////////////////////////////////////////////////////////// +// kill existing lists/fonts +//////////////////////////////////////////////////////////////////////// + +void CloseMenu(void) +{ + DestroyPic(); +} + +//////////////////////////////////////////////////////////////////////// +// DISPLAY FPS/MENU TEXT +//////////////////////////////////////////////////////////////////////// + +#include +extern time_t tStart; + +int iMPos=0; // menu arrow pos + +void DisplayText(void) // DISPLAY TEXT +{ +} + +//////////////////////////////////////////////////////////////////////// +// Build Menu buffer (== Dispbuffer without FPS)... +//////////////////////////////////////////////////////////////////////// + +void BuildDispMenu(int iInc) +{ + if(!(ulKeybits&KEY_SHOWFPS)) return; // mmm, cheater ;) + + iMPos+=iInc; // up or down + if(iMPos<0) iMPos=3; // wrap around + if(iMPos>3) iMPos=0; + + strcpy(szMenuBuf," FL FS DI GF "); // main menu items + + if(UseFrameLimit) // set marks + { + if(iFrameLimit==1) szMenuBuf[2] = '+'; + else szMenuBuf[2] = '*'; + } + if(iFastFwd) szMenuBuf[7] = '~'; + else + if(UseFrameSkip) szMenuBuf[7] = '*'; + + if(iUseDither) // set marks + { + if(iUseDither==1) szMenuBuf[12] = '+'; + else szMenuBuf[12] = '*'; + } + + if(dwActFixes) szMenuBuf[17] = '*'; + + if(dwCoreFlags&1) szMenuBuf[23] = 'A'; + if(dwCoreFlags&2) szMenuBuf[23] = 'M'; + + if(dwCoreFlags&0xff00) //A/M/G/D + { + if((dwCoreFlags&0x0f00)==0x0000) // D + szMenuBuf[23] = 'D'; + else + if((dwCoreFlags&0x0f00)==0x0100) // A + szMenuBuf[23] = 'A'; + else + if((dwCoreFlags&0x0f00)==0x0200) // M + szMenuBuf[23] = 'M'; + else + if((dwCoreFlags&0x0f00)==0x0300) // G + szMenuBuf[23] = 'G'; + + szMenuBuf[24]='0'+(char)((dwCoreFlags&0xf000)>>12); // number + } + + + if(lSelectedSlot) szMenuBuf[26] = '0'+(char)lSelectedSlot; + + szMenuBuf[(iMPos+1)*5]='<'; // set arrow + +} + +//////////////////////////////////////////////////////////////////////// +// Some menu action... +//////////////////////////////////////////////////////////////////////// + +void SwitchDispMenu(int iStep) // SWITCH DISP MENU +{ + if(!(ulKeybits&KEY_SHOWFPS)) return; // tststs + + switch(iMPos) + {////////////////////////////////////////////////////// + case 0: // frame limit + { + int iType=0; + bInitCap = TRUE; + + if(UseFrameLimit) iType=iFrameLimit; + iType+=iStep; + if(iType<0) iType=2; + if(iType>2) iType=0; + if(iType==0) UseFrameLimit=0; + else + { + UseFrameLimit=1; + iFrameLimit=iType; + SetAutoFrameCap(); + } + } break; + ////////////////////////////////////////////////////// + case 1: // frame skip + bInitCap = TRUE; + if(iStep>0) + { + if(!UseFrameSkip) {UseFrameSkip=1;iFastFwd = 0;} + else + { + if(!iFastFwd) iFastFwd=1; + else {UseFrameSkip=0;iFastFwd = 0;} + } + } + else + { + if(!UseFrameSkip) {UseFrameSkip=1;iFastFwd = 1;} + else + { + if(iFastFwd) iFastFwd=0; + else {UseFrameSkip=0;iFastFwd = 0;} + } + } + bSkipNextFrame=FALSE; + break; + ////////////////////////////////////////////////////// + case 2: // dithering + iUseDither+=iStep; + if(iUseDither<0) iUseDither=2; + if(iUseDither>2) iUseDither=0; + break; + ////////////////////////////////////////////////////// + case 3: // special fixes + if(iUseFixes) {iUseFixes=0;dwActFixes=0;} + else {iUseFixes=1;dwActFixes=dwCfgFixes;} + SetFixes(); + if(iFrameLimit==2) SetAutoFrameCap(); + break; + } + + BuildDispMenu(0); // update info +} + +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + diff --git a/PeopsSoftGPU/menu.h b/PeopsSoftGPU/menu.h new file mode 100644 index 0000000..60bebee --- /dev/null +++ b/PeopsSoftGPU/menu.h @@ -0,0 +1,36 @@ +/*************************************************************************** + menu.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_MENU_H_ +#define _GPU_MENU_H_ + +void DisplayText(void); +void CloseMenu(void); +void InitMenu(void); +void BuildDispMenu(int iInc); +void SwitchDispMenu(int iStep); + +#endif // _GPU_MENU_H_ diff --git a/PeopsSoftGPU/peops_soft_readme_1_18.txt b/PeopsSoftGPU/peops_soft_readme_1_18.txt new file mode 100644 index 0000000..9af0498 --- /dev/null +++ b/PeopsSoftGPU/peops_soft_readme_1_18.txt @@ -0,0 +1,270 @@ +P.E.Op.S. Open Source Soft driver for freeware PSX emus/ZN emus +--------------------------------------------------------------- + +The P.E.Op.S. soft gpu plugin is based on Pete's soft gpus +for Windows and Linux. + +---------------------------------------------------------------------------- + +Requirements: + +Windows: +-------- +Any 2 MB video card which can handle DirectDraw with 16 bit color +depth should work fine... only 16 and 32 bit color depths are +supported, if you are using a 24 bit desktop, switch to a fullscreen +mode because in Window mode you will get funny colors. + +Note: some (older) gfx cards can't handle the 16 bit mode properly +(screwed display), you have to use the 32 bit mode if that's happening. + +Linux: +------ +The X enviroment is needed, and a gfx card which can handle 15, 16 +or 32 bit color depths. Version 1.4 is linked statically with +libXxf86vm.a to change the video mode in fullscreen displays. +If that's causing problems on your system, simply edit the Makefile +and build a version without video mode changing support by running +"make". +Also, there is a special FPSE linux version, which is needing the +SDL libraries. To build that version, use the makefiles in the +"makes" sub-directory. +Don't try to use the SDL version with ePSXe or PCSX! +You can also compile a ePSXe/PCSX Linux DGA2 version of the soft +plugin, just take a look at the makefiles :) + +BeOS: +----- +It's enough to have SDL 1.2.x installed. + +---------------------------------------------------------------------------- + +Installation: + +Windows: copy the file "gpuPeopsSoft.dll" into the main emu +plugins directory. + +Linux: copy the file "libgpuPeopsSoftX.so.1.0.x" or the file +"libgpuPeopsSDL.so" (FPSE SDL version) into the main emu plugins +directory. Copy the file "gpuPeopsSoftX.cfg" into the main +emu "cfg" directory, or into the main emu directory, or into your +home directory. + +Notes for use with ZiNc: +You have to use the "--renderer=..." command line switch to load +the plugin (or rename the plugin DLL to "renderer.znc" and copy it +into the main ZiNc directory). For configuration you can specify +the Peops .cfg with the ZiNc "--use-renderer-cfg-file=..." command +line switch, or (Windows only) simply don't specify a .cfg file, +then automatically the settings in the Windows registry will be used. +Of course that will mean that you will need some Win psx emu to +configure the plugin. + +---------------------------------------------------------------------------- + +Configuration: + +The SoftGPU has not much options... because it doesn't need them :) + +0) Rendering device +-------------------- +If you have more than one gfx card installed (I have for example +a GeForce and Voodoo3 PCI), you can select the card you want to use +with the "Select device" button. +Note: that option is not available in the Linux config file. + +1) Resolution & Colors +----------------------- +Well, that section should be self-explaining. +Please note: some cards (like the 3dfx V2/V3) can't do a 32 bit +color depth, or rendering in a window (V2). Selecting an option +which your card can't handle will cause error message boxes or +crashes or something like that... yup, sorry + +If you want speed (who doesn't): the 16 bit color modes are faster +than the 32 bit ones... and with this SoftGpu you will _not_ get +a better image quality by choosing 32 Bit modes, so I really suggest +to use 16 bit colors. + +Enabling "unstreched display" will show the unstreched psx display +centered inside the window. + +Also available: certain 2xSai/Scale2x modes, which will enhance the +display (mainly in 2D games), at the cost of speed (you will need a +powerful cpu to use them). +Note: 16 bit desktop/fullscreen color modes will be faster with 2xSaI, +so I suggest to not use 32 bit color modes. Big thanx for the 2xSaI +modes goes to Derek Liauw, the available Scale2x modes are copyrighted +by Andrea Mazzoleni (http://scale2x.sourceforge.net). + +Note: in the Linux version you have to take care that you not only +set the fullscreen option, you also have to configure the width/heigth +of the output window in a way that it matches your possible desktop +sizes. + +Another way to enhance the display is to activate dithering. There are +3 dithering modes avaiable: + +- No dithering: + g-shaded polygons will not look very smooth, but it's the fastest mode. +- Game depended: + will activate dithering on g-shaded textures, if the game is turning + on dithering. +- Always: + will dither all g-shaded polygons, all the time. That one usually is + looking best, but it's also the slowest mode. + +You can toggle between the three dither modes with the in-game gpu menu +(see below). + + +2) Framerate limit/Frame skipping +---------------------------------- +You can activate FPS limitation if your game is running to fast. You can +use "Auto detect FPS limit", if you are not sure, what limit would be best +to use. Or you just type in a FPS rate that suits you. PAL games +use 50 FPS, non-PAL games 60 FPS. +And if things are getting too slow... you can try Frame skipping. +Tip for best results on slow systems: turn on both... +You can also enable the in-game menu right from the game start +(it's showing the fps and lets you change some gpu options while +playing). +Of course you still can use the "DEL" key for showing/hiding the menu. +Btw, all gpu hotkeys are described below. If you want to change the +keys, you can use the small "..." button in the Windows version. +"Transparent FPS display" will just draw the fps menu text, without +a filled box around it. + + +3) Special game fixes +------------------------ +Some gfx glitches are caused by the main emu core or because I've +not found out (yet) how certain things are activated on a real +psx gpu. But you can minimize bad effects with certain games by +using the internal gpu patches.... push the "..." button to see +(and activate) the list of available fixes (Windows/Linux) or set +the proper bits directly in the config file (Linux). + + +4) Movie recording (Windows version only) +----------------------------------------- +You can start/stop recording by using the 'recording' hotkey. +A avi file will get created in the \Demo sub-directory. + + +5) Misc +----------- +Windows only: + +"Use system memory" will use your PC main memory as video buffer, not +the Vram of your gfx card. Result: usually much slower, but the (maybe +unwanted) fullscreen filtering on nVidia cards is disabled. + +"Stop screen saver" will disabled screen savers and power management +while running the gpu. A note from syo: W95 and NT4 are not supported +and will likely crash your system. + +"Wait vsync" will force the gpu to sync the buffer swaps with the +vsync of your monitor. That will be slower, but it could fix "smearing" +effects. You can define an hotkey to toggle the "Wait vsync option", +if it's activated, the fps menu will display a "V" character. + +"Debug mode" will enable several debug keys (currently only one is +available, though, toggling the display between the 'normal' screen +and a full vram view). Please note: not all cards will be able to do this mode. + + +Keys +---- + save complete psx vram as a bitmap to the 'Snap' sub directory - + if you want to mail me a snapshot, please ask before doing + it... + ++ switch between window/fullscreen mode (Windows version only, and with most gfx card drivers your desktop color depth need +to be the same as the configured fullscreen color depth) + + start/stop avi file recording (Windows version only) + + show/hide the gpu version (if no FPS is displayed) or an help text (if the FPS menu is displayed, Windows version only) + + show/hide FPS and option menu + + How it works: Hit and the Framerate und the menu will appear. It + looks like: 'FPS XXXX.X FL< FS DI GF A V Rec' + + What does it all mean? Here's the legend: + + FPS: frames per second, higher means better :) + FL : Frame rate limiter + FS : Frame skipping, higher means faster + DI : The three available dithering modes + GF : Game fixes + A/M: Analog pad mode/PSX Mouse mode... that's an information from the emu core, telling you if the pad emulation is doing Mouse mode ('M'), Analog mode ('A') or Digital mode (no 'A' and no 'M') + V : "Wait vsync" is enabled (Windows version only) + Rec: Avi file recording in progress (Windows version only) + + If a '*' character is beneath an option, the option is active, otherwise + inactive. + There is a '<' sign you can move with the or keys + towards an option you want to toggle. + Just hit the / key to switch the selected option on or off. Changes will + be done immediatly, you can see how the framerate is affected if an option + is on or off. + If you are using a manual speed limit, and the in-game menu cursor is set to FL, you + can adjust the manual limit value by hitting + /. + If you have found a setting that suits your game just hide the menu by + pressing again. + I don't store changed options permanently, you have to do that still in the + main configuration dialog. + + +---------------------------------------------------------------------------- + +Some tips: + +- use a 16 bit desktop color depth if you want to play in Window mode + or use a 16 bit fullscreen mode to get higher speed +- activating the frame skipping option may be causing glitches... + turn it off before sending me mails. +- on nVidia cards you will notice blurred (or 'smoothed') screens in + the Windows version. + Well, some people enjoy that, others do not. You can turn off the + auto-smoothing by disabling hardware accelerated DirectDraw. Go + to the DirectX applet in your Windows Control Panel, start it and + select the DirectDraw tab. Here you can turn acceleration off... + the GPU will become slightly slower, though. And don't forget + to re-activate the DD option, else you will have troubles to + start DirectX based PC games. Or simply try the "system memory" + option... + +---------------------------------------------------------------------------- + +For version infos read the "version.txt" file. + +And, peops, have fun! + +Pete Bernert + +---------------------------------------------------------------------------- + +P.E.Op.S. page on sourceforge: https://sourceforge.net/projects/peops/ + +P.E.Op.S. developer: + +Pete Bernert http://www.pbernert.com +Lewpy http://lewpy.psxemu.com/ +lu_zero http://brsk.virtualave.net/lu_zero/ +linuzappz http://www.pcsx.net +Darko Matesic http://mrdario.tripod.com +syo http://www.geocities.co.jp/SiliconValley-Bay/2072/ + +---------------------------------------------------------------------------- + +Disclaimer/Licence: + +This plugin is under GPL... check out the license.txt file in the /src +directory for details. + +---------------------------------------------------------------------------- + + diff --git a/PeopsSoftGPU/peops_soft_version_1_18.txt b/PeopsSoftGPU/peops_soft_version_1_18.txt new file mode 100644 index 0000000..150b203 --- /dev/null +++ b/PeopsSoftGPU/peops_soft_version_1_18.txt @@ -0,0 +1,610 @@ + + +-------------------------------------------------------------------------- +May, 2008 Version 1.18 + +- Pete added Nagisa's frame limit timings (done by Nagisa for SSSPSX). + And the simpler SSSPSX frame limitation mode has been added as a gpu + config option. Advantage: SSSPSX will not show a 100% cpu load in + this mode, but it's slightly less accurate. + +- Pete added MxC's changes to the display filters (from the 'm9' filter + edition of the plugin). + Please note that the HQ2X/HQ3X filters need a cpu with MMX extensions. + Ah, and most of the filters are now available for Linux as well (the + 'stretched HQ3x / Scale3x' Linux modes seem to be a bit unstable, though). + +- Pete added "GPUsetframelimit" function, so the main emu can control + the frame limitation. + +- Pete added a new way to create the save state picture. This will fix + crashes on Windows Vista when doing save states. + +- Pete added a "special game fix" (called "Fake 'gpu busy' states") on + request of the ePSXe team (calb and Galtor). This will prevent lockups + in some games. The main emu can activate this fix automatically by a + new "GPUsetfix" interface function. + +- Pete added a "visual rumble" function to the Windows version of the + soft plugin on request of calb from the ePSXe team. + The main emu can call it to shake the display whenever the PSX pad + vibration kicks in. + + +-------------------------------------------------------------------------- +29. July, 2006 Version 1.17 for SSSPSX + +- Nagisa fixed the problem 100% CPU rate. + +- Nagisa fixed vertical synchronous frequency. + + +-------------------------------------------------------------------------- +12. June, 2005 Version 1.17 + +- MxC added HQ2X, HQ3X and Scale3X display filters to the Windows version. + +The other changes were done by Pete: + +- smf of the MAME team found a new capability of the PSX gpu: sprite Y + mirroring. I've added this to the P.E.Op.S. gpu, big thanx to smf + for sharing this info (and for coding a small psx demo showing this + feature) + +- softm informed me on my messageboard that one of the transparency modes + seems to be wrong in some games (Diablo, Legend of Mana, Castlevania). + I've repaired that, now it will look fine. + +- Sometimes small (wrong) texture distortions happened in the soft gpu. + That's caused by internal precision issues, when the plugin is drawing + quads using two triangles (needed to get the PSX g-shading right). + I've made a special game fix (0x200), now users can decide if they want + a correct g-shading (fix activated) or textures without distortions + (fix deactivated). + +- The frame limit value is now a floating point number, so you can + set (for example) "50.1" as limit. Dunno why, but many users requested + this... anyway, my advice: use the "auto-detect limit" option whenever + it's possible :) + + +-------------------------------------------------------------------------- + +13. March, 2004 Version 1.16 + +- Stefan Sperling improved the Linux fullscreen switching a little, + to get around refresh frequency issues in some special cases. + +- Pete fixed certain Skullmonkey issues (sprite coord y wrap is now + working fine) + +- Pete added a new game fix ("0x100 - Repeated flat tex triangles"), + activate it if you want to play Dark Forces without gfx problems. + +- Pete added arcade psx gpu compatibility + + OK, this feature will need some more explanations, so let me drop + this silly "Pete did this and that" changelog text, to take a closer + look what "arcade psx gpu" actually means :) + + Most psx emu fans will know that there are not only the psx consoles, + but also psx-based arcade cabinets for certain games. Such cabinets + often have 'enhanced' psx gpus inside, which are supporting more + internal vram (2 MByte instead of the 1 MByte used in the standard + psx gpu), mainly used to store more texture informations. + + The ZiNc (formerly known as "impact") emu can run such psx arcade + games, using special Glide/OGL/D3D renderer plugins done by Lewpy + and me. As you can see, only hw/accel plugins were available, due to + the fact that we were too lazy to add all the needed extra functions in + the Peops soft plugin ;) + + Well, in the last months smf did a fine job adding psx arcade games + into MAME (using his own psx gpu soft renderer functions for display), + and he even found a way to run the old Tekken arcade games without + glitches. He kindly gave this infos to Lewpy and me, and while we were + adding this stuff into our hw/accel ZiNc plugins, I also decided to + finally upgrade the Peops soft plugin, to get a ZiNc soft renderer as + well. + + Yeah, and now it is done, for both Windows and Linux. It's still one + plugin file, if you want to use it with ZiNc, simply copy it into its main + emu directory. If you only want to use the soft renderer in future, you can + rename the plugin to "renderer.znc" (Windows) or "librendererznc.so" + (Linux). Otherwise you can also use the ZiNc "--renderer=..." command + line switch to tell the main emu to temporary use the soft renderer for the + next game. + + How to configure it? The hw/accel ZiNc renderers use .cfg text files + containing all needed options (just like the Peops soft Linux version), so + there is no special config window in ZiNc. For the MSWindows version of + the Peops soft plugin I've decided to support both: .cfg text files and the + config settings stored in the Windows registry by the standard plugin + config window. So, if you start ZiNc with a command line option like + "--use-renderer-cfg-file=xxx.cfg", the settings of this file will be used (see + the "gpuPeopsSoftX.cfg" file included in the full sources release for details). + If you don't specify a .cfg file with ZiNc, the Peops soft plugin will use the + Windows registry settings instead. Of course that means that you first + have to start a psx emu like epsxe or pcsx, to configure the soft plugin + at least once. + + Mmm, what else? Ah, yes... the Peops soft gpu is capable to run Tekken + without glitches, but you will need a newer version of ZiNc, the current + release will not work correctly. Also certain display issues (for example + big polygons with one character in SFEX2) are most likely caused by + the main emu, and cannot get fixed by the gpu plugin, so don't blame me :) + + Anyway, have fun, + Pete + + +-------------------------------------------------------------------------- + +01. August, 2003 Version 1.15 + +- Yokota updated his MinGW patches. They are now "less ugly", + to quote him :) + +- Pete fixed an issue with frame limitation if the "old skipping" + method was used - thanx to Ronald Andersson for reporting it. + +- Pete added the new "Pad" display characters in the gpu in-game + menu (used with ePSXe 1.6.0) + +- Pete fixed the Skullmonkeys background layers, they are now + perfectly visible - thanx to calb for the save state. + + +-------------------------------------------------------------------------- + +09. Juny, 2003 Version 1.14 + +- Avery Lee, the author of VirtualDub, detected a bug + within the AVI recording funcs and kindly fixed the issue. + It's now possible to load avi files created by the P.E.Op.S. + soft gpu into VirtualDub without problems. + +- Yokota created a patch to compile the plugin with MinGW. + You can find it in the "makes" directory, please also check + out the included readme file for details. + +- linuzappz rewrote the Linux config/about dialogs, using Glade. + The new dialogs are listing the available fullscreen modes, + if XF86VM support is enabled. + + +-------------------------------------------------------------------------- + +07. January, 2003 Version 1.12 + +- linuzappz improved the linux ports further: he fixed the + non-streched 2x modes for DGA2, added some more + error messages, if the DGA2 init fails, and optimized + all the Linux stretching funcs, for a little speed up. + +- All other changes were done by me (Pete), but before + I explain them, I want to thank linuzappz for his never- + ending support. He added improvements in nearly every + release, I don't know how he finds the time beside his other + emulation related projects :) + +- Ok, first a small bugfix: the main menu of Legend of Legaia + is now displayed again (I screwed that somewhen in version + 1.10 or 1.11). + +- Important for all ChronoCross players: I have removed the + internal status screen hack, and made a special game fix for it. + That means that if you want to play CC with epsxe 1.5.2, + you have to activate the new "odd/even bit" game fix, otherwise + the game will lock up if you want to see the CC status screen. + That also means that in the next epsxe version that fix will not + needed anymore, due to an improved epsxe vsync handling :) + +- Another feature for the upcoming epsxe version has been + added: a cursor interface func. What's that for? well, the next + epsxe version will show it ;) + +- The 'improved frame skipping' handling has been improved + further. Some issues has been fixed, and some more security + code has been added. For the users who still like the old (V1.10 + and below) skipping method better (which only skipped every + second frame), I've added another special game fix, called "use + old frameskipping". + +- For the lovers of an 'enhanced display': I've added the Scale2x + stretching method. That one makes 2D images sharper, without + adding interpolations like the 2xSai/SuperEgale filters. + The Scale2x stretching is GPL, copyrighted by Andrea Mazzoleni , + you can find more informations on: http://scale2x.sourceforge.net. + The Scale2x stretching is again available in all MS-Windows screen + modes, as well as in the Linux X and DGA2 ports. + +- The nicest new feature (imho) is dithering support. Prolly you + already have noticed that g-shaded polygons (often used in 3D + games) have rough color steps, which is looking a bit ugly. + The real PSX can activate dithering, to make the colors smoother, + of course the side-effect is that you will notice a small dot effect + when dithering is activated. + + V1.12 will give you the choice, if the plugin should emulate the + psx dithering as well. Three modes are available: + + * No dithering: + fastest mode, no dithering will get activated (that's like in the + older plugin's versions) + * Game depended: + g-shaded textures polygons will get dithered, if the game is turning + on dithering. + * Always: + the plugin will dither all g-shaded polygons all the time, even if + a game doesn't ask for it. That's usually the nicest looking, but + also slowest, mode. + + I've added a new menu item to the gpu in-game menu as well, so + you can change between the three dithering modes while playing + a game. And a big thanx goes to Farfetch'd for his dithering + pattern. + + +-------------------------------------------------------------------------- + +03. December, 2002 Version 1.11 + +- linuzappz repaired the 2xSai modes for 15 bit color depths. + +- Pete added an improved frame skipping for slow systems. + For full details check out the 1.68 version notes of Pete's + hw/accel. gpu plugins, here's only a small summary: + * The 1.10 screen flickering with frame skipping will not + happen anymore + * Still: frame skipping will cause missing graphics in some + games + * For best results turn on skipping _and_ limitation. Try + to reach a steady 50 (PAL) or 59.94 (NTSC) frame rate. + * For buggy motherboard chipsets: activate the new 'low- + res fps timer' game fix. + + +-------------------------------------------------------------------------- + +09. November, 2002 Version 1.10 + +- Farfetch'd suggested a change in the "y display position" + code, so Pete changed it ;) + Well, it's not 100% perfect yet (could be done better in the + soft plugin), but since a 100% solution would need much + code changes (and would cause maybe slower speed), I want + to check out this approach first. + +- Pete added 2xSaI, Super2xSaI and SuperEagle display modes. + Of course a big thanx goes to Derek Liauw for his free available + 2xSaI source examples. + The following new options are available (in all supported + 15/16/32 bit desktop/fullscreen color modes): + + * 2xSaI stretching + * 2xSaI unstretched + * Super2xSaI stretching + * Super2xSaI unstretched + * SuperEagle stretching + * SuperEagle unstretched + + The "unstretched" modes will always display the screen at twice + the original psx resolution, so if your gpu window is too small, + parts of the display will get cropped (and if it's too big, a black + border will be drawn). The "stretched" modes will scale the image + to the window size, so prolly they are the better choice for gaming, + but be aware that some gfx cards will add an additional filtering + with that (as long as you don't use the "system memory" option + in Windows, which will be slower in most cards, though). + Talking about speed: all the new modes will need a fast cpu! Nevertheless + the "pure" 2xSaI mode will be the fastest, followed by the "SuperEagle" + mode, and the "Super2xSaI" mode will be the slowest option. + Note that a 16 bit color desktop/fullscreen mode will give a speed up, so + I strongly suggest to use it! + About the image quality: that's a matter of taste :) Personally I prefer the + Super2xSaI mode (and btw, that's what I am using in my hw/accel gpu + plugins). + Ah, and a note about the Linux ports: the standard X plugin (used by + epsxe and pcsx) does offer the same 6 new modes, and I've added most + stuff to the special DGA sources as well, only the unstretched modes + are not supported, as far as I remember (I can't test the DGA port here). + And all new modes are _not_ supported by the special FPSE SDL + version, maybe lu_zero can add them in the future, we will see :) + + +-------------------------------------------------------------------------- + +12. October, 2002 Version 1.9 + +- linuzappz moved the Linux config and about windows into + a separate application. This will prevent troubles with main emus/ + frontends usig a different GTK version, just copy the + cfgPeopsSoft application in the emu's cfg directory. + +- Pete added a new 'debug mode' option to the Window's plugin, + which will enable certain debug modes in the future (so it's mainly + interesting for developers). Currently only one debug feature is + available: you can configure a key to toggle between the 'normal' + display and a full vram view (showing the complete 1024x512 psx + gpu vram). Please note: not all cards will be able to do it. + +- Nearly one year ago the first version of the P.E.Op.S. soft plugin + has been released as Open Source. All kind of stuff has been + added and fixed during this year, and I would like to thank all the + coders who helped me to make it bigger and better, and of course + all the users giving support and bug reports :) + Now another nice thing happened: good ole Farfetch'd, a well-known + fellow emu coder, decided to share his knowledge about the psx + gpu with the P.E.Op.S. Open Source project. He provided me with a + lotta detail infos, things which are usually hard to find out, since + not much games are using every weird psx gpu ability. + So over a dozen small changes were done because of the new + informations, increasing the compatibility of the plugin, and actually + some of them even fixed certain issues :) + Enjoy the release, and be prepared for another year of plugin updates, + ehehe :) + + +-------------------------------------------------------------------------- + +06. September, 2002 Version 1.8 + +- linuzappz added a FPS display to the Linux DGA2 port + of the plugin + +- Lewpy and E}I{ fixed the texture window problem which + caused the bad FF7 text box borders, distortions in RRT4, + small glitches in Gauntlet Legends and a not fully displayed + loading screen in Casper. Therefore the FF7 special game + fix has been removed in 1.8! + +- Pete added a delayed odd/even toggle to correct the FF8 + intro scanlines + +- Pete changed the mask bit handling for sprites. Now the + Alone In The Dark 4 cut scenes get displayed, and FF6 + battle screen effects are fine + +- Pete added a "Sprite 1" command count (don't know if + such a command exists on the real psx, but Darko's + GPU test application needs it) + +- Pete fixed a small issue with the "screen disable" state, + which was hiding some splash screens in previous + versions + + +-------------------------------------------------------------------------- + +02. August, 2002 Version 1.7 + +- linuzappz fixed a small issue with the Linux 'About' dialog + +- Lewpy added a clean way to avoid troubles with the "Disable screen- + savers" option in Win95/WinNT + +- Lewpy replaced the old line drawing stuff (which used simply + thin quads) with nicer and faster native line functions + +- Pete added an internal fix for FF9 mask bit issues (a few texts in + animated mdecs were missing) + +- Pete improved the dma write/read wrapping. Should be fine now. + +- Pete removed the dmachain special game fixes with a good + working 'bad dmachain' auto-detection. + +- Pete changed major parts in the dmachain handler. Games like + 'Monkey Hero' are working now without problems. + + +-------------------------------------------------------------------------- + +29. May, 2002 Version 1.6 + +- linuzappz added a fast forward frame skipping. That will give + a big speed boost on slow systems as well. I (Pete) have + added a selectable hotkey for enabling/disabling this skipping + mode in Windows, and you can also use the gpu menu to activate + it (in both the Windows and the Linux version). Please note: + some games (like FF9) will really hate any kind of frame skipping, + you will have to turn it off in that games. + +- All other stuff in this release by Pete: + + * Fixed the "mdec polygons" in FF9 + * Added new coordinate checks, that will remove most weird + polygon glitches (like the lights in MGS) + * Extra code for fixing texture distortions on g-shaded rects + * Redone all texture window functions, that will give a big + speed boost in certain games (for example Jumping Flash) + * Fixed the mask bit emulation for non-textured primitives + (Bloody Roar 2, Ace Combat 3) + * Adjusted some other rendering stuff, Doom should rune fine + now + * A new special game fix for getting the Ranma 1/2 menus right + (most likely caused by a corrupt dma chain) + + +-------------------------------------------------------------------------- + +15. March, 2002 Version 1.5 + +- lu_zero was working on the SDL support (FPSE version only), + he added optional SDL direct blit/direct stretch funcs to get + more speed. + He also made some Linux Makefile changes, to make compiling of + all the different versions easier (well, some configure script + will follow soon, I think ;) If you want/need to compile the Linux version + yourself, just include the wanted mk file in the main Makefile (for + example "mk.x11" for the epsxe/pcsx version or "mk.fpse" for the + fpse/sdl version) and run a "make clean all" (or a "make clean release", + if you want to have a smaller stripped file). + +- linuzappz added fullscreen DGA2 support for the Linux version. That + will give a 30% speed increase in the fullscreen drawing, if your XServer + supports the DGA2 mode (linuappz had to update his XServer to version + 4.2.0 to get it to work, and my aging 4.0.3 crashes hard with DGA2). + To activate DGA2, you have to edit the mk.x11 files (in the "makes" directory), + and set the switch "XF86DGA2" to "TRUE". + +- Pete removed the "no sprite transparency" and "black poly" special + game fixes (both were fixing some main emu bugs, but they are + not longer needed), and added two new ones instead.. ;) + 1. a fix to increase the display size for Capcom 2D fighting games + (without the fix the right side of the display will be missing some pixels) + 2. a Lunar1 fix. That one will kinda fix all the black screens in Lunar1 + (also a main emu bug... well, the game seems to play ok with that + fix, an unwanted 'flashing' will appear when entering a house, but + that's bearable, I think) + Beside that special fixes Pete also squashed some real bugs, so + for example "The Mummy" and "T'ai Fu" will work now in the soft + plugin, and some more additional memory checks will make a few + magical effects in FF9 and BOF4 appear. + +- A few more additions (like the Linux xshm support from Vedran Rodic) + are not included in 1.5 (lack of time for testing, sorry), but hey, + there will be always a 1.6... and I know that some die-hard Lunar1 fans + couldn't wait anymore :) + + +-------------------------------------------------------------------------- + +12. January, 2002 Version 1.4 + +- lu_zero and linuzappz were working on the Linux config + windows, now the dialogs should work fine in + FPSE-Linux, and in pcsx-Linux as well. + +- Pete fixed a BAD bug in the linux version, which caused + garbage screens in certain games (for example Grandia or + Star Ocean2), if stretching was enabled. + +- Pete also removed unneeded screen clearing, if a game was + doing horizontal centering. That will speed up the windows + version, and fixes screen flickering in the Linux version. + +- Syo enhanced the Windows version by adding a "Wait for + vsync" option (including an hotkey to toggle vsync + waiting on/off during game play). Also the plugin now lists + the fullscreen resolutions with supported refresh rates + (if that info is available), so you can select a different + monitor refresh rate for fullscreen modes. + +- Small cosmetics: Syo added "Transparent fps menu" option + in the Windows version, and lu_zero took care about the + caption texts in the Linux versions. + +- Darko Matesic improved his recording funcs (Windows version). + Now there are two types of compression (16bit & 24bit), and + a WinFPSE 24bit MDEC support. + +- Pete added Linux fullscreen video mode switching in the non-SDL + version. Unlike the MesaGL plugin the libXxf86vm is linked + statically, hopefully that will give less troubles on + some systems. If you want to disable the xf86vm support, you + can edit the Makefile, and compile a version without + video mode switching support. + + +-------------------------------------------------------------------------- + +16. November, 2001 Version 1.3 + +- lu_zero added the native Windows FPSE interface (thanx to + xobro for additional help). Now you can use the Windows plugin + in FPSE without the PSEmu interface wrapper. + As a small goodie I (Pete) have added support for right colors + in FPSE mdec movies, if the FPSE interface is used. + +- Also done by lu_zero: real fullscreen support in the FPSE SDL + linux version. + +- A new coder is syo (syo68k@geocities.co.jp). He has added + two options in the Windows plugin: "use system memory" + and "stop screen saver". Let's hear what syo has to say about + the new options: + + -> added "Use system memory" + + When a stretch is carried out, the filter by the video card stops + applying, if this check is turned ON. + + However, when the memory speed of a system is slow, it leads to the + sharp fall of speed. In almost all cases, the speed of a system memory + is very slower than the memory of a video card. + + In the following environment, about 50% of speed fall was checked. + + CPU AMD AthlonMP 1200MHz@1400MHz (system bus speed 133MHz) + MotherBoard ASUSTeK A7V266 (VIA KT266) + VideoCard ATi RADEON DDR 32MB Clock 166MHz + Memory DDR-SDRAM 256MB CL=2.5 1T Command + OS WindowsXP Professional + Stretch 320x240 to 640x480 + + -> added "Stop screen saver" + If a check is turned ON, operation in a screen saver and + power-saving mode will be stopped. + + However, it does not operate in WindowsNT4 and Windows 95. + Since the version check has not been carried out, + if this check is confirmed, it will crash by WindowsNT4 and Windows 95. + + Syo also repaired a small thing in the Windows gpu config window... I never + had problems with the old code, but hey, the new one doesn't hurt either :) + +- linuzappz added a nice About... and Configure... window in the linux plugins. + The configure window will change the .cfg file, the file can now be placed + into the home directory, the main emu directory or a "/cfg" sub directory + (search for the file will happen in reverse order ;). + +- Oh well, and I've added some changes, too: + + 1.) support for psx 15 bit texture window primitives... never seen them in + games, but Darko and his gputest app forced me to include it ;) + + 2.) a small fix for Grandia... now the screen will be centered better, causing + that annoying flickering line on the right side of the display to disappear :) + + 3.) fixed a small but nasty bug with the mask bit in Poly4F primitives. + Now the MGS message display will be fine again. + + 4.) a new special game fix called "Adjust extreme coords". That will help + games like Nascar racing, Syphon Filter 2 and a few MGS light effects. + Maybe some more games are affected, you can try the new option + with all games showing wild polygons all over the screen. + Well, imho that's a bug of the main emus, but as long as the gpu can + repair it, who cares? ;) + + +-------------------------------------------------------------------------- + +11. November, 2001 Version 1.2 + +- Avi recording funcs by Darko Matesic (Windows version only). + You can start/stop the recording using a configurable hotkey. The + movie files will be stored into the \Demo sub-directory. + +- Nasm support by linuzappz. That's important for the Linux version, + the same asm code can finally be used in the Windows and Linux + plugin (and hopefully a small speedup will show up in the Linux + version). + +- SDL support and FPSE layer (just for the FPSE ports) by lu_zero. + Now we can have many more portable version. + The makefile has to be fixed again =/ + The FPSE layer for Win32 isn't ready + +-------------------------------------------------------------------------- + +04. November, 2001 Version 1.1 + +- First release of the P.E.Op.S soft gpu plugin, same funcs + and features as Pete's soft gpu version 1.54 + Check out https://sourceforge.net/projects/peops/ for future + releases. + + +-------------------------------------------------------------------------- diff --git a/PeopsSoftGPU/prim.c b/PeopsSoftGPU/prim.c new file mode 100644 index 0000000..a95ce5b --- /dev/null +++ b/PeopsSoftGPU/prim.c @@ -0,0 +1,1695 @@ +/*************************************************************************** + prim.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2004/01/31 - Pete +// - added zn bits and two zn cheats (TileS & move image - 2004/03/13) +// +// 2003/07/22 - Pete +// - added sprite x coord wrap (skullmonkey) - new: sprite y coord wrap as well +// +// 2002/12/14 - Pete +// - added dithering flag +// +// 2002/10/03 - Farfetch'd & Pete +// - changed: polylines, 11 bit coords, polygon discarding, BlkFill align, mask bits +// +// 2002/09/19 - Farfetch'd +// - STP: read control register is now masked correctly with 0x3 +// +// 2002/08/16 - Pete +// - additional mask bit handling for sprites (Alone in the Dark 4 & FF6) +// +// 2002/08/10 - Lewpy & E}I{ +// - correct TW coord adjustment (RRT4) +// +// 2002/07/22 - Pete +// - problem with the "2002/05/19 fixed mdec mask bit problem in FF9" fixed (hopefully) +// +// 2002/06/04 - Lewpy +// - new line drawing funcs +// +// 2002/05/19 - Pete +// - mdec mask bit problem in FF9 fixed +// +// 2002/05/14 - Pete +// - new coord check +// +// 2002/03/29 - Pete +// - tex window coord adjustment - thanx to E}I{ +// - faster generic coord check - thanx to E}I{ +// - StoreImage wrap (Devilsummoner Soul Hackers) +// +// 2002/03/27 - Pete +// - improved sprite texture wrapping func on _very_ big sprites +// +// 2002/02/23 - Pete +// - added Lunar "ignore blending color" fix +// +// 2002/02/12 - Pete +// - removed "no sprite transparency" and "black poly" fixes +// +// 2002/02/10 - Pete +// - additional Load/MoveImage checks for a few FF9/BOF4 effects +// +// 2001/12/10 - Pete +// - additional coord checks for Nascar and SF2 (and more...?) +// +// 2001/11/08 - Linuzappz +// - BGR24to16 converted to nasm, C version still works: define __i386_ +// to use the asm version +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#define _IN_PRIMDRAW + +#include "externals.h" +#include "gpu.h" +#include "draw.h" +#include "soft.h" +#include "swap.h" + +//////////////////////////////////////////////////////////////////////// +// globals +//////////////////////////////////////////////////////////////////////// + +BOOL bUsingTWin=FALSE; +TWin_t TWin; +unsigned long clutid; // global clut +unsigned short usMirror=0; // sprite mirror +int iDither=0; +long drawX; +long drawY; +long drawW; +long drawH; +unsigned long dwCfgFixes; +unsigned long dwActFixes=0; +unsigned long dwEmuFixes=0; +int iUseFixes; +int iUseDither=0; +BOOL bDoVSyncUpdate=FALSE; + +//////////////////////////////////////////////////////////////////////// +// Some ASM color convertion by LEWPY +//////////////////////////////////////////////////////////////////////// + +#ifdef __i386__ + +#define BGR24to16 i386_BGR24to16 +__inline unsigned short BGR24to16 (unsigned long BGR); + +#else + +__inline unsigned short BGR24to16 (unsigned long BGR) +{ + return (unsigned short)(((BGR>>3)&0x1f)|((BGR&0xf80000)>>9)|((BGR&0xf800)>>6)); +} + +#endif + +//////////////////////////////////////////////////////////////////////// +// Update global TP infos +//////////////////////////////////////////////////////////////////////// + +__inline void UpdateGlobalTP(unsigned short gdata) +{ + GlobalTextAddrX = (gdata << 6) & 0x3c0; // texture addr + GlobalTextAddrY = (gdata << 4) & 0x100; + + usMirror=gdata&0x3000; + + if(iUseDither==2) + { + iDither=2; + } + else + { + if(gdata&200) iDither=iUseDither; else iDither=0; + } + + GlobalTextTP = (gdata >> 7) & 0x3; // tex mode (4,8,15) + + if(GlobalTextTP==3) GlobalTextTP=2; // seen in Wild9 :( + + GlobalTextABR = (gdata >> 5) & 0x3; // blend mode + + lGPUstatusRet&=~0x07ff; // Clear the necessary bits + lGPUstatusRet|=(gdata & 0x07ff); // set the necessary bits +} + +//////////////////////////////////////////////////////////////////////// + +__inline void SetRenderMode(unsigned long DrawAttributes) +{ + DrawSemiTrans = (SEMITRANSBIT(DrawAttributes)) ? TRUE : FALSE; + + if(SHADETEXBIT(DrawAttributes)) + {g_m1=g_m2=g_m3=128;} + else + { + if((dwActFixes&4) && ((DrawAttributes&0x00ffffff)==0)) + DrawAttributes|=0x007f7f7f; + + g_m1=(short)(DrawAttributes&0xff); + g_m2=(short)((DrawAttributes>>8)&0xff); + g_m3=(short)((DrawAttributes>>16)&0xff); + } +} + +//////////////////////////////////////////////////////////////////////// + +// oki, here are the psx gpu coord rules: poly coords are +// 11 bit signed values (-1024...1023). If the x or y distance +// exceeds 1024, the polygon will not be drawn. +// Since quads are treated as two triangles by the real gpu, +// this 'discard rule' applies to each of the quad's triangle +// (so one triangle can be drawn, the other one discarded). +// Also, y drawing is wrapped at 512 one time, +// then it will get negative (and therefore not drawn). The +// 'CheckCoord' funcs are a simple (not comlete!) approach to +// do things right, I will add a better detection soon... the +// current approach will be easier to do in hw/accel plugins, imho + +// 11 bit signed +#define SIGNSHIFT 21 +#define CHKMAX_X 1024 +#define CHKMAX_Y 512 + +void AdjustCoord4() +{ + lx0=(short)(((int)lx0<>SIGNSHIFT); + lx1=(short)(((int)lx1<>SIGNSHIFT); + lx2=(short)(((int)lx2<>SIGNSHIFT); + lx3=(short)(((int)lx3<>SIGNSHIFT); + ly0=(short)(((int)ly0<>SIGNSHIFT); + ly1=(short)(((int)ly1<>SIGNSHIFT); + ly2=(short)(((int)ly2<>SIGNSHIFT); + ly3=(short)(((int)ly3<>SIGNSHIFT); +} + +void AdjustCoord3() +{ + lx0=(short)(((int)lx0<>SIGNSHIFT); + lx1=(short)(((int)lx1<>SIGNSHIFT); + lx2=(short)(((int)lx2<>SIGNSHIFT); + ly0=(short)(((int)ly0<>SIGNSHIFT); + ly1=(short)(((int)ly1<>SIGNSHIFT); + ly2=(short)(((int)ly2<>SIGNSHIFT); +} + +void AdjustCoord2() +{ + lx0=(short)(((int)lx0<>SIGNSHIFT); + lx1=(short)(((int)lx1<>SIGNSHIFT); + ly0=(short)(((int)ly0<>SIGNSHIFT); + ly1=(short)(((int)ly1<>SIGNSHIFT); +} + +void AdjustCoord1() +{ + lx0=(short)(((int)lx0<>SIGNSHIFT); + ly0=(short)(((int)ly0<>SIGNSHIFT); + + if(lx0<-512 && PSXDisplay.DrawOffset.x<=-512) + lx0+=2048; + + if(ly0<-512 && PSXDisplay.DrawOffset.y<=-512) + ly0+=2048; +} + +//////////////////////////////////////////////////////////////////////// +// special checks... nascar, syphon filter 2, mgs +//////////////////////////////////////////////////////////////////////// + +// xenogears FT4: not removed correctly right now... the tri 0,1,2 +// should get removed, the tri 1,2,3 should stay... pfff + +// x -466 1023 180 1023 +// y 20 -228 222 -100 + +// 0 __1 +// . . . +// 2___3 + +__inline BOOL CheckCoord4() +{ + if(lx0<0) + { + if(((lx1-lx0)>CHKMAX_X) || + ((lx2-lx0)>CHKMAX_X)) + { + if(lx3<0) + { + if((lx1-lx3)>CHKMAX_X) return TRUE; + if((lx2-lx3)>CHKMAX_X) return TRUE; + } + } + } + if(lx1<0) + { + if((lx0-lx1)>CHKMAX_X) return TRUE; + if((lx2-lx1)>CHKMAX_X) return TRUE; + if((lx3-lx1)>CHKMAX_X) return TRUE; + } + if(lx2<0) + { + if((lx0-lx2)>CHKMAX_X) return TRUE; + if((lx1-lx2)>CHKMAX_X) return TRUE; + if((lx3-lx2)>CHKMAX_X) return TRUE; + } + if(lx3<0) + { + if(((lx1-lx3)>CHKMAX_X) || + ((lx2-lx3)>CHKMAX_X)) + { + if(lx0<0) + { + if((lx1-lx0)>CHKMAX_X) return TRUE; + if((lx2-lx0)>CHKMAX_X) return TRUE; + } + } + } + + + if(ly0<0) + { + if((ly1-ly0)>CHKMAX_Y) return TRUE; + if((ly2-ly0)>CHKMAX_Y) return TRUE; + } + if(ly1<0) + { + if((ly0-ly1)>CHKMAX_Y) return TRUE; + if((ly2-ly1)>CHKMAX_Y) return TRUE; + if((ly3-ly1)>CHKMAX_Y) return TRUE; + } + if(ly2<0) + { + if((ly0-ly2)>CHKMAX_Y) return TRUE; + if((ly1-ly2)>CHKMAX_Y) return TRUE; + if((ly3-ly2)>CHKMAX_Y) return TRUE; + } + if(ly3<0) + { + if((ly1-ly3)>CHKMAX_Y) return TRUE; + if((ly2-ly3)>CHKMAX_Y) return TRUE; + } + + return FALSE; +} + +__inline BOOL CheckCoord3() +{ + if(lx0<0) + { + if((lx1-lx0)>CHKMAX_X) return TRUE; + if((lx2-lx0)>CHKMAX_X) return TRUE; + } + if(lx1<0) + { + if((lx0-lx1)>CHKMAX_X) return TRUE; + if((lx2-lx1)>CHKMAX_X) return TRUE; + } + if(lx2<0) + { + if((lx0-lx2)>CHKMAX_X) return TRUE; + if((lx1-lx2)>CHKMAX_X) return TRUE; + } + if(ly0<0) + { + if((ly1-ly0)>CHKMAX_Y) return TRUE; + if((ly2-ly0)>CHKMAX_Y) return TRUE; + } + if(ly1<0) + { + if((ly0-ly1)>CHKMAX_Y) return TRUE; + if((ly2-ly1)>CHKMAX_Y) return TRUE; + } + if(ly2<0) + { + if((ly0-ly2)>CHKMAX_Y) return TRUE; + if((ly1-ly2)>CHKMAX_Y) return TRUE; + } + + return FALSE; +} + + +__inline BOOL CheckCoord2() +{ + if(lx0<0) + { + if((lx1-lx0)>CHKMAX_X) return TRUE; + } + if(lx1<0) + { + if((lx0-lx1)>CHKMAX_X) return TRUE; + } + if(ly0<0) + { + if((ly1-ly0)>CHKMAX_Y) return TRUE; + } + if(ly1<0) + { + if((ly0-ly1)>CHKMAX_Y) return TRUE; + } + + return FALSE; +} + +__inline BOOL CheckCoordL(short slx0,short sly0,short slx1,short sly1) +{ + if(slx0<0) + { + if((slx1-slx0)>CHKMAX_X) return TRUE; + } + if(slx1<0) + { + if((slx0-slx1)>CHKMAX_X) return TRUE; + } + if(sly0<0) + { + if((sly1-sly0)>CHKMAX_Y) return TRUE; + } + if(sly1<0) + { + if((sly0-sly1)>CHKMAX_Y) return TRUE; + } + + return FALSE; +} + + +//////////////////////////////////////////////////////////////////////// +// mask stuff... used in silent hill +//////////////////////////////////////////////////////////////////////// + +void cmdSTP(unsigned char * baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + lGPUstatusRet&=~0x1800; // Clear the necessary bits + lGPUstatusRet|=((gdata & 0x03) << 11); // Set the necessary bits + + if(gdata&1) {sSetMask=0x8000;lSetMask=0x80008000;} + else {sSetMask=0; lSetMask=0; } + + if(gdata&2) bCheckMask=TRUE; + else bCheckMask=FALSE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: Set texture page infos +//////////////////////////////////////////////////////////////////////// + +void cmdTexturePage(unsigned char * baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + UpdateGlobalTP((unsigned short)gdata); + GlobalTextREST = (gdata&0x00ffffff)>>9; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: turn on/off texture window +//////////////////////////////////////////////////////////////////////// + +void cmdTextureWindow(unsigned char *baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + unsigned long YAlign,XAlign; + + lGPUInfoVals[INFO_TW]=gdata&0xFFFFF; + + if(gdata & 0x020) + TWin.Position.y1 = 8; // xxxx1 + else if (gdata & 0x040) + TWin.Position.y1 = 16; // xxx10 + else if (gdata & 0x080) + TWin.Position.y1 = 32; // xx100 + else if (gdata & 0x100) + TWin.Position.y1 = 64; // x1000 + else if (gdata & 0x200) + TWin.Position.y1 = 128; // 10000 + else + TWin.Position.y1 = 256; // 00000 + + // Texture window size is determined by the least bit set of the relevant 5 bits + + if (gdata & 0x001) + TWin.Position.x1 = 8; // xxxx1 + else if (gdata & 0x002) + TWin.Position.x1 = 16; // xxx10 + else if (gdata & 0x004) + TWin.Position.x1 = 32; // xx100 + else if (gdata & 0x008) + TWin.Position.x1 = 64; // x1000 + else if (gdata & 0x010) + TWin.Position.x1 = 128; // 10000 + else + TWin.Position.x1 = 256; // 00000 + + // Re-calculate the bit field, because we can't trust what is passed in the data + + YAlign = (unsigned long)(32 - (TWin.Position.y1 >> 3)); + XAlign = (unsigned long)(32 - (TWin.Position.x1 >> 3)); + + // Absolute position of the start of the texture window + + TWin.Position.y0 = (short)(((gdata >> 15) & YAlign) << 3); + TWin.Position.x0 = (short)(((gdata >> 10) & XAlign) << 3); + + if((TWin.Position.x0 == 0 && // tw turned off + TWin.Position.y0 == 0 && + TWin.Position.x1 == 0 && + TWin.Position.y1 == 0) || + (TWin.Position.x1 == 256 && + TWin.Position.y1 == 256)) + { + bUsingTWin = FALSE; // -> just do it + } + else // otherwise + { + bUsingTWin = TRUE; // -> tw turned on + } +} + +//////////////////////////////////////////////////////////////////////// +// cmd: start of drawing area... primitives will be clipped inside +//////////////////////////////////////////////////////////////////////// + +void cmdDrawAreaStart(unsigned char * baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + drawX = gdata & 0x3ff; // for soft drawing + + if(dwGPUVersion==2) + { + lGPUInfoVals[INFO_DRAWSTART]=gdata&0x3FFFFF; + drawY = (gdata>>12)&0x3ff; + if(drawY>=1024) drawY=1023; // some security + } + else + { + lGPUInfoVals[INFO_DRAWSTART]=gdata&0xFFFFF; + drawY = (gdata>>10)&0x3ff; + if(drawY>=512) drawY=511; // some security + } +} + +//////////////////////////////////////////////////////////////////////// +// cmd: end of drawing area... primitives will be clipped inside +//////////////////////////////////////////////////////////////////////// + +void cmdDrawAreaEnd(unsigned char * baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + drawW = gdata & 0x3ff; // for soft drawing + + if(dwGPUVersion==2) + { + lGPUInfoVals[INFO_DRAWEND]=gdata&0x3FFFFF; + drawH = (gdata>>12)&0x3ff; + if(drawH>=1024) drawH=1023; // some security + } + else + { + lGPUInfoVals[INFO_DRAWEND]=gdata&0xFFFFF; + drawH = (gdata>>10)&0x3ff; + if(drawH>=512) drawH=511; // some security + } +} + +//////////////////////////////////////////////////////////////////////// +// cmd: draw offset... will be added to prim coords +//////////////////////////////////////////////////////////////////////// + +void cmdDrawOffset(unsigned char * baseAddr) +{ + unsigned long gdata = GETLE32(&((unsigned long*)baseAddr)[0]); + + PSXDisplay.DrawOffset.x = (short)(gdata & 0x7ff); + + if(dwGPUVersion==2) + { + lGPUInfoVals[INFO_DRAWOFF]=gdata&0x7FFFFF; + PSXDisplay.DrawOffset.y = (short)((gdata>>12) & 0x7ff); + } + else + { + lGPUInfoVals[INFO_DRAWOFF]=gdata&0x3FFFFF; + PSXDisplay.DrawOffset.y = (short)((gdata>>11) & 0x7ff); + } + + PSXDisplay.DrawOffset.y=(short)(((int)PSXDisplay.DrawOffset.y<<21)>>21); + PSXDisplay.DrawOffset.x=(short)(((int)PSXDisplay.DrawOffset.x<<21)>>21); +} + +//////////////////////////////////////////////////////////////////////// +// cmd: load image to vram +//////////////////////////////////////////////////////////////////////// + +void primLoadImage(unsigned char * baseAddr) +{ + unsigned short *sgpuData = ((unsigned short *) baseAddr); + + VRAMWrite.x = GETLEs16(&sgpuData[2])&0x3ff; + VRAMWrite.y = GETLEs16(&sgpuData[3])&0x1ff; + VRAMWrite.Width = GETLEs16(&sgpuData[4]); + VRAMWrite.Height = GETLEs16(&sgpuData[5]); + + DataWriteMode = DR_VRAMTRANSFER; + + VRAMWrite.ImagePtr = psxVuw + (VRAMWrite.y<<10) + VRAMWrite.x; + VRAMWrite.RowsRemaining = VRAMWrite.Width; + VRAMWrite.ColsRemaining = VRAMWrite.Height; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: vram -> psx mem +//////////////////////////////////////////////////////////////////////// + +void primStoreImage(unsigned char * baseAddr) +{ + unsigned short *sgpuData = ((unsigned short *) baseAddr); + + VRAMRead.x = GETLEs16(&sgpuData[2])&0x03ff; + VRAMRead.y = GETLEs16(&sgpuData[3])&0x01ff; + VRAMRead.Width = GETLEs16(&sgpuData[4]); + VRAMRead.Height = GETLEs16(&sgpuData[5]); + + VRAMRead.ImagePtr = psxVuw + (VRAMRead.y<<10) + VRAMRead.x; + VRAMRead.RowsRemaining = VRAMRead.Width; + VRAMRead.ColsRemaining = VRAMRead.Height; + + DataReadMode = DR_VRAMTRANSFER; + + lGPUstatusRet |= GPUSTATUS_READYFORVRAM; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: blkfill - NO primitive! Doesn't care about draw areas... +//////////////////////////////////////////////////////////////////////// + +void primBlkFill(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + short sX = GETLEs16(&sgpuData[2]); + short sY = GETLEs16(&sgpuData[3]); + short sW = GETLEs16(&sgpuData[4]) & 0x3ff; + short sH = GETLEs16(&sgpuData[5]) & 0x3ff; + + sW = (sW+15) & ~15; + + // Increase H & W if they are one short of full values, because they never can be full values + if (sH >= 1023) sH=1024; + if (sW >= 1023) sW=1024; + + // x and y of end pos + sW+=sX; + sH+=sY; + + FillSoftwareArea(sX, sY, sW, sH, BGR24to16(GETLE32(&gpuData[0]))); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: move image vram -> vram +//////////////////////////////////////////////////////////////////////// + +void primMoveImage(unsigned char * baseAddr) +{ + short *sgpuData = ((short *) baseAddr); + + short imageY0,imageX0,imageY1,imageX1,imageSX,imageSY,i,j; + + imageX0 = GETLEs16(&sgpuData[2])&0x03ff; + imageY0 = GETLEs16(&sgpuData[3])&0x01ff; + imageX1 = GETLEs16(&sgpuData[4])&0x03ff; + imageY1 = GETLEs16(&sgpuData[5])&0x01ff; + imageSX = GETLEs16(&sgpuData[6]); + imageSY = GETLEs16(&sgpuData[7]); + + if((imageX0 == imageX1) && (imageY0 == imageY1)) return; + if(imageSX<=0) return; + if(imageSY<=0) return; + + // ZN SF2: screwed moves + // + // move sgpuData[2],sgpuData[3],sgpuData[4],sgpuData[5],sgpuData[6],sgpuData[7] + // + // move 365 182 32723 -21846 17219 15427 + // move 127 160 147 -1 20817 13409 + // move 141 165 16275 -21862 -32126 13442 + // move 161 136 24620 -1 16962 13388 + // move 168 138 32556 -13090 -29556 15500 + // + // and here's the hack for it: + + if(iGPUHeight==1024 && sgpuData[7]>1024) return; + + if((imageY0+imageSY)>iGPUHeight || + (imageX0+imageSX)>1024 || + (imageY1+imageSY)>iGPUHeight || + (imageX1+imageSX)>1024) + { + int i,j; + for(j=0;j>1; + + SRCPtr = (unsigned long *)(psxVuw + (1024*imageY0) + imageX0); + DSTPtr = (unsigned long *)(psxVuw + (1024*imageY1) + imageX1); + + LineOffset = 512 - dx; + + for(j=0;j=PSXDisplay.DisplayPosition.x && + imageY1=PSXDisplay.DisplayPosition.y) + updateDisplay(); + } +*/ + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: draw free-size Tile +//////////////////////////////////////////////////////////////////////// + +//#define SMALLDEBUG +//#include + +void primTileS(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long*)baseAddr); + short *sgpuData = ((short *) baseAddr); + short sW = GETLEs16(&sgpuData[4]) & 0x3ff; + short sH = GETLEs16(&sgpuData[5]) & 0x1ff; + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + // x and y of start + ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y; + ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y; + lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x; + lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x; + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + if(!(iTileCheat && sH==32 && GETLE32(&gpuData[0])==0x60ffffff)) // special cheat for certain ZiNc games + FillSoftwareAreaTrans(lx0,ly0,lx2,ly2, + BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: draw 1 dot Tile (point) +//////////////////////////////////////////////////////////////////////// + +void primTile1(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long*)baseAddr); + short *sgpuData = ((short *) baseAddr); + short sH = 1; + short sW = 1; + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + // x and y of start + ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y; + ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y; + lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x; + lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x; + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + FillSoftwareAreaTrans(lx0,ly0,lx2,ly2, + BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: draw 8 dot Tile (small rect) +//////////////////////////////////////////////////////////////////////// + +void primTile8(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long*)baseAddr); + short *sgpuData = ((short *) baseAddr); + short sH = 8; + short sW = 8; + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + // x and y of start + ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y; + ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y; + lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x; + lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x; + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + FillSoftwareAreaTrans(lx0,ly0,lx2,ly2, + BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: draw 16 dot Tile (medium rect) +//////////////////////////////////////////////////////////////////////// + +void primTile16(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long*)baseAddr); + short *sgpuData = ((short *) baseAddr); + short sH = 16; + short sW = 16; + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + // x and y of start + ly2 = ly3 = ly0+sH +PSXDisplay.DrawOffset.y; + ly0 = ly1 = ly0 +PSXDisplay.DrawOffset.y; + lx1 = lx2 = lx0+sW +PSXDisplay.DrawOffset.x; + lx0 = lx3 = lx0 +PSXDisplay.DrawOffset.x; + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + FillSoftwareAreaTrans(lx0,ly0,lx2,ly2, + BGR24to16(GETLE32(&gpuData[0]))); // Takes Start and Offset + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: small sprite (textured rect) +//////////////////////////////////////////////////////////////////////// + +void primSprt8(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + SetRenderMode(GETLE32(&gpuData[0])); + + if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,8,8); + else + if(usMirror) DrawSoftwareSpriteMirror(baseAddr,8,8); + else DrawSoftwareSprite(baseAddr,8,8, + baseAddr[8], + baseAddr[9]); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: medium sprite (textured rect) +//////////////////////////////////////////////////////////////////////// + +void primSprt16(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + SetRenderMode(GETLE32(&gpuData[0])); + + if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,16,16); + else + if(usMirror) DrawSoftwareSpriteMirror(baseAddr,16,16); + else DrawSoftwareSprite(baseAddr,16,16, + baseAddr[8], + baseAddr[9]); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: free-size sprite (textured rect) +//////////////////////////////////////////////////////////////////////// + +// func used on texture coord wrap +void primSprtSRest(unsigned char * baseAddr,unsigned short type) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + unsigned short sTypeRest=0; + + short s; + short sX = GETLEs16(&sgpuData[2]); + short sY = GETLEs16(&sgpuData[3]); + short sW = GETLEs16(&sgpuData[6]) & 0x3ff; + short sH = GETLEs16(&sgpuData[7]) & 0x1ff; + short tX = baseAddr[8]; + short tY = baseAddr[9]; + + switch(type) + { + case 1: + s=256-baseAddr[8]; + sW-=s; + sX+=s; + tX=0; + break; + case 2: + s=256-baseAddr[9]; + sH-=s; + sY+=s; + tY=0; + break; + case 3: + s=256-baseAddr[8]; + sW-=s; + sX+=s; + tX=0; + s=256-baseAddr[9]; + sH-=s; + sY+=s; + tY=0; + break; + case 4: + s=512-baseAddr[8]; + sW-=s; + sX+=s; + tX=0; + break; + case 5: + s=512-baseAddr[9]; + sH-=s; + sY+=s; + tY=0; + break; + case 6: + s=512-baseAddr[8]; + sW-=s; + sX+=s; + tX=0; + s=512-baseAddr[9]; + sH-=s; + sY+=s; + tY=0; + break; + } + + SetRenderMode(GETLE32(&gpuData[0])); + + if(tX+sW>256) {sW=256-tX;sTypeRest+=1;} + if(tY+sH>256) {sH=256-tY;sTypeRest+=2;} + + lx0 = sX; + ly0 = sY; + + if(!(dwActFixes&8)) AdjustCoord1(); + + DrawSoftwareSprite(baseAddr,sW,sH,tX,tY); + + if(sTypeRest && type<4) + { + if(sTypeRest&1 && type==1) primSprtSRest(baseAddr,4); + if(sTypeRest&2 && type==2) primSprtSRest(baseAddr,5); + if(sTypeRest==3 && type==3) primSprtSRest(baseAddr,6); + } + +} + +//////////////////////////////////////////////////////////////////////// + +void primSprtS(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + short sW,sH; + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + + if(!(dwActFixes&8)) AdjustCoord1(); + + sW = GETLEs16(&sgpuData[6]) & 0x3ff; + sH = GETLEs16(&sgpuData[7]) & 0x1ff; + + SetRenderMode(GETLE32(&gpuData[0])); + + if(bUsingTWin) DrawSoftwareSpriteTWin(baseAddr,sW,sH); + else + if(usMirror) DrawSoftwareSpriteMirror(baseAddr,sW,sH); + else + { + unsigned short sTypeRest=0; + short tX=baseAddr[8]; + short tY=baseAddr[9]; + + if(tX+sW>256) {sW=256-tX;sTypeRest+=1;} + if(tY+sH>256) {sH=256-tY;sTypeRest+=2;} + + DrawSoftwareSprite(baseAddr,sW,sH,tX,tY); + + if(sTypeRest) + { + if(sTypeRest&1) primSprtSRest(baseAddr,1); + if(sTypeRest&2) primSprtSRest(baseAddr,2); + if(sTypeRest==3) primSprtSRest(baseAddr,3); + } + + } + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: flat shaded Poly4 +//////////////////////////////////////////////////////////////////////// + +void primPolyF4(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[4]); + ly1 = GETLEs16(&sgpuData[5]); + lx2 = GETLEs16(&sgpuData[6]); + ly2 = GETLEs16(&sgpuData[7]); + lx3 = GETLEs16(&sgpuData[8]); + ly3 = GETLEs16(&sgpuData[9]); + + if(!(dwActFixes&8)) + { + AdjustCoord4(); + if(CheckCoord4()) return; + } + + offsetPSX4(); + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + drawPoly4F(GETLE32(&gpuData[0])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: smooth shaded Poly4 +//////////////////////////////////////////////////////////////////////// + +void primPolyG4(unsigned char * baseAddr) +{ + unsigned long *gpuData = (unsigned long *)baseAddr; + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[6]); + ly1 = GETLEs16(&sgpuData[7]); + lx2 = GETLEs16(&sgpuData[10]); + ly2 = GETLEs16(&sgpuData[11]); + lx3 = GETLEs16(&sgpuData[14]); + ly3 = GETLEs16(&sgpuData[15]); + + if(!(dwActFixes&8)) + { + AdjustCoord4(); + if(CheckCoord4()) return; + } + + offsetPSX4(); + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + drawPoly4G(GETLE32(&gpuData[0]), GETLE32(&gpuData[2]), + GETLE32(&gpuData[4]), GETLE32(&gpuData[6])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: flat shaded Texture3 +//////////////////////////////////////////////////////////////////////// + +void primPolyFT3(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[6]); + ly1 = GETLEs16(&sgpuData[7]); + lx2 = GETLEs16(&sgpuData[10]); + ly2 = GETLEs16(&sgpuData[11]); + + lLowerpart=GETLE32(&gpuData[4])>>16; + UpdateGlobalTP((unsigned short)lLowerpart); + + if(!(dwActFixes&8)) + { + AdjustCoord3(); + if(CheckCoord3()) return; + } + + offsetPSX3(); + SetRenderMode(GETLE32(&gpuData[0])); + + drawPoly3FT(baseAddr); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: flat shaded Texture4 +//////////////////////////////////////////////////////////////////////// + +void primPolyFT4(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[6]); + ly1 = GETLEs16(&sgpuData[7]); + lx2 = GETLEs16(&sgpuData[10]); + ly2 = GETLEs16(&sgpuData[11]); + lx3 = GETLEs16(&sgpuData[14]); + ly3 = GETLEs16(&sgpuData[15]); + + lLowerpart=GETLE32(&gpuData[4])>>16; + UpdateGlobalTP((unsigned short)lLowerpart); + + if(!(dwActFixes&8)) + { + AdjustCoord4(); + if(CheckCoord4()) return; + } + + offsetPSX4(); + + SetRenderMode(GETLE32(&gpuData[0])); + + drawPoly4FT(baseAddr); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: smooth shaded Texture3 +//////////////////////////////////////////////////////////////////////// + +void primPolyGT3(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[8]); + ly1 = GETLEs16(&sgpuData[9]); + lx2 = GETLEs16(&sgpuData[14]); + ly2 = GETLEs16(&sgpuData[15]); + + lLowerpart=GETLE32(&gpuData[5])>>16; + UpdateGlobalTP((unsigned short)lLowerpart); + + if(!(dwActFixes&8)) + { + AdjustCoord3(); + if(CheckCoord3()) return; + } + + offsetPSX3(); + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + if(SHADETEXBIT(GETLE32(&gpuData[0]))) + { + gpuData[0] = (gpuData[0]&SWAP32(0xff000000))|SWAP32(0x00808080); + gpuData[3] = (gpuData[3]&SWAP32(0xff000000))|SWAP32(0x00808080); + gpuData[6] = (gpuData[6]&SWAP32(0xff000000))|SWAP32(0x00808080); + } + + drawPoly3GT(baseAddr); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: smooth shaded Poly3 +//////////////////////////////////////////////////////////////////////// + +void primPolyG3(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[6]); + ly1 = GETLEs16(&sgpuData[7]); + lx2 = GETLEs16(&sgpuData[10]); + ly2 = GETLEs16(&sgpuData[11]); + + if(!(dwActFixes&8)) + { + AdjustCoord3(); + if(CheckCoord3()) return; + } + + offsetPSX3(); + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + drawPoly3G(GETLE32(&gpuData[0]), GETLE32(&gpuData[2]), GETLE32(&gpuData[4])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: smooth shaded Texture4 +//////////////////////////////////////////////////////////////////////// + +void primPolyGT4(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[8]); + ly1 = GETLEs16(&sgpuData[9]); + lx2 = GETLEs16(&sgpuData[14]); + ly2 = GETLEs16(&sgpuData[15]); + lx3 = GETLEs16(&sgpuData[20]); + ly3 = GETLEs16(&sgpuData[21]); + + lLowerpart=GETLE32(&gpuData[5])>>16; + UpdateGlobalTP((unsigned short)lLowerpart); + + if(!(dwActFixes&8)) + { + AdjustCoord4(); + if(CheckCoord4()) return; + } + + offsetPSX4(); + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + if(SHADETEXBIT(GETLE32(&gpuData[0]))) + { + gpuData[0] = (gpuData[0]&SWAP32(0xff000000))|SWAP32(0x00808080); + gpuData[3] = (gpuData[3]&SWAP32(0xff000000))|SWAP32(0x00808080); + gpuData[6] = (gpuData[6]&SWAP32(0xff000000))|SWAP32(0x00808080); + gpuData[9] = (gpuData[9]&SWAP32(0xff000000))|SWAP32(0x00808080); + } + + drawPoly4GT(baseAddr); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: smooth shaded Poly3 +//////////////////////////////////////////////////////////////////////// + +void primPolyF3(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[4]); + ly1 = GETLEs16(&sgpuData[5]); + lx2 = GETLEs16(&sgpuData[6]); + ly2 = GETLEs16(&sgpuData[7]); + + if(!(dwActFixes&8)) + { + AdjustCoord3(); + if(CheckCoord3()) return; + } + + offsetPSX3(); + SetRenderMode(GETLE32(&gpuData[0])); + + drawPoly3F(GETLE32(&gpuData[0])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: skipping shaded polylines +//////////////////////////////////////////////////////////////////////// + +void primLineGSkip(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + int iMax=255; + int i=2; + + ly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff); + lx1 = (short)(GETLE32(&gpuData[1]) & 0xffff); + + while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=4)) + { + i++; + ly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff); + lx1 = (short)(GETLE32(&gpuData[i]) & 0xffff); + i++;if(i>iMax) break; + } +} + +//////////////////////////////////////////////////////////////////////// +// cmd: shaded polylines +//////////////////////////////////////////////////////////////////////// + +void primLineGEx(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + int iMax=255; + unsigned long lc1; + short slx1,sly1;int i=2;BOOL bDraw=TRUE; + + sly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff); + slx1 = (short)(GETLE32(&gpuData[1]) & 0xffff); + + if(!(dwActFixes&8)) + { + slx1=(short)(((int)slx1<>SIGNSHIFT); + sly1=(short)(((int)sly1<>SIGNSHIFT); + } + + lc1 = gpuData[0] & 0xffffff; + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + + while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=4)) + { + short sly0=sly1; short slx0=slx1; unsigned long lc0=lc1; + lc1=GETLE32(&gpuData[i]) & 0xffffff; + + i++; + + // no check needed on gshaded polyline positions + // if((gpuData[i] & 0xF000F000) == 0x50005000) break; + + sly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff); + slx1 = (short)(GETLE32(&gpuData[i]) & 0xffff); + + if(!(dwActFixes&8)) + { + slx1=(short)(((int)slx1<>SIGNSHIFT); + sly1=(short)(((int)sly1<>SIGNSHIFT); + if(CheckCoordL(slx0,sly0,slx1,sly1)) bDraw=FALSE; else bDraw=TRUE; + } + + if ((lx0 != lx1) || (ly0 != ly1)) + { + ly0=sly0; + lx0=slx0; + ly1=sly1; + lx1=slx1; + + offsetPSX2(); + if(bDraw) DrawSoftwareLineShade(lc0, lc1); + } + i++; + if(i>iMax) break; + } + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: shaded polyline2 +//////////////////////////////////////////////////////////////////////// + +void primLineG2(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[6]); + ly1 = GETLEs16(&sgpuData[7]); + + if(!(dwActFixes&8)) + { + AdjustCoord2(); + if(CheckCoord2()) return; + } + + if((lx0 == lx1) && (ly0 == ly1)) {lx1++;ly1++;} + + DrawSemiTrans = (SEMITRANSBIT(GETLE32(&gpuData[0]))) ? TRUE : FALSE; + offsetPSX2(); + DrawSoftwareLineShade(GETLE32(&gpuData[0]),GETLE32(&gpuData[2])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: skipping flat polylines +//////////////////////////////////////////////////////////////////////// + +void primLineFSkip(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + int i=2,iMax=255; + + ly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff); + lx1 = (short)(GETLE32(&gpuData[1]) & 0xffff); + + while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=3)) + { + ly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff); + lx1 = (short)(GETLE32(&gpuData[i]) & 0xffff); + i++;if(i>iMax) break; + } +} + +//////////////////////////////////////////////////////////////////////// +// cmd: drawing flat polylines +//////////////////////////////////////////////////////////////////////// + +void primLineFEx(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + int iMax; + short slx1,sly1;int i=2;BOOL bDraw=TRUE; + + iMax=255; + + sly1 = (short)((GETLE32(&gpuData[1])>>16) & 0xffff); + slx1 = (short)(GETLE32(&gpuData[1]) & 0xffff); + if(!(dwActFixes&8)) + { + slx1=(short)(((int)slx1<>SIGNSHIFT); + sly1=(short)(((int)sly1<>SIGNSHIFT); + } + + SetRenderMode(GETLE32(&gpuData[0])); + + while(!(((GETLE32(&gpuData[i]) & 0xF000F000) == 0x50005000) && i>=3)) + { + short sly0 = sly1;short slx0=slx1; + sly1 = (short)((GETLE32(&gpuData[i])>>16) & 0xffff); + slx1 = (short)(GETLE32(&gpuData[i]) & 0xffff); + if(!(dwActFixes&8)) + { + slx1=(short)(((int)slx1<>SIGNSHIFT); + sly1=(short)(((int)sly1<>SIGNSHIFT); + + if(CheckCoordL(slx0,sly0,slx1,sly1)) bDraw=FALSE; else bDraw=TRUE; + } + + ly0=sly0; + lx0=slx0; + ly1=sly1; + lx1=slx1; + + offsetPSX2(); + if(bDraw) DrawSoftwareLineFlat(GETLE32(&gpuData[0])); + + i++;if(i>iMax) break; + } + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: drawing flat polyline2 +//////////////////////////////////////////////////////////////////////// + +void primLineF2(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + short *sgpuData = ((short *) baseAddr); + + lx0 = GETLEs16(&sgpuData[2]); + ly0 = GETLEs16(&sgpuData[3]); + lx1 = GETLEs16(&sgpuData[4]); + ly1 = GETLEs16(&sgpuData[5]); + + if(!(dwActFixes&8)) + { + AdjustCoord2(); + if(CheckCoord2()) return; + } + + if((lx0 == lx1) && (ly0 == ly1)) {lx1++;ly1++;} + + offsetPSX2(); + SetRenderMode(GETLE32(&gpuData[0])); + + DrawSoftwareLineFlat(GETLE32(&gpuData[0])); + + bDoVSyncUpdate=TRUE; +} + +//////////////////////////////////////////////////////////////////////// +// cmd: well, easiest command... not implemented +//////////////////////////////////////////////////////////////////////// + +void primNI(unsigned char *bA) +{ +} + +//////////////////////////////////////////////////////////////////////// +// cmd func ptr table +//////////////////////////////////////////////////////////////////////// + + +void (*primTableJ[256])(unsigned char *) = +{ + // 00 + primNI,primNI,primBlkFill,primNI,primNI,primNI,primNI,primNI, + // 08 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 10 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 18 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 20 + primPolyF3,primPolyF3,primPolyF3,primPolyF3,primPolyFT3,primPolyFT3,primPolyFT3,primPolyFT3, + // 28 + primPolyF4,primPolyF4,primPolyF4,primPolyF4,primPolyFT4,primPolyFT4,primPolyFT4,primPolyFT4, + // 30 + primPolyG3,primPolyG3,primPolyG3,primPolyG3,primPolyGT3,primPolyGT3,primPolyGT3,primPolyGT3, + // 38 + primPolyG4,primPolyG4,primPolyG4,primPolyG4,primPolyGT4,primPolyGT4,primPolyGT4,primPolyGT4, + // 40 + primLineF2,primLineF2,primLineF2,primLineF2,primNI,primNI,primNI,primNI, + // 48 + primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx,primLineFEx, + // 50 + primLineG2,primLineG2,primLineG2,primLineG2,primNI,primNI,primNI,primNI, + // 58 + primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx,primLineGEx, + // 60 + primTileS,primTileS,primTileS,primTileS,primSprtS,primSprtS,primSprtS,primSprtS, + // 68 + primTile1,primTile1,primTile1,primTile1,primNI,primNI,primNI,primNI, + // 70 + primTile8,primTile8,primTile8,primTile8,primSprt8,primSprt8,primSprt8,primSprt8, + // 78 + primTile16,primTile16,primTile16,primTile16,primSprt16,primSprt16,primSprt16,primSprt16, + // 80 + primMoveImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 88 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 90 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 98 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // a0 + primLoadImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // a8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // b0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // b8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // c0 + primStoreImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // c8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // d0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // d8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // e0 + primNI,cmdTexturePage,cmdTextureWindow,cmdDrawAreaStart,cmdDrawAreaEnd,cmdDrawOffset,cmdSTP,primNI, + // e8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // f0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // f8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI +}; + +//////////////////////////////////////////////////////////////////////// +// cmd func ptr table for skipping +//////////////////////////////////////////////////////////////////////// + +void (*primTableSkip[256])(unsigned char *) = +{ + // 00 + primNI,primNI,primBlkFill,primNI,primNI,primNI,primNI,primNI, + // 08 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 10 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 18 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 20 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 28 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 30 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 38 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 40 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 48 + primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip,primLineFSkip, + // 50 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 58 + primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip,primLineGSkip, + // 60 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 68 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 70 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 78 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 80 + primMoveImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 88 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 90 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // 98 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // a0 + primLoadImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // a8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // b0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // b8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // c0 + primStoreImage,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // c8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // d0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // d8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // e0 + primNI,cmdTexturePage,cmdTextureWindow,cmdDrawAreaStart,cmdDrawAreaEnd,cmdDrawOffset,cmdSTP,primNI, + // e8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // f0 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI, + // f8 + primNI,primNI,primNI,primNI,primNI,primNI,primNI,primNI +}; diff --git a/PeopsSoftGPU/prim.h b/PeopsSoftGPU/prim.h new file mode 100644 index 0000000..8e61f7d --- /dev/null +++ b/PeopsSoftGPU/prim.h @@ -0,0 +1,33 @@ +/*************************************************************************** + prim.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _PRIMDRAW_H_ +#define _PRIMDRAW_H_ + +void UploadScreen (long Position); +void PrepareFullScreenUpload (long Position); + +#endif // _PRIMDRAW_H_ diff --git a/PeopsSoftGPU/psemu.h b/PeopsSoftGPU/psemu.h new file mode 100644 index 0000000..ec76b02 --- /dev/null +++ b/PeopsSoftGPU/psemu.h @@ -0,0 +1,36 @@ +/*************************************************************************** + psemu.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _PSEMU_PLUGIN_DEFS_H +#define _PSEMU_PLUGIN_DEFS_H + +// plugin type returned by PSEgetLibType +#define PSE_LT_CDR 1 +#define PSE_LT_GPU 2 +#define PSE_LT_SPU 4 + + +#endif // _PSEMU_PLUGIN_DEFS_H diff --git a/PeopsSoftGPU/sdk.h b/PeopsSoftGPU/sdk.h new file mode 100644 index 0000000..a4133a3 --- /dev/null +++ b/PeopsSoftGPU/sdk.h @@ -0,0 +1,129 @@ +#ifndef _SDK_H_ +#define _SDK_H_ + +typedef void (*FPSE_CallBack_Type)(void); + +// CDROM section +//------------------------------------------------------------ + +UINT8 *CD_Read(UINT8 *param); +int CD_Play(UINT8 *param); +int CD_Stop(void); +int CD_GetTD(UINT8 *result,int track); +int CD_GetTN(UINT8 *result); +int CD_Open(UINT32 *par); +void CD_Close(void); +int CD_Wait(void); + +// High level functions +int CD_Configure(UINT32 *par); +void CD_About(UINT32 *par); + + +// GPU section +//------------------------------------------------------------ + +typedef struct { + int dummy; +} GPU_State; + +int GPU_Open(UINT32 *gpu); +void GPU_Close(void); + +UINT32 GP0_Read(void); +UINT32 GP1_Read(void); +void GP0_Write(UINT32 data); +void GP1_Write(UINT32 code); + +void GPU_Update(void); + +void GPU_DmaExec(UINT32 adr,UINT32 bcr,UINT32 chcr); + +void GPU_ScreenShot(char *path); + +int GPU_Configure(UINT32 *par); +void GPU_About(UINT32 *par); + +void GPU_LoadState(GPU_State *state); +void GPU_SaveState(GPU_State *state); + +// SPU section +//------------------------------------------------------------ + +typedef struct { + int dummy; +} SPU_State; + +int SPU_Open(UINT32 *spu); +void SPU_Close(void); + +int SPU_Read(UINT32 adr); +void SPU_Write(UINT32 adr, unsigned int data); + +void SPU_DmaExec(UINT32 adr,UINT32 bcr,UINT32 chcr); + +int SPU_Configure(UINT32 *par); +void SPU_About(UINT32 *par); + +void SPU_PlayStream(INT16 *XAsampleBuf, int freq, int chns); + +void SPU_LoadState(SPU_State *state); +void SPU_SaveState(SPU_State *state); + +FPSE_CallBack_Type SPU_GetCallBack(void); + +// CONTROLLERS section +//------------------------------------------------------------ + +typedef struct { + int dummy; +} JOY_State; + +#define ACK_OK 1 +#define ACK_ERR 0 + +int JOY0_Open(UINT32 *joy); +void JOY0_Close(void); +void JOY0_SetOutputBuffer(UINT8 *buf); +int JOY0_StartPoll(void); +int JOY0_Poll(int outbyte); +void JOY0_LoadState(JOY_State *state); +void JOY0_SaveState(JOY_State *state); +int JOY0_Configure(UINT32 *par); +void JOY0_About(UINT32 *par); + +int JOY1_Open(UINT32 *joy); +void JOY1_Close(void); +void JOY1_SetOutputBuffer(UINT8 *buf); +int JOY1_StartPoll(void); +int JOY1_Poll(int outbyte); +void JOY1_LoadState(JOY_State *state); +void JOY1_SaveState(JOY_State *state); +int JOY1_Configure(UINT32 *par); +void JOY1_About(UINT32 *par); + + +// PARALLEL port section +//------------------------------------------------------------ + +typedef struct { + int dummy; +} PAR_State; + +int PAR_Open(UINT32 *par); +void PAR_Close(void); + +int PAR_Read(UINT32 adr); +void PAR_Write(UINT32 adr, unsigned int data); + +void PAR_DmaExec(UINT32 adr,UINT32 bcr,UINT32 chcr); + +int PAR_Configure(UINT32 *par); +void PAR_About(UINT32 *par); + +void PAR_LoadState(PAR_State *state); +void PAR_SaveState(PAR_State *state); + +FPSE_CallBack_Type PAR_GetCallBack(void); + +#endif diff --git a/PeopsSoftGPU/soft.c b/PeopsSoftGPU/soft.c new file mode 100644 index 0000000..0ebaf07 --- /dev/null +++ b/PeopsSoftGPU/soft.c @@ -0,0 +1,7498 @@ +/*************************************************************************** + soft.c - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2005/06/11 - Pete +// - added y sprite mirror +// +// 2005/04/15 - Pete +// - gamefix 0x200 controls g-shaded quads now +// +// 2005/04/12 - Pete +// - 25% blending mode 3 +// +// 2004/02/01 - Pete +// - added ZN stuff... Tekken "IL" texture decoding infos kindly given by smf from the MAME team +// +// 2003/08/30 - Pete +// - added game fix 0x100 (dark forces) +// +// 2002/10/03 - Farfetch'd & Pete +// - changed: mask bit handling +// +// 2002/06/04 - Lewpy +// - new line drawing funcs +// +// 2002/05/24 - Pete +// - added additional handling for tex quads to avoid texture distortions +// +// 2002/05/14 - Pete +// - redone all texture window funcs... much faster now +// +// 2002/05/12 - Pete +// - Mask bit fix on non-textured/sprite prims +// +// 2002/03/27 - Pete +// - doom adjustment +// +// 2002/02/12 - Pete +// - removed "no sprite transparency" fix +// +// 2001/12/14 - Pete +// - added support for 15 bit texture window primitives +// +// 2001/12/10 - Pete +// - fixed a mask bit bug in drawPoly4F, causing troubles in MGS +// +// 2001/11/08 - Linuzappz +// - shl10idiv converted to nasm, C version still works :define __i386_ +// to use the asm version +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#include "stdafx.h" + +#include "../Gamecube/DEBUG.h" + +#define _IN_SOFT + +#include "externals.h" +#include "soft.h" + +//#define VC_INLINE +#include "gpu.h" +#include "prim.h" +#include "menu.h" +#include "swap.h" + + +//////////////////////////////////////////////////////////////////////////////////// +// "NO EDGE BUFFER" POLY VERSION... FUNCS BASED ON FATMAP.TXT FROM MRI / Doomsday +//////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////// +// defines +//////////////////////////////////////////////////////////////////////////////////// + +// switches for painting textured quads as 2 triangles (small glitches, but better shading!) +// can be toggled by game fix 0x200 in version 1.17 anyway, so let the defines enabled! + +#define POLYQUAD3 +#define POLYQUAD3GT + +// fast solid loops... a bit more additional code, of course + +#define FASTSOLID + +// psx blending mode 3 with 25% incoming color (instead 50% without the define) + +#define HALFBRIGHTMODE3 + +// color decode defines + +#define XCOL1(x) (x & 0x1f) +#define XCOL2(x) (x & 0x3e0) +#define XCOL3(x) (x & 0x7c00) + +#define XCOL1D(x) (x & 0x1f) +#define XCOL2D(x) ((x>>5) & 0x1f) +#define XCOL3D(x) ((x>>10) & 0x1f) + +#define X32TCOL1(x) ((x & 0x001f001f)<<7) +#define X32TCOL2(x) ((x & 0x03e003e0)<<2) +#define X32TCOL3(x) ((x & 0x7c007c00)>>3) + +#define X32COL1(x) (x & 0x001f001f) +#define X32COL2(x) ((x>>5) & 0x001f001f) +#define X32COL3(x) ((x>>10) & 0x001f001f) + +#define X32ACOL1(x) (x & 0x001e001e) +#define X32ACOL2(x) ((x>>5) & 0x001e001e) +#define X32ACOL3(x) ((x>>10) & 0x001e001e) + +#define X32BCOL1(x) (x & 0x001c001c) +#define X32BCOL2(x) ((x>>5) & 0x001c001c) +#define X32BCOL3(x) ((x>>10) & 0x001c001c) + +#define X32PSXCOL(r,g,b) ((g<<10)|(b<<5)|r) + +#define XPSXCOL(r,g,b) ((g&0x7c00)|(b&0x3e0)|(r&0x1f)) + +//////////////////////////////////////////////////////////////////////////////////// +// soft globals +//////////////////////////////////////////////////////////////////////////////////// + +short g_m1=255,g_m2=255,g_m3=255; +short DrawSemiTrans=FALSE; +short Ymin; +short Ymax; + +short ly0,lx0,ly1,lx1,ly2,lx2,ly3,lx3; // global psx vertex coords +long GlobalTextAddrX,GlobalTextAddrY,GlobalTextTP; +long GlobalTextREST,GlobalTextABR,GlobalTextPAGE; + +//////////////////////////////////////////////////////////////////////// +// POLYGON OFFSET FUNCS +//////////////////////////////////////////////////////////////////////// + +void offsetPSXLine(void) +{ + short x0,x1,y0,y1,dx,dy;float px,py; + + x0 = lx0+1+PSXDisplay.DrawOffset.x; + x1 = lx1+1+PSXDisplay.DrawOffset.x; + y0 = ly0+1+PSXDisplay.DrawOffset.y; + y1 = ly1+1+PSXDisplay.DrawOffset.y; + + dx=x1-x0; + dy=y1-y0; + + // tricky line width without sqrt + + if(dx>=0) + { + if(dy>=0) + { + px=0.5f; + if(dx>dy) py=-0.5f; + else if(dxdy) px= 0.5f; + else if(dx=0) + { + py=0.5f; + dx=-dx; + if(dx>dy) px=-0.5f; + else if(dxdy) py=-0.5f; + else if(dx>10; + x-=(y<<10); + + coeff = dithertable[(y&3)*4+(x&3)]; + + rlow = r&7; glow = g&7; blow = b&7; + + r>>=3; g>>=3; b>>=3; + + if ((r < 0x1F) && rlow > coeff) r++; + if ((g < 0x1F) && glow > coeff) g++; + if ((b < 0x1F) && blow > coeff) b++; + + PUTLE16(pdest, ((unsigned short)b<<10) | + ((unsigned short)g<<5) | + (unsigned short)r | sM); +} + +///////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////// + +//__inline__ void GetShadeTransCol_Dither(unsigned short * pdest,long m1,long m2,long m3) __attribute__ ((__pure__)); +__inline__ void GetShadeTransCol_Dither(unsigned short * pdest,long m1,long m2,long m3) +{ + long r,g,b; + + if(bCheckMask && (*pdest & HOST2LE16(0x8000))) return; + + if(DrawSemiTrans) + { + r=((XCOL1D(GETLE16(pdest)))<<3); + b=((XCOL2D(GETLE16(pdest)))<<3); + g=((XCOL3D(GETLE16(pdest)))<<3); + + if(GlobalTextABR==0) + { + r=(r>>1)+(m1>>1); + b=(b>>1)+(m2>>1); + g=(g>>1)+(m3>>1); + } + else + if(GlobalTextABR==1) + { + r+=m1; + b+=m2; + g+=m3; + } + else + if(GlobalTextABR==2) + { + r-=m1; + b-=m2; + g-=m3; + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r+=(m1>>2); + b+=(m2>>2); + g+=(m3>>2); +#else + r+=(m1>>1); + b+=(m2>>1); + g+=(m3>>1); +#endif + } + } + else + { + r=m1; + b=m2; + g=m3; + } + + if(r&0x7FFFFF00) r=0xff; + if(b&0x7FFFFF00) b=0xff; + if(g&0x7FFFFF00) g=0xff; + + Dither16(pdest,r,b,g,sSetMask); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetShadeTransCol(unsigned short * pdest,unsigned short color) __attribute__ ((__pure__)); +__inline__ void GetShadeTransCol(unsigned short * pdest,unsigned short color) +{ + if(bCheckMask && (*pdest & HOST2LE16(0x8000))) return; + + if(DrawSemiTrans) + { + long r,g,b; + + if(GlobalTextABR==0) + { + PUTLE16(pdest, (((GETLE16(pdest)&0x7bde)>>1)+(((color)&0x7bde)>>1))|sSetMask);//0x8000; + return; +/* + r=(XCOL1(*pdest)>>1)+((XCOL1(color))>>1); + b=(XCOL2(*pdest)>>1)+((XCOL2(color))>>1); + g=(XCOL3(*pdest)>>1)+((XCOL3(color))>>1); +*/ + } + else + if(GlobalTextABR==1) + { + r=(XCOL1(GETLE16(pdest)))+((XCOL1(color))); + b=(XCOL2(GETLE16(pdest)))+((XCOL2(color))); + g=(XCOL3(GETLE16(pdest)))+((XCOL3(color))); + } + else + if(GlobalTextABR==2) + { + r=(XCOL1(GETLE16(pdest)))-((XCOL1(color))); + b=(XCOL2(GETLE16(pdest)))-((XCOL2(color))); + g=(XCOL3(GETLE16(pdest)))-((XCOL3(color))); + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(XCOL1(GETLE16(pdest)))+((XCOL1(color))>>2); + b=(XCOL2(GETLE16(pdest)))+((XCOL2(color))>>2); + g=(XCOL3(GETLE16(pdest)))+((XCOL3(color))>>2); +#else + r=(XCOL1(GETLE16(pdest)))+((XCOL1(color))>>1); + b=(XCOL2(GETLE16(pdest)))+((XCOL2(color))>>1); + g=(XCOL3(GETLE16(pdest)))+((XCOL3(color))>>1); +#endif + } + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|sSetMask);//0x8000; + } + else PUTLE16(pdest, color|sSetMask); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetShadeTransCol32(unsigned long * pdest,unsigned long color) __attribute__ ((__pure__)); +__inline__ void GetShadeTransCol32(unsigned long * pdest,unsigned long color) +{ + if(DrawSemiTrans) + { + long r,g,b; + + if(GlobalTextABR==0) + { + if(!bCheckMask) + { + PUTLE32(pdest, (((GETLE32(pdest)&0x7bde7bde)>>1)+(((color)&0x7bde7bde)>>1))|lSetMask);//0x80008000; + return; + } + r=(X32ACOL1(GETLE32(pdest))>>1)+((X32ACOL1(color))>>1); + b=(X32ACOL2(GETLE32(pdest))>>1)+((X32ACOL2(color))>>1); + g=(X32ACOL3(GETLE32(pdest))>>1)+((X32ACOL3(color))>>1); + } + else + if(GlobalTextABR==1) + { + r=(X32COL1(GETLE32(pdest)))+((X32COL1(color))); + b=(X32COL2(GETLE32(pdest)))+((X32COL2(color))); + g=(X32COL3(GETLE32(pdest)))+((X32COL3(color))); + } + else + if(GlobalTextABR==2) + { + long sr,sb,sg,src,sbc,sgc,c; + src=XCOL1(color);sbc=XCOL2(color);sgc=XCOL3(color); + c=GETLE32(pdest)>>16; + sr=(XCOL1(c))-src; if(sr&0x8000) sr=0; + sb=(XCOL2(c))-sbc; if(sb&0x8000) sb=0; + sg=(XCOL3(c))-sgc; if(sg&0x8000) sg=0; + r=((long)sr)<<16;b=((long)sb)<<11;g=((long)sg)<<6; + c=LOWORD(GETLE32(pdest)); + sr=(XCOL1(c))-src; if(sr&0x8000) sr=0; + sb=(XCOL2(c))-sbc; if(sb&0x8000) sb=0; + sg=(XCOL3(c))-sgc; if(sg&0x8000) sg=0; + r|=sr;b|=sb>>5;g|=sg>>10; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(X32COL1(GETLE32(pdest)))+((X32BCOL1(color))>>2); + b=(X32COL2(GETLE32(pdest)))+((X32BCOL2(color))>>2); + g=(X32COL3(GETLE32(pdest)))+((X32BCOL3(color))>>2); +#else + r=(X32COL1(GETLE32(pdest)))+((X32ACOL1(color))>>1); + b=(X32COL2(GETLE32(pdest)))+((X32ACOL2(color))>>1); + g=(X32COL3(GETLE32(pdest)))+((X32ACOL3(color))>>1); +#endif + } + + if(r&0x7FE00000) r=0x1f0000|(r&0xFFFF); + if(r&0x7FE0) r=0x1f |(r&0xFFFF0000); + if(b&0x7FE00000) b=0x1f0000|(b&0xFFFF); + if(b&0x7FE0) b=0x1f |(b&0xFFFF0000); + if(g&0x7FE00000) g=0x1f0000|(g&0xFFFF); + if(g&0x7FE0) g=0x1f |(g&0xFFFF0000); + + if(bCheckMask) + { + unsigned long ma=GETLE32(pdest); + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask); + // This is Gil's version + //if(ma&0x80000000) PUTLE32(pdest, (ma&0xFFFF0000)|(*pdest&0xFFFF)); + //if(ma&0x00008000) PUTLE32(pdest, (ma&0xFFFF) |(*pdest&0xFFFF0000)); + // TODO: Figure out if the following is correct: + if(ma&0x80000000) PUTLE32(pdest, (ma&0xFFFF0000)|(GETLE32(pdest)&0xFFFF)); + if(ma&0x00008000) PUTLE32(pdest, (ma&0xFFFF) |(GETLE32(pdest)&0xFFFF0000)); + // End TODO + return; + } + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask);//0x80008000; + } + else + { + if(bCheckMask) + { + unsigned long ma=GETLE32(pdest); + PUTLE32(pdest, color|lSetMask); + if(ma&0x80000000) PUTLE32(pdest, (ma&0xFFFF0000)|(GETLE32(pdest)&0xFFFF)); + if(ma&0x00008000) PUTLE32(pdest, (ma&0xFFFF) |(GETLE32(pdest)&0xFFFF0000)); + return; + } + + PUTLE32(pdest, color|lSetMask); + } +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG(unsigned short * pdest,unsigned short color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG(unsigned short * pdest,unsigned short color) +{ + long r,g,b;unsigned short l; + + if(color==0) return; + + if(bCheckMask && (*pdest & HOST2LE16(0x8000))) return; + + l=sSetMask|(color&0x8000); + + if(DrawSemiTrans && (color&0x8000)) + { + if(GlobalTextABR==0) + { + unsigned short d; + d =(GETLE16(pdest)&0x7bde)>>1; + color =((color) &0x7bde)>>1; + r=(XCOL1(d))+((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(d))+((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(d))+((((XCOL3(color)))* g_m3)>>7); + +/* + r=(XCOL1(*pdest)>>1)+((((XCOL1(color))>>1)* g_m1)>>7); + b=(XCOL2(*pdest)>>1)+((((XCOL2(color))>>1)* g_m2)>>7); + g=(XCOL3(*pdest)>>1)+((((XCOL3(color))>>1)* g_m3)>>7); +*/ + } + else + if(GlobalTextABR==1) + { + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color)))* g_m3)>>7); + } + else + if(GlobalTextABR==2) + { + r=(XCOL1(GETLE16(pdest)))-((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))-((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))-((((XCOL3(color)))* g_m3)>>7); + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>2)* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>2)* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>2)* g_m3)>>7); +#else + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>1)* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>1)* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>1)* g_m3)>>7); +#endif + } + } + else + { + r=((XCOL1(color))* g_m1)>>7; + b=((XCOL2(color))* g_m2)>>7; + g=((XCOL3(color))* g_m3)>>7; + } + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|l); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG_S(unsigned short * pdest,unsigned short color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG_S(unsigned short * pdest,unsigned short color) +{ + long r,g,b;unsigned short l; + + if(color==0) return; + + l=sSetMask|(color&0x8000); + + r=((XCOL1(color))* g_m1)>>7; + b=((XCOL2(color))* g_m2)>>7; + g=((XCOL3(color))* g_m3)>>7; + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|l); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG_SPR(unsigned short * pdest,unsigned short color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG_SPR(unsigned short * pdest,unsigned short color) +{ + long r,g,b;unsigned short l; + + if(color==0) return; + + if(bCheckMask && (GETLE16(pdest) & 0x8000)) return; + + l=sSetMask|(color&0x8000); + + if(DrawSemiTrans && (color&0x8000)) + { + if(GlobalTextABR==0) + { + unsigned short d; + d =(GETLE16(pdest)&0x7bde)>>1; + color =((color) &0x7bde)>>1; + r=(XCOL1(d))+((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(d))+((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(d))+((((XCOL3(color)))* g_m3)>>7); + +/* + r=(XCOL1(*pdest)>>1)+((((XCOL1(color))>>1)* g_m1)>>7); + b=(XCOL2(*pdest)>>1)+((((XCOL2(color))>>1)* g_m2)>>7); + g=(XCOL3(*pdest)>>1)+((((XCOL3(color))>>1)* g_m3)>>7); +*/ + } + else + if(GlobalTextABR==1) + { + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color)))* g_m3)>>7); + } + else + if(GlobalTextABR==2) + { + r=(XCOL1(GETLE16(pdest)))-((((XCOL1(color)))* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))-((((XCOL2(color)))* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))-((((XCOL3(color)))* g_m3)>>7); + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>2)* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>2)* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>2)* g_m3)>>7); +#else + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>1)* g_m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>1)* g_m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>1)* g_m3)>>7); +#endif + } + } + else + { + r=((XCOL1(color))* g_m1)>>7; + b=((XCOL2(color))* g_m2)>>7; + g=((XCOL3(color))* g_m3)>>7; + } + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|l); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG32(unsigned long * pdest,unsigned long color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG32(unsigned long * pdest,unsigned long color) +{ + long r,g,b,l; + + if(color==0) return; + + l=lSetMask|(color&0x80008000); + + if(DrawSemiTrans && (color&0x80008000)) + { + if(GlobalTextABR==0) + { + r=((((X32TCOL1(GETLE32(pdest)))+((X32COL1(color)) * g_m1))&0xFF00FF00)>>8); + b=((((X32TCOL2(GETLE32(pdest)))+((X32COL2(color)) * g_m2))&0xFF00FF00)>>8); + g=((((X32TCOL3(GETLE32(pdest)))+((X32COL3(color)) * g_m3))&0xFF00FF00)>>8); + } + else + if(GlobalTextABR==1) + { + r=(X32COL1(GETLE32(pdest)))+(((((X32COL1(color)))* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32COL2(color)))* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32COL3(color)))* g_m3)&0xFF80FF80)>>7); + } + else + if(GlobalTextABR==2) + { + long t; + r=(((((X32COL1(color)))* g_m1)&0xFF80FF80)>>7); + t=(GETLE32(pdest)&0x001f0000)-(r&0x003f0000); if(t&0x80000000) t=0; + r=(GETLE32(pdest)&0x0000001f)-(r&0x0000003f); if(r&0x80000000) r=0; + r|=t; + + b=(((((X32COL2(color)))* g_m2)&0xFF80FF80)>>7); + t=((GETLE32(pdest)>>5)&0x001f0000)-(b&0x003f0000); if(t&0x80000000) t=0; + b=((GETLE32(pdest)>>5)&0x0000001f)-(b&0x0000003f); if(b&0x80000000) b=0; + b|=t; + + g=(((((X32COL3(color)))* g_m3)&0xFF80FF80)>>7); + t=((GETLE32(pdest)>>10)&0x001f0000)-(g&0x003f0000); if(t&0x80000000) t=0; + g=((GETLE32(pdest)>>10)&0x0000001f)-(g&0x0000003f); if(g&0x80000000) g=0; + g|=t; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(X32COL1(GETLE32(pdest)))+(((((X32BCOL1(color))>>2)* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32BCOL2(color))>>2)* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32BCOL3(color))>>2)* g_m3)&0xFF80FF80)>>7); +#else + r=(X32COL1(GETLE32(pdest)))+(((((X32ACOL1(color))>>1)* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32ACOL2(color))>>1)* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32ACOL3(color))>>1)* g_m3)&0xFF80FF80)>>7); +#endif + } + + if(!(color&0x8000)) + { + r=(r&0xffff0000)|((((X32COL1(color))* g_m1)&0x0000FF80)>>7); + b=(b&0xffff0000)|((((X32COL2(color))* g_m2)&0x0000FF80)>>7); + g=(g&0xffff0000)|((((X32COL3(color))* g_m3)&0x0000FF80)>>7); + } + if(!(color&0x80000000)) + { + r=(r&0xffff)|((((X32COL1(color))* g_m1)&0xFF800000)>>7); + b=(b&0xffff)|((((X32COL2(color))* g_m2)&0xFF800000)>>7); + g=(g&0xffff)|((((X32COL3(color))* g_m3)&0xFF800000)>>7); + } + + } + else + { + r=(((X32COL1(color))* g_m1)&0xFF80FF80)>>7; + b=(((X32COL2(color))* g_m2)&0xFF80FF80)>>7; + g=(((X32COL3(color))* g_m3)&0xFF80FF80)>>7; + } + + if(r&0x7FE00000) r=0x1f0000|(r&0xFFFF); + if(r&0x7FE0) r=0x1f |(r&0xFFFF0000); + if(b&0x7FE00000) b=0x1f0000|(b&0xFFFF); + if(b&0x7FE0) b=0x1f |(b&0xFFFF0000); + if(g&0x7FE00000) g=0x1f0000|(g&0xFFFF); + if(g&0x7FE0) g=0x1f |(g&0xFFFF0000); + + if(bCheckMask) + { + unsigned long ma=GETLE32(pdest); + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|l); + + if((color&0xffff)==0 ) PUTLE32(pdest, (ma&0xffff)|(GETLE32(pdest)&0xffff0000)); + if((color&0xffff0000)==0) PUTLE32(pdest, (ma&0xffff0000)|(GETLE32(pdest)&0xffff)); + if(ma&0x80000000) PUTLE32(pdest, (ma&0xFFFF0000)|(GETLE32(pdest)&0xFFFF)); + if(ma&0x00008000) PUTLE32(pdest, (ma&0xFFFF) |(GETLE32(pdest)&0xFFFF0000)); + + return; + } + if((color&0xffff)==0 ) {PUTLE32(pdest, (GETLE32(pdest)&0xffff)|(((X32PSXCOL(r,g,b))|l)&0xffff0000));return;} + if((color&0xffff0000)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff0000)|(((X32PSXCOL(r,g,b))|l)&0xffff));return;} + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|l); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG32_S(unsigned long * pdest,unsigned long color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG32_S(unsigned long * pdest,unsigned long color) +{ + long r,g,b; + + if(color==0) return; + + r=(((X32COL1(color))* g_m1)&0xFF80FF80)>>7; + b=(((X32COL2(color))* g_m2)&0xFF80FF80)>>7; + g=(((X32COL3(color))* g_m3)&0xFF80FF80)>>7; + + if(r&0x7FE00000) r=0x1f0000|(r&0xFFFF); + if(r&0x7FE0) r=0x1f |(r&0xFFFF0000); + if(b&0x7FE00000) b=0x1f0000|(b&0xFFFF); + if(b&0x7FE0) b=0x1f |(b&0xFFFF0000); + if(g&0x7FE00000) g=0x1f0000|(g&0xFFFF); + if(g&0x7FE0) g=0x1f |(g&0xFFFF0000); + + if((color&0xffff)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff0000));return;} + if((color&0xffff0000)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff0000)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff));return;} + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000)); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColG32_SPR(unsigned long * pdest,unsigned long color) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColG32_SPR(unsigned long * pdest,unsigned long color) +{ + long r,g,b; + + if(color==0) return; + + if(DrawSemiTrans && (color&0x80008000)) + { + if(GlobalTextABR==0) + { + r=((((X32TCOL1(GETLE32(pdest)))+((X32COL1(color)) * g_m1))&0xFF00FF00)>>8); + b=((((X32TCOL2(GETLE32(pdest)))+((X32COL2(color)) * g_m2))&0xFF00FF00)>>8); + g=((((X32TCOL3(GETLE32(pdest)))+((X32COL3(color)) * g_m3))&0xFF00FF00)>>8); + } + else + if(GlobalTextABR==1) + { + r=(X32COL1(GETLE32(pdest)))+(((((X32COL1(color)))* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32COL2(color)))* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32COL3(color)))* g_m3)&0xFF80FF80)>>7); + } + else + if(GlobalTextABR==2) + { + long t; + r=(((((X32COL1(color)))* g_m1)&0xFF80FF80)>>7); + t=(GETLE32(pdest)&0x001f0000)-(r&0x003f0000); if(t&0x80000000) t=0; + r=(GETLE32(pdest)&0x0000001f)-(r&0x0000003f); if(r&0x80000000) r=0; + r|=t; + + b=(((((X32COL2(color)))* g_m2)&0xFF80FF80)>>7); + t=((GETLE32(pdest)>>5)&0x001f0000)-(b&0x003f0000); if(t&0x80000000) t=0; + b=((GETLE32(pdest)>>5)&0x0000001f)-(b&0x0000003f); if(b&0x80000000) b=0; + b|=t; + + g=(((((X32COL3(color)))* g_m3)&0xFF80FF80)>>7); + t=((GETLE32(pdest)>>10)&0x001f0000)-(g&0x003f0000); if(t&0x80000000) t=0; + g=((GETLE32(pdest)>>10)&0x0000001f)-(g&0x0000003f); if(g&0x80000000) g=0; + g|=t; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(X32COL1(GETLE32(pdest)))+(((((X32BCOL1(color))>>2)* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32BCOL2(color))>>2)* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32BCOL3(color))>>2)* g_m3)&0xFF80FF80)>>7); +#else + r=(X32COL1(GETLE32(pdest)))+(((((X32ACOL1(color))>>1)* g_m1)&0xFF80FF80)>>7); + b=(X32COL2(GETLE32(pdest)))+(((((X32ACOL2(color))>>1)* g_m2)&0xFF80FF80)>>7); + g=(X32COL3(GETLE32(pdest)))+(((((X32ACOL3(color))>>1)* g_m3)&0xFF80FF80)>>7); +#endif + } + + if(!(color&0x8000)) + { + r=(r&0xffff0000)|((((X32COL1(color))* g_m1)&0x0000FF80)>>7); + b=(b&0xffff0000)|((((X32COL2(color))* g_m2)&0x0000FF80)>>7); + g=(g&0xffff0000)|((((X32COL3(color))* g_m3)&0x0000FF80)>>7); + } + if(!(color&0x80000000)) + { + r=(r&0xffff)|((((X32COL1(color))* g_m1)&0xFF800000)>>7); + b=(b&0xffff)|((((X32COL2(color))* g_m2)&0xFF800000)>>7); + g=(g&0xffff)|((((X32COL3(color))* g_m3)&0xFF800000)>>7); + } + + } + else + { + r=(((X32COL1(color))* g_m1)&0xFF80FF80)>>7; + b=(((X32COL2(color))* g_m2)&0xFF80FF80)>>7; + g=(((X32COL3(color))* g_m3)&0xFF80FF80)>>7; + } + + if(r&0x7FE00000) r=0x1f0000|(r&0xFFFF); + if(r&0x7FE0) r=0x1f |(r&0xFFFF0000); + if(b&0x7FE00000) b=0x1f0000|(b&0xFFFF); + if(b&0x7FE0) b=0x1f |(b&0xFFFF0000); + if(g&0x7FE00000) g=0x1f0000|(g&0xFFFF); + if(g&0x7FE0) g=0x1f |(g&0xFFFF0000); + + if(bCheckMask) + { + unsigned long ma=GETLE32(pdest); + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000)); + + if((color&0xffff)==0 ) PUTLE32(pdest, (ma&0xffff)|(GETLE32(pdest)&0xffff0000)); + if((color&0xffff0000)==0) PUTLE32(pdest, (ma&0xffff0000)|(GETLE32(pdest)&0xffff)); + if(ma&0x80000000) PUTLE32(pdest, (ma&0xFFFF0000)|(GETLE32(pdest)&0xFFFF)); + if(ma&0x00008000) PUTLE32(pdest, (ma&0xFFFF) |(GETLE32(pdest)&0xFFFF0000)); + + return; + } + if((color&0xffff)==0 ) {PUTLE32(pdest, (GETLE32(pdest)&0xffff)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff0000));return;} + if((color&0xffff0000)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff0000)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff));return;} + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000)); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColGX_Dither(unsigned short * pdest,unsigned short color,long m1,long m2,long m3) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColGX_Dither(unsigned short * pdest,unsigned short color,long m1,long m2,long m3) +{ + long r,g,b; + + if(color==0) return; + + if(bCheckMask && (*pdest & HOST2LE16(0x8000))) return; + + m1=(((XCOL1D(color)))*m1)>>4; + m2=(((XCOL2D(color)))*m2)>>4; + m3=(((XCOL3D(color)))*m3)>>4; + + if(DrawSemiTrans && (color&0x8000)) + { + r=((XCOL1D(GETLE16(pdest)))<<3); + b=((XCOL2D(GETLE16(pdest)))<<3); + g=((XCOL3D(GETLE16(pdest)))<<3); + + if(GlobalTextABR==0) + { + r=(r>>1)+(m1>>1); + b=(b>>1)+(m2>>1); + g=(g>>1)+(m3>>1); + } + else + if(GlobalTextABR==1) + { + r+=m1; + b+=m2; + g+=m3; + } + else + if(GlobalTextABR==2) + { + r-=m1; + b-=m2; + g-=m3; + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r+=(m1>>2); + b+=(m2>>2); + g+=(m3>>2); +#else + r+=(m1>>1); + b+=(m2>>1); + g+=(m3>>1); +#endif + } + } + else + { + r=m1; + b=m2; + g=m3; + } + + if(r&0x7FFFFF00) r=0xff; + if(b&0x7FFFFF00) b=0xff; + if(g&0x7FFFFF00) g=0xff; + + Dither16(pdest,r,b,g,sSetMask|(color&0x8000)); + +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColGX(unsigned short * pdest,unsigned short color,short m1,short m2,short m3) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColGX(unsigned short * pdest,unsigned short color,short m1,short m2,short m3) +{ + long r,g,b;unsigned short l; + + if(color==0) return; + + if(bCheckMask && (*pdest & HOST2LE16(0x8000))) return; + + l=sSetMask|(color&0x8000); + + if(DrawSemiTrans && (color&0x8000)) + { + if(GlobalTextABR==0) + { + unsigned short d; + d =(GETLE16(pdest)&0x7bde)>>1; + color =((color) &0x7bde)>>1; + r=(XCOL1(d))+((((XCOL1(color)))* m1)>>7); + b=(XCOL2(d))+((((XCOL2(color)))* m2)>>7); + g=(XCOL3(d))+((((XCOL3(color)))* m3)>>7); +/* + r=(XCOL1(*pdest)>>1)+((((XCOL1(color))>>1)* m1)>>7); + b=(XCOL2(*pdest)>>1)+((((XCOL2(color))>>1)* m2)>>7); + g=(XCOL3(*pdest)>>1)+((((XCOL3(color))>>1)* m3)>>7); +*/ + } + else + if(GlobalTextABR==1) + { + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color)))* m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color)))* m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color)))* m3)>>7); + } + else + if(GlobalTextABR==2) + { + r=(XCOL1(GETLE16(pdest)))-((((XCOL1(color)))* m1)>>7); + b=(XCOL2(GETLE16(pdest)))-((((XCOL2(color)))* m2)>>7); + g=(XCOL3(GETLE16(pdest)))-((((XCOL3(color)))* m3)>>7); + if(r&0x80000000) r=0; + if(b&0x80000000) b=0; + if(g&0x80000000) g=0; + } + else + { +#ifdef HALFBRIGHTMODE3 + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>2)* m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>2)* m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>2)* m3)>>7); +#else + r=(XCOL1(GETLE16(pdest)))+((((XCOL1(color))>>1)* m1)>>7); + b=(XCOL2(GETLE16(pdest)))+((((XCOL2(color))>>1)* m2)>>7); + g=(XCOL3(GETLE16(pdest)))+((((XCOL3(color))>>1)* m3)>>7); +#endif + } + } + else + { + r=((XCOL1(color))* m1)>>7; + b=((XCOL2(color))* m2)>>7; + g=((XCOL3(color))* m3)>>7; + } + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|l); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColGX_S(unsigned short * pdest,unsigned short color,short m1,short m2,short m3) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColGX_S(unsigned short * pdest,unsigned short color,short m1,short m2,short m3) +{ + long r,g,b; + + if(color==0) return; + + r=((XCOL1(color))* m1)>>7; + b=((XCOL2(color))* m2)>>7; + g=((XCOL3(color))* m3)>>7; + + if(r&0x7FFFFFE0) r=0x1f; + if(b&0x7FFFFC00) b=0x3e0; + if(g&0x7FFF8000) g=0x7c00; + + PUTLE16(pdest, (XPSXCOL(r,g,b))|sSetMask|(color&0x8000)); +} + +//////////////////////////////////////////////////////////////////////// +//__inline__ void GetTextureTransColGX32_S(unsigned long * pdest,unsigned long color,short m1,short m2,short m3) __attribute__ ((__pure__)); +__inline__ void GetTextureTransColGX32_S(unsigned long * pdest,unsigned long color,short m1,short m2,short m3) +{ + long r,g,b; + + if(color==0) return; + + r=(((X32COL1(color))* m1)&0xFF80FF80)>>7; + b=(((X32COL2(color))* m2)&0xFF80FF80)>>7; + g=(((X32COL3(color))* m3)&0xFF80FF80)>>7; + + if(r&0x7FE00000) r=0x1f0000|(r&0xFFFF); + if(r&0x7FE0) r=0x1f |(r&0xFFFF0000); + if(b&0x7FE00000) b=0x1f0000|(b&0xFFFF); + if(b&0x7FE0) b=0x1f |(b&0xFFFF0000); + if(g&0x7FE00000) g=0x1f0000|(g&0xFFFF); + if(g&0x7FE0) g=0x1f |(g&0xFFFF0000); + + if((color&0xffff)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff0000));return;} + if((color&0xffff0000)==0) {PUTLE32(pdest, (GETLE32(pdest)&0xffff0000)|(((X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000))&0xffff));return;} + + PUTLE32(pdest, (X32PSXCOL(r,g,b))|lSetMask|(color&0x80008000)); +} + +//////////////////////////////////////////////////////////////////////// +// FILL FUNCS +//////////////////////////////////////////////////////////////////////// + +void FillSoftwareAreaTrans(short x0,short y0,short x1, // FILL AREA TRANS + short y1,unsigned short col) +{ + short j,i,dx,dy; + + if(y0>y1) return; + if(x0>x1) return; + + if(x1drawW) return; + if(y0>drawH) return; + + x1=min(x1,drawW+1); + y1=min(y1,drawH+1); + x0=max(x0,drawX); + y0=max(y0,drawY); + + if(y0>=iGPUHeight) return; + if(x0>1023) return; + + if(y1>iGPUHeight) y1=iGPUHeight; + if(x1>1024) x1=1024; + + dx=x1-x0;dy=y1-y0; + + if(dx==1 && dy==1 && x0==1020 && y0==511) // special fix for pinball game... emu protection??? + { +/* +m->v 1020 511 1 1 +writedatamem 0x00000000 1 +tile1 newcol 7fff (orgcol 0xffffff), oldvram 0 +v->m 1020 511 1 1 +readdatamem 0x00007fff 1 +m->v 1020 511 1 1 +writedatamem 0x00000000 1 +tile1 newcol 8000 (orgcol 0xffffff), oldvram 0 +v->m 1020 511 1 1 +readdatamem 0x00008000 1 +*/ + + static int iCheat=0; + col+=iCheat; + if(iCheat==1) iCheat=0; else iCheat=1; + } + + + if(dx&1) // slow fill + { + unsigned short *DSTPtr; + unsigned short LineOffset; + DSTPtr = psxVuw + (1024*y0) + x0; + LineOffset = 1024 - dx; + for(i=0;i>=1; + DSTPtr = (unsigned long *)(psxVuw + (1024*y0) + x0); + LineOffset = 512 - dx; + + if(!bCheckMask && !DrawSemiTrans) + { + for(i=0;iy1) return; + if(x0>x1) return; + + if(y0>=iGPUHeight) return; + if(x0>1023) return; + + if(y1>iGPUHeight) y1=iGPUHeight; + if(x1>1024) x1=1024; + + dx=x1-x0;dy=y1-y0; + if(dx&1) + { + unsigned short *DSTPtr; + unsigned short LineOffset; + + DSTPtr = psxVuw + (1024*y0) + x0; + LineOffset = 1024 - dx; + + for(i=0;i>=1; + DSTPtr = (unsigned long *)(psxVuw + (1024*y0) + x0); + LineOffset = 512 - dx; + + for(i=0;iy - v1->y; + if(height == 0) return 0; + delta_right_x = (v2->x - v1->x) / height; + right_x = v1->x; + + right_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_F(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_left_x = (v2->x - v1->x) / height; + left_x = v1->x; + + left_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_F(void) +{ + if(--left_section_height<=0) + { + if(--left_section <= 0) {return TRUE;} + if(LeftSection_F() <= 0) {return TRUE;} + } + else + { + left_x += delta_left_x; + } + + if(--right_section_height<=0) + { + if(--right_section<=0) {return TRUE;} + if(RightSection_F() <=0) {return TRUE;} + } + else + { + right_x += delta_right_x; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_F(short x1, short y1, short x2, short y2, short x3, short y3) +{ + soft_vertex * v1, * v2, * v3; + int height,longest; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + + height = v3->y - v1->y; + if(height == 0) {return FALSE;} + longest = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest == 0) {return FALSE;} + + if(longest < 0) + { + right_array[0] = v3; + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + left_array[0] = v3; + left_array[1] = v1; + left_section = 1; + + if(LeftSection_F() <= 0) return FALSE; + if(RightSection_F() <= 0) + { + right_section--; + if(RightSection_F() <= 0) return FALSE; + } + } + else + { + left_array[0] = v3; + left_array[1] = v2; + left_array[2] = v1; + left_section = 2; + right_array[0] = v3; + right_array[1] = v1; + right_section = 1; + + if(RightSection_F() <= 0) return FALSE; + if(LeftSection_F() <= 0) + { + left_section--; + if(LeftSection_F() <= 0) return FALSE; + } + } + + Ymin=v1->y; + Ymax=min(v3->y-1,drawH); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_G(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_right_x = (v2->x - v1->x) / height; + right_x = v1->x; + + right_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_G(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_left_x = (v2->x - v1->x) / height; + left_x = v1->x; + + delta_left_R = ((v2->R - v1->R)) / height; + left_R = v1->R; + delta_left_G = ((v2->G - v1->G)) / height; + left_G = v1->G; + delta_left_B = ((v2->B - v1->B)) / height; + left_B = v1->B; + + left_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_G(void) +{ + if(--left_section_height<=0) + { + if(--left_section <= 0) {return TRUE;} + if(LeftSection_G() <= 0) {return TRUE;} + } + else + { + left_x += delta_left_x; + left_R += delta_left_R; + left_G += delta_left_G; + left_B += delta_left_B; + } + + if(--right_section_height<=0) + { + if(--right_section<=0) {return TRUE;} + if(RightSection_G() <=0) {return TRUE;} + } + else + { + right_x += delta_right_x; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_G(short x1,short y1,short x2,short y2,short x3,short y3,long rgb1, long rgb2, long rgb3) +{ + soft_vertex * v1, * v2, * v3; + int height,longest,temp; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v1->R=(rgb1) & 0x00ff0000; + v1->G=(rgb1<<8) & 0x00ff0000; + v1->B=(rgb1<<16) & 0x00ff0000; + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v2->R=(rgb2) & 0x00ff0000; + v2->G=(rgb2<<8) & 0x00ff0000; + v2->B=(rgb2<<16) & 0x00ff0000; + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v3->R=(rgb3) & 0x00ff0000; + v3->G=(rgb3<<8) & 0x00ff0000; + v3->B=(rgb3<<16) & 0x00ff0000; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + + height = v3->y - v1->y; + if(height == 0) {return FALSE;} + temp=(((v2->y - v1->y) << 16) / height); + longest = temp * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest == 0) {return FALSE;} + + if(longest < 0) + { + right_array[0] = v3; + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + left_array[0] = v3; + left_array[1] = v1; + left_section = 1; + + if(LeftSection_G() <= 0) return FALSE; + if(RightSection_G() <= 0) + { + right_section--; + if(RightSection_G() <= 0) return FALSE; + } + if(longest > -0x1000) longest = -0x1000; + } + else + { + left_array[0] = v3; + left_array[1] = v2; + left_array[2] = v1; + left_section = 2; + right_array[0] = v3; + right_array[1] = v1; + right_section = 1; + + if(RightSection_G() <= 0) return FALSE; + if(LeftSection_G() <= 0) + { + left_section--; + if(LeftSection_G() <= 0) return FALSE; + } + if(longest < 0x1000) longest = 0x1000; + } + + Ymin=v1->y; + Ymax=min(v3->y-1,drawH); + + delta_right_R=shl10idiv(temp*((v3->R - v1->R)>>10)+((v1->R - v2->R)<<6),longest); + delta_right_G=shl10idiv(temp*((v3->G - v1->G)>>10)+((v1->G - v2->G)<<6),longest); + delta_right_B=shl10idiv(temp*((v3->B - v1->B)>>10)+((v1->B - v2->B)<<6),longest); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_FT(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_right_x = (v2->x - v1->x) / height; + right_x = v1->x; + + right_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_FT(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_left_x = (v2->x - v1->x) / height; + left_x = v1->x; + + delta_left_u = ((v2->u - v1->u)) / height; + left_u = v1->u; + delta_left_v = ((v2->v - v1->v)) / height; + left_v = v1->v; + + left_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_FT(void) +{ + if(--left_section_height<=0) + { + if(--left_section <= 0) {return TRUE;} + if(LeftSection_FT() <= 0) {return TRUE;} + } + else + { + left_x += delta_left_x; + left_u += delta_left_u; + left_v += delta_left_v; + } + + if(--right_section_height<=0) + { + if(--right_section<=0) {return TRUE;} + if(RightSection_FT() <=0) {return TRUE;} + } + else + { + right_x += delta_right_x; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_FT(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3) +{ + soft_vertex * v1, * v2, * v3; + int height,longest,temp; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v1->u=tx1<<16;v1->v=ty1<<16; + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v2->u=tx2<<16;v2->v=ty2<<16; + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v3->u=tx3<<16;v3->v=ty3<<16; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + + height = v3->y - v1->y; + if(height == 0) {return FALSE;} + + temp=(((v2->y - v1->y) << 16) / height); + longest = temp * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + + if(longest == 0) {return FALSE;} + + if(longest < 0) + { + right_array[0] = v3; + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + left_array[0] = v3; + left_array[1] = v1; + left_section = 1; + + if(LeftSection_FT() <= 0) return FALSE; + if(RightSection_FT() <= 0) + { + right_section--; + if(RightSection_FT() <= 0) return FALSE; + } + if(longest > -0x1000) longest = -0x1000; + } + else + { + left_array[0] = v3; + left_array[1] = v2; + left_array[2] = v1; + left_section = 2; + right_array[0] = v3; + right_array[1] = v1; + right_section = 1; + + if(RightSection_FT() <= 0) return FALSE; + if(LeftSection_FT() <= 0) + { + left_section--; + if(LeftSection_FT() <= 0) return FALSE; + } + if(longest < 0x1000) longest = 0x1000; + } + + Ymin=v1->y; + Ymax=min(v3->y-1,drawH); + + delta_right_u=shl10idiv(temp*((v3->u - v1->u)>>10)+((v1->u - v2->u)<<6),longest); + delta_right_v=shl10idiv(temp*((v3->v - v1->v)>>10)+((v1->v - v2->v)<<6),longest); + +/* +Mmm... adjust neg tex deltas... will sometimes cause slight +texture distortions + + longest>>=16; + if(longest) + { + if(longest<0) longest=-longest; + if(delta_right_u<0) + delta_right_u-=delta_right_u/longest; + if(delta_right_v<0) + delta_right_v-=delta_right_v/longest; + } +*/ + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_GT(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_right_x = (v2->x - v1->x) / height; + right_x = v1->x; + + right_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_GT(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + if(height == 0) return 0; + delta_left_x = (v2->x - v1->x) / height; + left_x = v1->x; + + delta_left_u = ((v2->u - v1->u)) / height; + left_u = v1->u; + delta_left_v = ((v2->v - v1->v)) / height; + left_v = v1->v; + + delta_left_R = ((v2->R - v1->R)) / height; + left_R = v1->R; + delta_left_G = ((v2->G - v1->G)) / height; + left_G = v1->G; + delta_left_B = ((v2->B - v1->B)) / height; + left_B = v1->B; + + left_section_height = height; + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_GT(void) +{ + if(--left_section_height<=0) + { + if(--left_section <= 0) {return TRUE;} + if(LeftSection_GT() <= 0) {return TRUE;} + } + else + { + left_x += delta_left_x; + left_u += delta_left_u; + left_v += delta_left_v; + left_R += delta_left_R; + left_G += delta_left_G; + left_B += delta_left_B; + } + + if(--right_section_height<=0) + { + if(--right_section<=0) {return TRUE;} + if(RightSection_GT() <=0) {return TRUE;} + } + else + { + right_x += delta_right_x; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_GT(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, long rgb1, long rgb2, long rgb3) +{ + soft_vertex * v1, * v2, * v3; + int height,longest,temp; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v1->u=tx1<<16;v1->v=ty1<<16; + v1->R=(rgb1) & 0x00ff0000; + v1->G=(rgb1<<8) & 0x00ff0000; + v1->B=(rgb1<<16) & 0x00ff0000; + + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v2->u=tx2<<16;v2->v=ty2<<16; + v2->R=(rgb2) & 0x00ff0000; + v2->G=(rgb2<<8) & 0x00ff0000; + v2->B=(rgb2<<16) & 0x00ff0000; + + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v3->u=tx3<<16;v3->v=ty3<<16; + v3->R=(rgb3) & 0x00ff0000; + v3->G=(rgb3<<8) & 0x00ff0000; + v3->B=(rgb3<<16) & 0x00ff0000; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + + height = v3->y - v1->y; + if(height == 0) {return FALSE;} + + temp=(((v2->y - v1->y) << 16) / height); + longest = temp * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + + if(longest == 0) {return FALSE;} + + if(longest < 0) + { + right_array[0] = v3; + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + left_array[0] = v3; + left_array[1] = v1; + left_section = 1; + + if(LeftSection_GT() <= 0) return FALSE; + if(RightSection_GT() <= 0) + { + right_section--; + if(RightSection_GT() <= 0) return FALSE; + } + + if(longest > -0x1000) longest = -0x1000; + } + else + { + left_array[0] = v3; + left_array[1] = v2; + left_array[2] = v1; + left_section = 2; + right_array[0] = v3; + right_array[1] = v1; + right_section = 1; + + if(RightSection_GT() <= 0) return FALSE; + if(LeftSection_GT() <= 0) + { + left_section--; + if(LeftSection_GT() <= 0) return FALSE; + } + if(longest < 0x1000) longest = 0x1000; + } + + Ymin=v1->y; + Ymax=min(v3->y-1,drawH); + + delta_right_R=shl10idiv(temp*((v3->R - v1->R)>>10)+((v1->R - v2->R)<<6),longest); + delta_right_G=shl10idiv(temp*((v3->G - v1->G)>>10)+((v1->G - v2->G)<<6),longest); + delta_right_B=shl10idiv(temp*((v3->B - v1->B)>>10)+((v1->B - v2->B)<<6),longest); + + delta_right_u=shl10idiv(temp*((v3->u - v1->u)>>10)+((v1->u - v2->u)<<6),longest); + delta_right_v=shl10idiv(temp*((v3->v - v1->v)>>10)+((v1->v - v2->v)<<6),longest); + + +/* +Mmm... adjust neg tex deltas... will sometimes cause slight +texture distortions + longest>>=16; + if(longest) + { + if(longest<0) longest=-longest; + if(delta_right_u<0) + delta_right_u-=delta_right_u/longest; + if(delta_right_v<0) + delta_right_v-=delta_right_v/longest; + } +*/ + + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_F4(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + right_section_height = height; + right_x = v1->x; + if(height == 0) + { + return 0; + } + delta_right_x = (v2->x - v1->x) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_F4(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + left_section_height = height; + left_x = v1->x; + if(height == 0) + { + return 0; + } + delta_left_x = (v2->x - v1->x) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_F4(void) +{ + if(--left_section_height<=0) + { + if(--left_section > 0) + while(LeftSection_F4()<=0) + { + if(--left_section <= 0) break; + } + } + else + { + left_x += delta_left_x; + } + + if(--right_section_height<=0) + { + if(--right_section > 0) + while(RightSection_F4()<=0) + { + if(--right_section<=0) break; + } + } + else + { + right_x += delta_right_x; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_F4(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4) +{ + soft_vertex * v1, * v2, * v3, * v4; + int height,width,longest1,longest2; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v4 = vtx+3; v4->x=x4<<16;v4->y=y4; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v1->y > v4->y) { soft_vertex * v = v1; v1 = v4; v4 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + if(v2->y > v4->y) { soft_vertex * v = v2; v2 = v4; v4 = v; } + if(v3->y > v4->y) { soft_vertex * v = v3; v3 = v4; v4 = v; } + + height = v4->y - v1->y; if(height == 0) height =1; + width = (v4->x - v1->x)>>16; + longest1 = (((v2->y - v1->y) << 16) / height) * width + (v1->x - v2->x); + longest2 = (((v3->y - v1->y) << 16) / height) * width + (v1->x - v3->x); + + if(longest1 < 0) // 2 is right + { + if(longest2 < 0) // 3 is right + { + left_array[0] = v4; + left_array[1] = v1; + left_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 3 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v2; // 2 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 2 + right_array[2] = v2; // 3 + right_array[3] = v1; // 4 + right_section = 3; + } + } + } + else + { + left_array[0] = v4; + left_array[1] = v3; // 1 + left_array[2] = v1; // 2 + left_section = 2; // 3 + right_array[0] = v4; // 4 + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + } + } + else + { + if(longest2 < 0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 3 + left_section = 2; // 4 + right_array[0] = v4; + right_array[1] = v3; + right_array[2] = v1; + right_section = 2; + } + else + { + right_array[0] = v4; + right_array[1] = v1; + right_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 3 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 2 + left_array[2] = v2; // 3 + left_array[3] = v1; // 4 + left_section = 3; + } + } + } + } + + while(LeftSection_F4()<=0) + { + if(--left_section <= 0) break; + } + + while(RightSection_F4()<=0) + { + if(--right_section <= 0) break; + } + + Ymin=v1->y; + Ymax=min(v4->y-1,drawH); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_FT4(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + right_section_height = height; + right_x = v1->x; + right_u = v1->u; + right_v = v1->v; + if(height == 0) + { + return 0; + } + delta_right_x = (v2->x - v1->x) / height; + delta_right_u = (v2->u - v1->u) / height; + delta_right_v = (v2->v - v1->v) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_FT4(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + left_section_height = height; + left_x = v1->x; + left_u = v1->u; + left_v = v1->v; + if(height == 0) + { + return 0; + } + delta_left_x = (v2->x - v1->x) / height; + delta_left_u = (v2->u - v1->u) / height; + delta_left_v = (v2->v - v1->v) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_FT4(void) +{ + if(--left_section_height<=0) + { + if(--left_section > 0) + while(LeftSection_FT4()<=0) + { + if(--left_section <= 0) break; + } + } + else + { + left_x += delta_left_x; + left_u += delta_left_u; + left_v += delta_left_v; + } + + if(--right_section_height<=0) + { + if(--right_section > 0) + while(RightSection_FT4()<=0) + { + if(--right_section<=0) break; + } + } + else + { + right_x += delta_right_x; + right_u += delta_right_u; + right_v += delta_right_v; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_FT4(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4) +{ + soft_vertex * v1, * v2, * v3, * v4; + int height,width,longest1,longest2; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v1->u=tx1<<16;v1->v=ty1<<16; + + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v2->u=tx2<<16;v2->v=ty2<<16; + + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v3->u=tx3<<16;v3->v=ty3<<16; + + v4 = vtx+3; v4->x=x4<<16;v4->y=y4; + v4->u=tx4<<16;v4->v=ty4<<16; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v1->y > v4->y) { soft_vertex * v = v1; v1 = v4; v4 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + if(v2->y > v4->y) { soft_vertex * v = v2; v2 = v4; v4 = v; } + if(v3->y > v4->y) { soft_vertex * v = v3; v3 = v4; v4 = v; } + + height = v4->y - v1->y; if(height == 0) height =1; + width = (v4->x - v1->x)>>16; + longest1 = (((v2->y - v1->y) << 16) / height) * width + (v1->x - v2->x); + longest2 = (((v3->y - v1->y) << 16) / height) * width + (v1->x - v3->x); + + if(longest1 < 0) // 2 is right + { + if(longest2 < 0) // 3 is right + { + left_array[0] = v4; + left_array[1] = v1; + left_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 3 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v2; // 2 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 2 + right_array[2] = v2; // 3 + right_array[3] = v1; // 4 + right_section = 3; + } + } + } + else + { + left_array[0] = v4; + left_array[1] = v3; // 1 + left_array[2] = v1; // 2 + left_section = 2; // 3 + right_array[0] = v4; // 4 + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + } + } + else + { + if(longest2 < 0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 3 + left_section = 2; // 4 + right_array[0] = v4; + right_array[1] = v3; + right_array[2] = v1; + right_section = 2; + } + else + { + right_array[0] = v4; + right_array[1] = v1; + right_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 3 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 2 + left_array[2] = v2; // 3 + left_array[3] = v1; // 4 + left_section = 3; + } + } + } + } + + while(LeftSection_FT4()<=0) + { + if(--left_section <= 0) break; + } + + while(RightSection_FT4()<=0) + { + if(--right_section <= 0) break; + } + + Ymin=v1->y; + Ymax=min(v4->y-1,drawH); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +__inline__ int RightSection_GT4(void) +{ + soft_vertex * v1 = right_array[ right_section ]; + soft_vertex * v2 = right_array[ right_section-1 ]; + + int height = v2->y - v1->y; + right_section_height = height; + right_x = v1->x; + right_u = v1->u; + right_v = v1->v; + right_R = v1->R; + right_G = v1->G; + right_B = v1->B; + + if(height == 0) + { + return 0; + } + delta_right_x = (v2->x - v1->x) / height; + delta_right_u = (v2->u - v1->u) / height; + delta_right_v = (v2->v - v1->v) / height; + delta_right_R = (v2->R - v1->R) / height; + delta_right_G = (v2->G - v1->G) / height; + delta_right_B = (v2->B - v1->B) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ int LeftSection_GT4(void) +{ + soft_vertex * v1 = left_array[ left_section ]; + soft_vertex * v2 = left_array[ left_section-1 ]; + + int height = v2->y - v1->y; + left_section_height = height; + left_x = v1->x; + left_u = v1->u; + left_v = v1->v; + left_R = v1->R; + left_G = v1->G; + left_B = v1->B; + + if(height == 0) + { + return 0; + } + delta_left_x = (v2->x - v1->x) / height; + delta_left_u = (v2->u - v1->u) / height; + delta_left_v = (v2->v - v1->v) / height; + delta_left_R = (v2->R - v1->R) / height; + delta_left_G = (v2->G - v1->G) / height; + delta_left_B = (v2->B - v1->B) / height; + + return height; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL NextRow_GT4(void) +{ + if(--left_section_height<=0) + { + if(--left_section > 0) + while(LeftSection_GT4()<=0) + { + if(--left_section <= 0) break; + } + } + else + { + left_x += delta_left_x; + left_u += delta_left_u; + left_v += delta_left_v; + left_R += delta_left_R; + left_G += delta_left_G; + left_B += delta_left_B; + } + + if(--right_section_height<=0) + { + if(--right_section > 0) + while(RightSection_GT4()<=0) + { + if(--right_section<=0) break; + } + } + else + { + right_x += delta_right_x; + right_u += delta_right_u; + right_v += delta_right_v; + right_R += delta_right_R; + right_G += delta_right_G; + right_B += delta_right_B; + } + return FALSE; +} + +//////////////////////////////////////////////////////////////////////// + +__inline__ BOOL SetupSections_GT4(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,long rgb1,long rgb2,long rgb3,long rgb4) +{ + soft_vertex * v1, * v2, * v3, * v4; + int height,width,longest1,longest2; + + v1 = vtx; v1->x=x1<<16;v1->y=y1; + v1->u=tx1<<16;v1->v=ty1<<16; + v1->R=(rgb1) & 0x00ff0000; + v1->G=(rgb1<<8) & 0x00ff0000; + v1->B=(rgb1<<16) & 0x00ff0000; + + v2 = vtx+1; v2->x=x2<<16;v2->y=y2; + v2->u=tx2<<16;v2->v=ty2<<16; + v2->R=(rgb2) & 0x00ff0000; + v2->G=(rgb2<<8) & 0x00ff0000; + v2->B=(rgb2<<16) & 0x00ff0000; + + v3 = vtx+2; v3->x=x3<<16;v3->y=y3; + v3->u=tx3<<16;v3->v=ty3<<16; + v3->R=(rgb3) & 0x00ff0000; + v3->G=(rgb3<<8) & 0x00ff0000; + v3->B=(rgb3<<16) & 0x00ff0000; + + v4 = vtx+3; v4->x=x4<<16;v4->y=y4; + v4->u=tx4<<16;v4->v=ty4<<16; + v4->R=(rgb4) & 0x00ff0000; + v4->G=(rgb4<<8) & 0x00ff0000; + v4->B=(rgb4<<16) & 0x00ff0000; + + if(v1->y > v2->y) { soft_vertex * v = v1; v1 = v2; v2 = v; } + if(v1->y > v3->y) { soft_vertex * v = v1; v1 = v3; v3 = v; } + if(v1->y > v4->y) { soft_vertex * v = v1; v1 = v4; v4 = v; } + if(v2->y > v3->y) { soft_vertex * v = v2; v2 = v3; v3 = v; } + if(v2->y > v4->y) { soft_vertex * v = v2; v2 = v4; v4 = v; } + if(v3->y > v4->y) { soft_vertex * v = v3; v3 = v4; v4 = v; } + + height = v4->y - v1->y; if(height == 0) height =1; + width = (v4->x - v1->x)>>16; + longest1 = (((v2->y - v1->y) << 16) / height) * width + (v1->x - v2->x); + longest2 = (((v3->y - v1->y) << 16) / height) * width + (v1->x - v3->x); + + if(longest1 < 0) // 2 is right + { + if(longest2 < 0) // 3 is right + { + left_array[0] = v4; + left_array[1] = v1; + left_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 3 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1 >= 0) + { + right_array[0] = v4; // 1 + right_array[1] = v2; // 2 + right_array[2] = v1; // 4 + right_section = 2; + } + else + { + right_array[0] = v4; // 1 + right_array[1] = v3; // 2 + right_array[2] = v2; // 3 + right_array[3] = v1; // 4 + right_section = 3; + } + } + } + else + { + left_array[0] = v4; + left_array[1] = v3; // 1 + left_array[2] = v1; // 2 + left_section = 2; // 3 + right_array[0] = v4; // 4 + right_array[1] = v2; + right_array[2] = v1; + right_section = 2; + } + } + else + { + if(longest2 < 0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 3 + left_section = 2; // 4 + right_array[0] = v4; + right_array[1] = v3; + right_array[2] = v1; + right_section = 2; + } + else + { + right_array[0] = v4; + right_array[1] = v1; + right_section = 1; + + height = v3->y - v1->y; if(height == 0) height=1; + longest1 = (((v2->y - v1->y) << 16) / height) * ((v3->x - v1->x)>>16) + (v1->x - v2->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 3 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + height = v4->y - v2->y; if(height == 0) height=1; + longest1 = (((v3->y - v2->y) << 16) / height) * ((v4->x - v2->x)>>16) + (v2->x - v3->x); + if(longest1<0) + { + left_array[0] = v4; // 1 + left_array[1] = v2; // 2 + left_array[2] = v1; // 4 + left_section = 2; + } + else + { + left_array[0] = v4; // 1 + left_array[1] = v3; // 2 + left_array[2] = v2; // 3 + left_array[3] = v1; // 4 + left_section = 3; + } + } + } + } + + while(LeftSection_GT4()<=0) + { + if(--left_section <= 0) break; + } + + while(RightSection_GT4()<=0) + { + if(--right_section <= 0) break; + } + + Ymin=v1->y; + Ymax=min(v4->y-1,drawH); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +// POLY FUNCS +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////// +// POLY 3/4 FLAT SHADED +//////////////////////////////////////////////////////////////////////// + +__inline__ void drawPoly3Fi(short x1,short y1,short x2,short y2,short x3,short y3,long rgb) +{ + int i,j,xmin,xmax,ymin,ymax; + unsigned short color;unsigned long lcolor; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_F(x1,y1,x2,y2,x3,y3)) return; + + ymax=Ymax; + + color = ((rgb & 0x00f80000)>>9) | ((rgb & 0x0000f800)>>6) | ((rgb & 0x000000f8)>>3); + lcolor=lSetMask|(((unsigned long)(color))<<16)|color; + + for(ymin=Ymin;ymin> 16; if(drawX>xmin) xmin=drawX; + xmax=(right_x >> 16)-1; if(drawW> 16; if(drawX>xmin) xmin=drawX; + xmax=(right_x >> 16)-1; if(drawWdrawW && lx1>drawW && lx2>drawW && lx3>drawW) return; + if(ly0>drawH && ly1>drawH && ly2>drawH && ly3>drawH) return; + if(lx0=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_F4(lx0,ly0,lx1,ly1,lx2,ly2,lx3,ly3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin>9) | ((rgb & 0x0000f800)>>6) | ((rgb & 0x000000f8)>>3); + lcolor= lSetMask|(((unsigned long)(color))<<16)|color; + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + color |=sSetMask; + for (i=ymin;i<=ymax;i++) + { + xmin=left_x >> 16; if(drawX>xmin) xmin=drawX; + xmax=(right_x >> 16)-1; if(drawW> 16; if(drawX>xmin) xmin=drawX; + xmax=(right_x >> 16)-1; if(drawWdrawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16); + tC1 = src[((posY>>5)&0xFFFFF800)+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = src[(((posY+difY)>>5)&0xFFFFF800)+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = src[((posY>>5)&0xFFFFF800)+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16); + tC1 = src[((posY>>5)&0xFFFFF800)+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = src[(((posY+difY)>>5)&0xFFFFF800)+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = src[((posY>>5)&0xFFFFF800)+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TEx4_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3,short clX, short clY) +{ + int i,j,xmin,xmax,ymin,ymax; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,XAdjust; + long clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin>1); + + difX=delta_right_u;difX2=difX<<1; + difY=delta_right_v;difY2=difY<<1; + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16);//-1; //!!!!!!!!!!!!!!!! + if(xmax>xmin) xmax--; + + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +#ifdef POLYQUAD3 + +void drawPoly4TEx4_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + drawPoly3TEx4(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY); + drawPoly3TEx4(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY); +} + +#endif + +// more exact: + +void drawPoly4TEx4(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TEx4_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin>1); + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TEx4_TW_S(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin>1); + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColG32_SPR((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColG_SPR(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} +//////////////////////////////////////////////////////////////////////// +// POLY 3 F-SHADED TEX PAL 8 +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TEx8(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3,short clX, short clY) +{ + int i,j,xmin,xmax,ymin,ymax; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + ((posX+difX)>>16)]; + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + ((posX+difX)>>16)]; + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + + } + if(NextRow_FT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TEx8_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3,short clX, short clY) +{ + int i,j,xmin,xmax,ymin,ymax; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16);//-1; //!!!!!!!!!!!!!!!! + if(xmax>xmin) xmax--; + + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + + if(j==xmax) + { + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + + if(j==xmax) + { + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + + } + if(NextRow_FT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +#ifdef POLYQUAD3 + +void drawPoly4TEx8_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + drawPoly3TEx8(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY); + + drawPoly3TEx8(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY); +} + +#endif + +// more exact: + +void drawPoly4TEx8(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + ((posX+difX)>>16)]; + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + ((posX+difX)>>16)]; + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TEx8_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TEx8_TW_S(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4,short clX, short clY) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1,tC2; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG_S(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG32_SPR((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16); + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + { + tC1 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColG_SPR(&psxVuw[(i<<10)+j],GETLE16(&psxVuw[clutP+tC1])); + } + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// +// POLY 3 F-SHADED TEX 15 BIT +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TD(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3) +{ + int i,j,xmin,xmax,ymin,ymax; + long difX, difY,difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX])); + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX])); + } + if(NextRow_FT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TD_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3) +{ + int i,j,xmin,xmax,ymin,ymax; + long difX, difY,difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT()) + { + return; + } + } +} + + +//////////////////////////////////////////////////////////////////////// + +#ifdef POLYQUAD3 + +void drawPoly4TD_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4) +{ + drawPoly3TD(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4); + drawPoly3TD(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4); +} + +#endif + +// more exact: + +void drawPoly4TD(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY; + + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX])); + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX])); + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TD_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY)<<10)+TWin.Position.y0+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TD_TW_S(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long difX, difY, difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_FT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY)<<10)+TWin.Position.y0+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + difX2=difX<<1; + difY2=difY<<1; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + + posX+=difX2; + posY+=difY2; + } + if(j==xmax) + GetTextureTransColG_SPR(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0])); + } + if(NextRow_FT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// +// POLY 3/4 G-SHADED +//////////////////////////////////////////////////////////////////////// + +__inline__ void drawPoly3Gi(short x1,short y1,short x2,short y2,short x3,short y3,long rgb1, long rgb2, long rgb3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_G(x1,y1,x2,y2,x3,y3,rgb1,rgb2,rgb3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1;if(drawW=xmin) + { + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>3)&0x001f0000)| + (((cR1) >> 9)&0x7c00)|(((cG1) >> 14)&0x03e0)|(((cB1) >> 19)&0x001f))|lSetMask); + + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + PUTLE16(&psxVuw[(i<<10)+j], (((cR1 >> 9)&0x7c00)|((cG1 >> 14)&0x03e0)|((cB1 >> 19)&0x001f))|sSetMask); + } + if(NextRow_G()) return; + } + return; + } + +#endif + + if(iDither==2) + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1;if(drawW=xmin) + { + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16),(cG1>>16),(cR1>>16)); + + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_G()) return; + } + else + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1;if(drawW=xmin) + { + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin> 9)&0x7c00)|((cG1 >> 14)&0x03e0)|((cB1 >> 19)&0x001f)); + + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_G()) return; + } + +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3G(long rgb1, long rgb2, long rgb3) +{ + drawPoly3Gi(lx0,ly0,lx1,ly1,lx2,ly2,rgb1,rgb2,rgb3); +} + +// draw two g-shaded tris for right psx shading emulation + +void drawPoly4G(long rgb1, long rgb2, long rgb3, long rgb4) +{ + drawPoly3Gi(lx1,ly1,lx3,ly3,lx2,ly2, + rgb2,rgb4,rgb3); + drawPoly3Gi(lx0,ly0,lx1,ly1,lx2,ly2, + rgb1,rgb2,rgb3); +} + +//////////////////////////////////////////////////////////////////////// +// POLY 3/4 G-SHADED TEX PAL4 +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGEx4(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short clX, short clY,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=((right_x) >> 16)-1; //!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGEx4_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short clX, short clY,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin>1); + + difR=delta_right_R; + difG=delta_right_G; + difB=delta_right_B; + difR2=difR<<1; + difG2=difG<<1; + difB2=difB<<1; + + difX=delta_right_u;difX2=difX<<1; + difY=delta_right_v;difY2=difY<<1; + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans && !iDither) + { + for (i=ymin;i<=ymax;i++) + { + xmin=((left_x) >> 16); + xmax=((right_x) >> 16)-1; //!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16) & (TWin.Position.x1-1); + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + XAdjust=(posX>>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.x1-1); + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +// note: the psx is doing g-shaded quads as two g-shaded tris, +// like the following func... sadly texturing is not 100% +// correct that way, so small texture distortions can +// happen... + +#ifdef POLYQUAD3GT + +void drawPoly4TGEx4_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col3, long col4) +{ + drawPoly3TGEx4(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY, + col2,col4,col3); + drawPoly3TGEx4(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY, + col1,col2,col3); +} + +#endif + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TGEx4(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col4, long col3) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG; + long difX, difY; + long posX,posY,YAdjust,clutP,XAdjust; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4,col1,col2,col3,col4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + long difX2=difX<<1; + long difY2=difY<<1; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + long difR2=difR<<1; + long difG2=difG<<1; + long difB2=difB<<1; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + XAdjust=((posX+difX)>>16); + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC2=(tC2>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + XAdjust=(posX>>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + + if(xmin>16); + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+ + (XAdjust>>1)]; + tC1=(tC1>>((XAdjust&1)<<2))&0xf; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TGEx4_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col3, long col4) +{ + drawPoly3TGEx4_TW(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY, + col2,col4,col3); + + drawPoly3TGEx4_TW(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY, + col1,col2,col3); +} + +//////////////////////////////////////////////////////////////////////// +// POLY 3/4 G-SHADED TEX PAL8 +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGEx8(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short clX, short clY,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; // !!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>5)&0xFFFFF800)+YAdjust+((posX>>16))]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + (((posX+difX)>>16))]; + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+((posX>>16))]; + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>5)&0xFFFFF800)+YAdjust+((posX>>16))]; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGEx8_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short clX, short clY,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY,YAdjust,clutP; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; // !!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + tC2 = psxVub[((((posY+difY)>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+(((posX+difX)>>16) & (TWin.Position.x1-1))]; + + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + tC1 = psxVub[(((posY>>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.y1-1))<<11)+ + YAdjust+((posX>>16) & (TWin.Position.x1-1))]; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +// note: two g-shaded tris: small texture distortions can happen + +#ifdef POLYQUAD3GT + +void drawPoly4TGEx8_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col3, long col4) +{ + drawPoly3TGEx8(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY, + col2,col4,col3); + drawPoly3TGEx8(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY, + col1,col2,col3); +} + +#endif + +void drawPoly4TGEx8(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col4, long col3) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG; + long difX, difY; + long posX,posY,YAdjust,clutP; + short tC1; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4,col1,col2,col3,col4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + long difX2=difX<<1; + long difY2=difY<<1; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + long difR2=difR<<1; + long difG2=difG<<1; + long difB2=difB<<1; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + tC2 = psxVub[(((posY+difY)>>5)&0xFFFFF800)+YAdjust+ + ((posX+difX)>>16)]; + + GetTextureTransColGX32_S((unsigned long *)&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1])| + ((long)GETLE16(&psxVuw[clutP+tC2]))<<16, + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + { + tC1 = psxVub[((posY>>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + } + if(NextRow_GT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + + if(xmin>5)&0xFFFFF800)+YAdjust+(posX>>16)]; + if(iDither) + GetTextureTransColGX_Dither(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[clutP+tC1]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TGEx8_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, + short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, + short clX, short clY, + long col1, long col2, long col3, long col4) +{ + drawPoly3TGEx8_TW(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + clX,clY, + col2,col4,col3); + drawPoly3TGEx8_TW(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + clX,clY, + col1,col2,col3); +} + +//////////////////////////////////////////////////////////////////////// +// POLY 3 G-SHADED TEX 15 BIT +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGD(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX]), + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3TGD_TW(short x1, short y1, short x2, short y2, short x3, short y3, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3,long col1, long col2, long col3) +{ + int i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG,difR2,difB2,difG2; + long difX, difY,difX2, difY2; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT(x1,y1,x2,y2,x3,y3,tx1,ty1,tx2,ty2,tx3,ty3,col1,col2,col3)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX+difX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]))<<16)| + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + (((posX)>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]), + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + if(NextRow_GT()) + { + return; + } + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16)-1; //!!!!!!!!!!!!!!!!!! + if(drawW=xmin) + { + posX=left_u; + posY=left_v; + cR1=left_R; + cG1=left_G; + cB1=left_B; + + if(xmin>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[((((posY>>16) & (TWin.Position.y1-1))+GlobalTextAddrY+TWin.Position.y0)<<10)+ + ((posX>>16) & (TWin.Position.x1-1))+GlobalTextAddrX+TWin.Position.x0]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT()) + { + return; + } + } +} + +//////////////////////////////////////////////////////////////////////// + +// note: two g-shaded tris: small texture distortions can happen + +#ifdef POLYQUAD3GT + +void drawPoly4TGD_TRI(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, long col1, long col2, long col3, long col4) +{ + drawPoly3TGD(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + col2,col4,col3); + drawPoly3TGD(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + col1,col2,col3); +} + +#endif + +void drawPoly4TGD(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, long col1, long col2, long col4, long col3) +{ + long num; + long i,j,xmin,xmax,ymin,ymax; + long cR1,cG1,cB1; + long difR,difB,difG; + long difX, difY; + long posX,posY; + + if(x1>drawW && x2>drawW && x3>drawW && x4>drawW) return; + if(y1>drawH && y2>drawH && y3>drawH && y4>drawH) return; + if(x1=drawH) return; + if(drawX>=drawW) return; + + if(!SetupSections_GT4(x1,y1,x2,y2,x3,y3,x4,y4,tx1,ty1,tx2,ty2,tx3,ty3,tx4,ty4,col1,col2,col3,col4)) return; + + ymax=Ymax; + + for(ymin=Ymin;ymin> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + long difX2=difX<<1; + long difY2=difY<<1; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + long difR2=difR<<1; + long difG2=difG<<1; + long difB2=difB<<1; + + if(xmin>16)+GlobalTextAddrY)<<10)+((posX+difX)>>16)+GlobalTextAddrX]))<<16)| + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+((posX)>>16)+GlobalTextAddrX]), + (cB1>>16)|((cB1+difB)&0xff0000), + (cG1>>16)|((cG1+difG)&0xff0000), + (cR1>>16)|((cR1+difR)&0xff0000)); + posX+=difX2; + posY+=difY2; + cR1+=difR2; + cG1+=difG2; + cB1+=difB2; + } + if(j==xmax) + GetTextureTransColGX_S(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + } + if(NextRow_GT4()) return; + } + return; + } + +#endif + + for (i=ymin;i<=ymax;i++) + { + xmin=(left_x >> 16); + xmax=(right_x >> 16); + + if(xmax>=xmin) + { + posX=left_u; + posY=left_v; + + num=(xmax-xmin); + if(num==0) num=1; + difX=(right_u-posX)/num; + difY=(right_v-posY)/num; + + cR1=left_R; + cG1=left_G; + cB1=left_B; + difR=(right_R-cR1)/num; + difG=(right_G-cG1)/num; + difB=(right_B-cB1)/num; + + if(xmin>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + else + GetTextureTransColGX(&psxVuw[(i<<10)+j], + GETLE16(&psxVuw[(((posY>>16)+GlobalTextAddrY)<<10)+(posX>>16)+GlobalTextAddrX]), + (cB1>>16),(cG1>>16),(cR1>>16)); + posX+=difX; + posY+=difY; + cR1+=difR; + cG1+=difG; + cB1+=difB; + } + } + if(NextRow_GT4()) return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4TGD_TW(short x1, short y1, short x2, short y2, short x3, short y3, short x4, short y4, short tx1, short ty1, short tx2, short ty2, short tx3, short ty3, short tx4, short ty4, long col1, long col2, long col3, long col4) +{ + drawPoly3TGD_TW(x2,y2,x3,y3,x4,y4, + tx2,ty2,tx3,ty3,tx4,ty4, + col2,col4,col3); + drawPoly3TGD_TW(x1,y1,x2,y2,x4,y4, + tx1,ty1,tx2,ty2,tx4,ty4, + col1,col2,col3); +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + + +/* +// no real rect test, but it does its job the way I need it +__inline BOOL IsNoRect(void) +{ + if(lx0==lx1 && lx2==lx3) return FALSE; + if(lx0==lx2 && lx1==lx3) return FALSE; + if(lx0==lx3 && lx1==lx2) return FALSE; + return TRUE; +} +*/ + +// real rect test +__inline BOOL IsNoRect(void) +{ + if(!(dwActFixes&0x200)) return FALSE; + + if(ly0==ly1) + { + if(lx1==lx3 && ly3==ly2 && lx2==lx0) return FALSE; + if(lx1==lx2 && ly2==ly3 && lx3==lx0) return FALSE; + return TRUE; + } + + if(ly0==ly2) + { + if(lx2==lx3 && ly3==ly1 && lx1==lx0) return FALSE; + if(lx2==lx1 && ly1==ly3 && lx3==lx0) return FALSE; + return TRUE; + } + + if(ly0==ly3) + { + if(lx3==lx2 && ly2==ly1 && lx1==lx0) return FALSE; + if(lx3==lx1 && ly1==ly2 && lx2==lx0) return FALSE; + return TRUE; + } + return TRUE; +} + +//////////////////////////////////////////////////////////////////////// +void drawPoly3FT(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + + if(GlobalTextIL && GlobalTextTP<2) + { + sprintf(txtbuffer,"Missing function drawPoly3TEx4_IL(). Notify sepp256 as to which game."); + DEBUG_print(txtbuffer,DBG_GPU1); + } + + if(!bUsingTWin && !(dwActFixes&0x100)) + { + switch(GlobalTextTP) // depending on texture mode + { + case 0: + drawPoly3TEx4(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & iGPUHeightMask)); + return; + case 1: + drawPoly3TEx8(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & iGPUHeightMask)); + return; + case 2: + drawPoly3TD(lx0,ly0,lx1,ly1,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff)); + return; + } + return; + } + + switch(GlobalTextTP) // depending on texture mode + { + case 0: + drawPoly3TEx4_TW(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & iGPUHeightMask)); + return; + case 1: + drawPoly3TEx8_TW(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & iGPUHeightMask)); + return; + case 2: + drawPoly3TD_TW(lx0,ly0,lx1,ly1,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff)); + return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4FT(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + + if(!bUsingTWin) + { +#ifdef POLYQUAD3GT + if(IsNoRect()) + { + switch (GlobalTextTP) + { + case 0: + drawPoly4TEx4_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 1: + drawPoly4TEx8_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 2: + drawPoly4TD_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff)); + return; + } + return; + } +#endif + + switch (GlobalTextTP) + { + case 0: // grandia investigations needed + drawPoly4TEx4(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 1: + drawPoly4TEx8(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 2: + drawPoly4TD(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff)); + return; + } + return; + } + + switch (GlobalTextTP) + { + case 0: + drawPoly4TEx4_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 1: + drawPoly4TEx8_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff), ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 2: + drawPoly4TD_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[4]) & 0x000000ff), ((GETLE32(&gpuData[4])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),(GETLE32(&gpuData[6]) & 0x000000ff), ((GETLE32(&gpuData[6])>>8) & 0x000000ff)); + return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly3GT(unsigned char * baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + + if(!bUsingTWin) + { + switch (GlobalTextTP) + { + case 0: + drawPoly3TGEx4(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + case 1: + drawPoly3TGEx8(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + case 2: + drawPoly3TGD(lx0,ly0,lx1,ly1,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + } + return; + } + + switch(GlobalTextTP) + { + case 0: + drawPoly3TGEx4_TW(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + case 1: + drawPoly3TGEx8_TW(lx0,ly0,lx1,ly1,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + case 2: + drawPoly3TGD_TW(lx0,ly0,lx1,ly1,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6])); + return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void drawPoly4GT(unsigned char *baseAddr) +{ + unsigned long *gpuData = ((unsigned long *) baseAddr); + + if(!bUsingTWin) + { +#ifdef POLYQUAD3GT + if(IsNoRect()) + { + switch (GlobalTextTP) + { + case 0: + drawPoly4TGEx4_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + + return; + case 1: + drawPoly4TGEx8_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + case 2: + drawPoly4TGD_TRI(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff),((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + } + return; + } +#endif + + switch (GlobalTextTP) + { + case 0: + drawPoly4TGEx4(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + + return; + case 1: + drawPoly4TGEx8(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + case 2: + drawPoly4TGD(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff),((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + } + return; + } + + + switch (GlobalTextTP) + { + case 0: + drawPoly4TGEx4_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + case 1: + drawPoly4TGEx8_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2, + (GETLE32(&gpuData[2]) & 0x000000ff), ((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff), + ((GETLE32(&gpuData[2])>>12) & 0x3f0),((GETLE32(&gpuData[2])>>22) & 0x1ff), + GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + case 2: + drawPoly4TGD_TW(lx0,ly0,lx1,ly1,lx3,ly3,lx2,ly2,(GETLE32(&gpuData[2]) & 0x000000ff),((GETLE32(&gpuData[2])>>8) & 0x000000ff), (GETLE32(&gpuData[5]) & 0x000000ff), ((GETLE32(&gpuData[5])>>8) & 0x000000ff),(GETLE32(&gpuData[11]) & 0x000000ff), ((GETLE32(&gpuData[11])>>8) & 0x000000ff),(GETLE32(&gpuData[8]) & 0x000000ff), ((GETLE32(&gpuData[8])>>8) & 0x000000ff),GETLE32(&gpuData[0]),GETLE32(&gpuData[3]),GETLE32(&gpuData[6]),GETLE32(&gpuData[9])); + return; + } +} + +//////////////////////////////////////////////////////////////////////// +// SPRITE FUNCS +//////////////////////////////////////////////////////////////////////// + +void DrawSoftwareSpriteTWin(unsigned char * baseAddr,long w,long h) +{ + unsigned long *gpuData = (unsigned long *)baseAddr; + short sx0,sy0,sx1,sy1,sx2,sy2,sx3,sy3; + short tx0,ty0,tx1,ty1,tx2,ty2,tx3,ty3; + + sx0=lx0; + sy0=ly0; + + sx0=sx3=sx0+PSXDisplay.DrawOffset.x; + sx1=sx2=sx0+w; + sy0=sy1=sy0+PSXDisplay.DrawOffset.y; + sy2=sy3=sy0+h; + + tx0=tx3=GETLE32(&gpuData[2])&0xff; + tx1=tx2=tx0+w; + ty0=ty1=(GETLE32(&gpuData[2])>>8)&0xff; + ty2=ty3=ty0+h; + + switch (GlobalTextTP) + { + case 0: + drawPoly4TEx4_TW_S(sx0,sy0,sx1,sy1,sx2,sy2,sx3,sy3, + tx0,ty0,tx1,ty1,tx2,ty2,tx3,ty3, + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 1: + drawPoly4TEx8_TW_S(sx0,sy0,sx1,sy1,sx2,sy2,sx3,sy3, + tx0,ty0,tx1,ty1,tx2,ty2,tx3,ty3, + ((GETLE32(&gpuData[2])>>12) & 0x3f0), ((GETLE32(&gpuData[2])>>22) & 0x1ff)); + return; + case 2: + drawPoly4TD_TW_S(sx0,sy0,sx1,sy1,sx2,sy2,sx3,sy3, + tx0,ty0,tx1,ty1,tx2,ty2,tx3,ty3); + return; + } +} + +//////////////////////////////////////////////////////////////////////// + +void DrawSoftwareSpriteMirror(unsigned char * baseAddr,long w,long h) +{ + long sprtY,sprtX,sprtW,sprtH,lXDir,lYDir; + long clutY0,clutX0,clutP,textX0,textY0,sprtYa,sprCY,sprCX,sprA; + short tC; + unsigned long *gpuData = (unsigned long *)baseAddr; + sprtY = ly0; + sprtX = lx0; + sprtH = h; + sprtW = w; + clutY0 = (GETLE32(&gpuData[2])>>22) & 0x1ff; + clutX0 = (GETLE32(&gpuData[2])>>12) & 0x3f0; + clutP = (clutY0<<11) + (clutX0<<1); + textY0 = ((GETLE32(&gpuData[2])>>8) & 0x000000ff) + GlobalTextAddrY; + textX0 = (GETLE32(&gpuData[2]) & 0x000000ff); + + sprtX+=PSXDisplay.DrawOffset.x; + sprtY+=PSXDisplay.DrawOffset.y; + +// while (sprtX>1023) sprtX-=1024; +// while (sprtY>MAXYLINESMIN1) sprtY-=MAXYLINES; + + if(sprtX>drawW) + { +// if((sprtX+sprtW)>1023) sprtX-=1024; +// else return; + return; + } + + if(sprtY>drawH) + { +// if ((sprtY+sprtH)>MAXYLINESMIN1) sprtY-=MAXYLINES; +// else return; + return; + } + + if(sprtYdrawH) sprtH=drawH-sprtY+1; + if((sprtX+sprtW)>drawW) sprtW=drawW-sprtX+1; + + if(usMirror&0x1000) lXDir=-1; else lXDir=1; + if(usMirror&0x2000) lYDir=-1; else lYDir=1; + + switch (GlobalTextTP) + { + case 0: // texture is 4-bit + + sprtW=sprtW/2; + textX0=(GlobalTextAddrX<<1)+(textX0>>1); + sprtYa=(sprtY<<10); + clutP=(clutY0<<10)+clutX0; + for (sprCY=0;sprCY>4)&0xf)])); + GetTextureTransColG_SPR(&psxVuw[sprA+1],GETLE16(&psxVuw[clutP+(tC&0xf)])); + } + return; + + case 1: + + clutP>>=1; + for(sprCY=0;sprCY>22) & 0x1ff; + clutX0 = (GETLE32(&gpuData[2])>>12) & 0x3f0; + + clutP = (clutY0<<11) + (clutX0<<1); + + textY0 =ty+ GlobalTextAddrY; + textX0 =tx; + + sprtX+=PSXDisplay.DrawOffset.x; + sprtY+=PSXDisplay.DrawOffset.y; + + //while (sprtX>1023) sprtX-=1024; + //while (sprtY>MAXYLINESMIN1) sprtY-=MAXYLINES; + + if(sprtX>drawW) + { +// if((sprtX+sprtW)>1023) sprtX-=1024; +// else return; + return; + } + + if(sprtY>drawH) + { +// if ((sprtY+sprtH)>MAXYLINESMIN1) sprtY-=MAXYLINES; +// else return; + return; + } + + if(sprtYdrawH) sprtH=drawH-sprtY+1; + if((sprtX+sprtW)>drawW) sprtW=drawW-sprtX+1; + + + bWT=FALSE; + bWS=FALSE; + + switch (GlobalTextTP) + { + case 0: + + if(textX0&1) {bWS=TRUE;sprtW--;} + if(sprtW&1) bWT=TRUE; + + sprtW=sprtW>>1; + textX0=(GlobalTextAddrX<<1)+(textX0>>1)+(textY0<<11); + sprtYa=(sprtY<<10)+sprtX; + clutP=(clutY0<<10)+clutX0; + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + for (sprCY=0;sprCY>4)&0xf)])); + } + + for (sprCX=0;sprCX>4)&0xf)]))<<16)| + GETLE16(&psxVuw[clutP+(tC&0x0f)])); + } + + if(bWT) + { + tC=*pV; + GetTextureTransColG_S(&psxVuw[sprA],GETLE16(&psxVuw[clutP+(tC&0x0f)])); + } + } + return; + } + +#endif + + for (sprCY=0;sprCY>4)&0xf)])); + } + + for (sprCX=0;sprCX>4)&0xf)])<<16))| + GETLE16(&psxVuw[clutP+(tC&0x0f)])); + } + + if(bWT) + { + tC=*pV; + GetTextureTransColG_SPR(&psxVuw[sprA],GETLE16(&psxVuw[clutP+(tC&0x0f)])); + } + } + return; + + case 1: + clutP>>=1;sprtW--; + textX0+=(GlobalTextAddrX<<1) + (textY0<<11); + +#ifdef FASTSOLID + + if(!bCheckMask && !DrawSemiTrans) + { + for(sprCY=0;sprCY 0) + { + dr = ((long)r1 - (long)r0) / dx; + dg = ((long)g1 - (long)g0) / dx; + db = ((long)b1 - (long)b0) / dx; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + d = 2*dy - dx; /* Initial value of d */ + incrE = 2*dy; /* incr. used for move to E */ + incrSE = 2*(dy - dx); /* incr. used for move to SE */ + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + while(x0 < x1) + { + if (d <= 0) + { + d = d + incrE; /* Choose E */ + } + else + { + d = d + incrSE; /* Choose SE */ + y0++; + } + x0++; + + r0+=dr; + g0+=dg; + b0+=db; + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + } +} + +/////////////////////////////////////////////////////////////////////// + +void Line_S_SE_Shade(int x0, int y0, int x1, int y1, unsigned long rgb0, unsigned long rgb1) +{ + int dx, dy, incrS, incrSE, d; + unsigned long r0, g0, b0, r1, g1, b1; + long dr, dg, db; + + r0 = (rgb0 & 0x00ff0000); + g0 = (rgb0 & 0x0000ff00) << 8; + b0 = (rgb0 & 0x000000ff) << 16; + r1 = (rgb1 & 0x00ff0000); + g1 = (rgb1 & 0x0000ff00) << 8; + b1 = (rgb1 & 0x000000ff) << 16; + + dx = x1 - x0; + dy = y1 - y0; + + if (dy > 0) + { + dr = ((long)r1 - (long)r0) / dy; + dg = ((long)g1 - (long)g0) / dy; + db = ((long)b1 - (long)b0) / dy; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + d = 2*dx - dy; /* Initial value of d */ + incrS = 2*dx; /* incr. used for move to S */ + incrSE = 2*(dx - dy); /* incr. used for move to SE */ + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + while(y0 < y1) + { + if (d <= 0) + { + d = d + incrS; /* Choose S */ + } + else + { + d = d + incrSE; /* Choose SE */ + x0++; + } + y0++; + + r0+=dr; + g0+=dg; + b0+=db; + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + } +} + +/////////////////////////////////////////////////////////////////////// + +void Line_N_NE_Shade(int x0, int y0, int x1, int y1, unsigned long rgb0, unsigned long rgb1) +{ + int dx, dy, incrN, incrNE, d; + unsigned long r0, g0, b0, r1, g1, b1; + long dr, dg, db; + + r0 = (rgb0 & 0x00ff0000); + g0 = (rgb0 & 0x0000ff00) << 8; + b0 = (rgb0 & 0x000000ff) << 16; + r1 = (rgb1 & 0x00ff0000); + g1 = (rgb1 & 0x0000ff00) << 8; + b1 = (rgb1 & 0x000000ff) << 16; + + dx = x1 - x0; + dy = -(y1 - y0); + + if (dy > 0) + { + dr = ((long)r1 - (long)r0) / dy; + dg = ((long)g1 - (long)g0) / dy; + db = ((long)b1 - (long)b0) / dy; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + d = 2*dx - dy; /* Initial value of d */ + incrN = 2*dx; /* incr. used for move to N */ + incrNE = 2*(dx - dy); /* incr. used for move to NE */ + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + while(y0 > y1) + { + if (d <= 0) + { + d = d + incrN; /* Choose N */ + } + else + { + d = d + incrNE; /* Choose NE */ + x0++; + } + y0--; + + r0+=dr; + g0+=dg; + b0+=db; + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + } +} + +/////////////////////////////////////////////////////////////////////// + +void Line_E_NE_Shade(int x0, int y0, int x1, int y1, unsigned long rgb0, unsigned long rgb1) +{ + int dx, dy, incrE, incrNE, d; + unsigned long r0, g0, b0, r1, g1, b1; + long dr, dg, db; + + r0 = (rgb0 & 0x00ff0000); + g0 = (rgb0 & 0x0000ff00) << 8; + b0 = (rgb0 & 0x000000ff) << 16; + r1 = (rgb1 & 0x00ff0000); + g1 = (rgb1 & 0x0000ff00) << 8; + b1 = (rgb1 & 0x000000ff) << 16; + + dx = x1 - x0; + dy = -(y1 - y0); + + if (dx > 0) + { + dr = ((long)r1 - (long)r0) / dx; + dg = ((long)g1 - (long)g0) / dx; + db = ((long)b1 - (long)b0) / dx; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + d = 2*dy - dx; /* Initial value of d */ + incrE = 2*dy; /* incr. used for move to E */ + incrNE = 2*(dy - dx); /* incr. used for move to NE */ + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + while(x0 < x1) + { + if (d <= 0) + { + d = d + incrE; /* Choose E */ + } + else + { + d = d + incrNE; /* Choose NE */ + y0--; + } + x0++; + + r0+=dr; + g0+=dg; + b0+=db; + + if ((x0>=drawX)&&(x0=drawY)&&(y0> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + } +} + +/////////////////////////////////////////////////////////////////////// + +void VertLineShade(int x, int y0, int y1, unsigned long rgb0, unsigned long rgb1) +{ + int y, dy; + unsigned long r0, g0, b0, r1, g1, b1; + long dr, dg, db; + + r0 = (rgb0 & 0x00ff0000); + g0 = (rgb0 & 0x0000ff00) << 8; + b0 = (rgb0 & 0x000000ff) << 16; + r1 = (rgb1 & 0x00ff0000); + g1 = (rgb1 & 0x0000ff00) << 8; + b1 = (rgb1 & 0x000000ff) << 16; + + dy = (y1 - y0); + + if (dy > 0) + { + dr = ((long)r1 - (long)r0) / dy; + dg = ((long)g1 - (long)g0) / dy; + db = ((long)b1 - (long)b0) / dy; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + if (y0 < drawY) + { + r0+=dr*(drawY - y0); + g0+=dg*(drawY - y0); + b0+=db*(drawY - y0); + y0 = drawY; + } + + if (y1 > drawH) + y1 = drawH; + + for (y = y0; y <= y1; y++) + { + GetShadeTransCol(&psxVuw[(y<<10)+x],(unsigned short)(((r0 >> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + r0+=dr; + g0+=dg; + b0+=db; + } +} + +/////////////////////////////////////////////////////////////////////// + +void HorzLineShade(int y, int x0, int x1, unsigned long rgb0, unsigned long rgb1) +{ + int x, dx; + unsigned long r0, g0, b0, r1, g1, b1; + long dr, dg, db; + + r0 = (rgb0 & 0x00ff0000); + g0 = (rgb0 & 0x0000ff00) << 8; + b0 = (rgb0 & 0x000000ff) << 16; + r1 = (rgb1 & 0x00ff0000); + g1 = (rgb1 & 0x0000ff00) << 8; + b1 = (rgb1 & 0x000000ff) << 16; + + dx = (x1 - x0); + + if (dx > 0) + { + dr = ((long)r1 - (long)r0) / dx; + dg = ((long)g1 - (long)g0) / dx; + db = ((long)b1 - (long)b0) / dx; + } + else + { + dr = ((long)r1 - (long)r0); + dg = ((long)g1 - (long)g0); + db = ((long)b1 - (long)b0); + } + + if (x0 < drawX) + { + r0+=dr*(drawX - x0); + g0+=dg*(drawX - x0); + b0+=db*(drawX - x0); + x0 = drawX; + } + + if (x1 > drawW) + x1 = drawW; + + for (x = x0; x <= x1; x++) + { + GetShadeTransCol(&psxVuw[(y<<10)+x],(unsigned short)(((r0 >> 9)&0x7c00)|((g0 >> 14)&0x03e0)|((b0 >> 19)&0x001f))); + r0+=dr; + g0+=dg; + b0+=db; + } +} + +/////////////////////////////////////////////////////////////////////// + +void Line_E_SE_Flat(int x0, int y0, int x1, int y1, unsigned short colour) +{ + int dx, dy, incrE, incrSE, d, x, y; + + dx = x1 - x0; + dy = y1 - y0; + d = 2*dy - dx; /* Initial value of d */ + incrE = 2*dy; /* incr. used for move to E */ + incrSE = 2*(dy - dx); /* incr. used for move to SE */ + x = x0; + y = y0; + if ((x>=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y y1) + { + if (d <= 0) + { + d = d + incrN; /* Choose N */ + y--; + } + else + { + d = d + incrNE; /* Choose NE */ + x++; + y--; + } + if ((x>=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y=drawX)&&(x=drawY)&&(y drawH) + y1 = drawH; + + for (y = y0; y <= y1; y++) + GetShadeTransCol(&psxVuw[(y<<10)+x], colour); +} + +/////////////////////////////////////////////////////////////////////// + +void HorzLineFlat(int y, int x0, int x1, unsigned short colour) +{ + int x; + + if (x0 < drawX) + x0 = drawX; + + if (x1 > drawW) + x1 = drawW; + + for (x = x0; x <= x1; x++) + GetShadeTransCol(&psxVuw[(y<<10)+x], colour); +} + +/////////////////////////////////////////////////////////////////////// + +/* Bresenham Line drawing function */ +void DrawSoftwareLineShade(long rgb0, long rgb1) +{ + short x0, y0, x1, y1, xt, yt; + //long rgbt; + float m, dy, dx; + + if(lx0>drawW && lx1>drawW) return; + if(ly0>drawH && ly1>drawH) return; + if(lx0=drawH) return; + if(drawX>=drawW) return; + + x0 = lx0; + y0 = ly0; + x1 = lx1; + y1 = ly1; + + dx = x1 - x0; + dy = y1 - y0; + + if (dx == 0) + { + if (dy > 0) + VertLineShade(x0, y0, y1, rgb0, rgb1); + else + VertLineShade(x0, y1, y0, rgb1, rgb0); + } + else + if (dy == 0) + { + if (dx > 0) + HorzLineShade(y0, x0, x1, rgb0, rgb1); + else + HorzLineShade(y0, x1, x0, rgb1, rgb0); + } + else + { + if (dx < 0) + { + xt = x0; + yt = y0; + //rgbt = rgb0; + x0 = x1; + y0 = y1; + rgb0 = rgb1; + x1 = xt; + y1 = yt; + rgb1 = rgb0; + + dx = x1 - x0; + dy = y1 - y0; + } + + m = dy/dx; + + if (m >= 0) + { + if (m > 1) + Line_S_SE_Shade(x0, y0, x1, y1, rgb0, rgb1); + else + Line_E_SE_Shade(x0, y0, x1, y1, rgb0, rgb1); + } + else + if (m < -1) + Line_N_NE_Shade(x0, y0, x1, y1, rgb0, rgb1); + else + Line_E_NE_Shade(x0, y0, x1, y1, rgb0, rgb1); + } +} + +/////////////////////////////////////////////////////////////////////// + +void DrawSoftwareLineFlat(long rgb) +{ + short x0, y0, x1, y1, xt, yt; + float m, dy, dx; + unsigned short colour = 0; + + if(lx0>drawW && lx1>drawW) return; + if(ly0>drawH && ly1>drawH) return; + if(lx0=drawH) return; + if(drawX>=drawW) return; + + colour = ((rgb & 0x00f80000)>>9) | ((rgb & 0x0000f800)>>6) | ((rgb & 0x000000f8)>>3); + + x0 = lx0; + y0 = ly0; + x1 = lx1; + y1 = ly1; + + dx = x1 - x0; + dy = y1 - y0; + + if (dx == 0) + { + if (dy == 0) + return; // Nothing to draw + else if (dy > 0) + VertLineFlat(x0, y0, y1, colour); + else + VertLineFlat(x0, y1, y0, colour); + } + else + if (dy == 0) + { + if (dx > 0) + HorzLineFlat(y0, x0, x1, colour); + else + HorzLineFlat(y0, x1, x0, colour); + } + else + { + if (dx < 0) + { + xt = x0; + yt = y0; + x0 = x1; + y0 = y1; + x1 = xt; + y1 = yt; + + dx = x1 - x0; + dy = y1 - y0; + } + + m = dy/dx; + + if (m >= 0) + { + if (m > 1) + Line_S_SE_Flat(x0, y0, x1, y1, colour); + else + Line_E_SE_Flat(x0, y0, x1, y1, colour); + } + else + if (m < -1) + Line_N_NE_Flat(x0, y0, x1, y1, colour); + else + Line_E_NE_Flat(x0, y0, x1, y1, colour); + } +} + +/////////////////////////////////////////////////////////////////////// diff --git a/PeopsSoftGPU/soft.h b/PeopsSoftGPU/soft.h new file mode 100644 index 0000000..eec428a --- /dev/null +++ b/PeopsSoftGPU/soft.h @@ -0,0 +1,54 @@ +/*************************************************************************** + soft.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2002/06/04 - Lewpy +// - new line drawing funcs +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#ifndef _GPU_SOFT_H_ +#define _GPU_SOFT_H_ + +void offsetPSXLine(void); +void offsetPSX2(void); +void offsetPSX3(void); +void offsetPSX4(void); + +void FillSoftwareAreaTrans(short x0,short y0,short x1,short y1,unsigned short col); +void FillSoftwareArea(short x0,short y0,short x1,short y1,unsigned short col); +void drawPoly3G(long rgb1, long rgb2, long rgb3); +void drawPoly4G(long rgb1, long rgb2, long rgb3, long rgb4); +void drawPoly3F(long rgb); +void drawPoly4F(long rgb); +void drawPoly4FT(unsigned char * baseAddr); +void drawPoly4GT(unsigned char * baseAddr); +void drawPoly3FT(unsigned char * baseAddr); +void drawPoly3GT(unsigned char * baseAddr); +void DrawSoftwareSprite(unsigned char * baseAddr,short w,short h,long tx,long ty); +void DrawSoftwareSpriteTWin(unsigned char * baseAddr,long w,long h); +void DrawSoftwareSpriteMirror(unsigned char * baseAddr,long w,long h); +void DrawSoftwareLineShade(long rgb0, long rgb1); +void DrawSoftwareLineFlat(long rgb); + +#endif // _GPU_SOFT_H_ diff --git a/PeopsSoftGPU/stdafx.h b/PeopsSoftGPU/stdafx.h new file mode 100644 index 0000000..de94182 --- /dev/null +++ b/PeopsSoftGPU/stdafx.h @@ -0,0 +1,35 @@ +/*************************************************************************** + stdafx.h - description + ------------------- + begin : Sun Oct 28 2001 + copyright : (C) 2001 by Pete Bernert + email : BlackDove@addcom.de + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ + +//*************************************************************************// +// History of changes: +// +// 2001/10/28 - Pete +// - generic cleanup for the Peops release +// +//*************************************************************************// + +#define __inline inline +#define CALLBACK + +#include +#include +#include +#include +#include + diff --git a/PeopsSoftGPU/swap.h b/PeopsSoftGPU/swap.h new file mode 100644 index 0000000..2d9ef0a --- /dev/null +++ b/PeopsSoftGPU/swap.h @@ -0,0 +1,51 @@ + +// byteswappings + +#define SWAP16(x) (((x)>>8 & 0xff) | ((x)<<8 & 0xff00)) +#define SWAP32(x) (((x)>>24 & 0xfful) | ((x)>>8 & 0xff00ul) | ((x)<<8 & 0xff0000ul) | ((x)<<24 & 0xff000000ul)) + +// big endian config +#define HOST2LE32(x) SWAP32(x) +#define HOST2BE32(x) (x) +#define LE2HOST32(x) SWAP32(x) +#define BE2HOST32(x) (x) + +#define HOST2LE16(x) SWAP16(x) +#define HOST2BE16(x) (x) +#define LE2HOST16(x) SWAP16(x) +#define BE2HOST16(x) (x) + +#define GETLEs16(X) ((short)GETLE16((unsigned short *)X)) +#define GETLEs32(X) ((short)GETLE32((unsigned short *)X)) + +#ifdef _BIG_ENDIAN +// GCC style +extern __inline__ unsigned short GETLE16(unsigned short *ptr) { + unsigned short ret; __asm__ ("lhbrx %0, 0, %1" : "=r" (ret) : "r" (ptr)); + return ret; +} +extern __inline__ unsigned long GETLE32(unsigned long *ptr) { + unsigned long ret; + __asm__ ("lwbrx %0, 0, %1" : "=r" (ret) : "r" (ptr)); + return ret; +} +extern __inline__ unsigned long GETLE16D(unsigned long *ptr) { + unsigned long ret; + __asm__ ("lwbrx %0, 0, %1\n" + "rlwinm %0, %0, 16, 0, 31" : "=r" (ret) : "r" (ptr)); + return ret; +} + +extern __inline__ void PUTLE16(unsigned short *ptr, unsigned short val) { + __asm__ ("sthbrx %0, 0, %1" : : "r" (val), "r" (ptr) : "memory"); +} +extern __inline__ void PUTLE32(unsigned long *ptr, unsigned long val) { + __asm__ ("stwbrx %0, 0, %1" : : "r" (val), "r" (ptr) : "memory"); +} +#else // _BIG_ENDIAN +#define GETLE16(X) ((unsigned short *)X) +#define GETLE32(X) ((unsigned long *)X) +#define GETLE16D(X) ({unsigned long val = GETLE32(X); (val<<16 | val >> 16)}) +#define PUTLE16(X, Y) {((unsigned short *)X)=(unsigned short)X} +#define PUTLE32(X, Y) {((unsigned long *)X)=(unsigned long)X} +#endif //!_BIG_ENDIAN diff --git a/PeopsSoftGPU/type.h b/PeopsSoftGPU/type.h new file mode 100644 index 0000000..625ef00 --- /dev/null +++ b/PeopsSoftGPU/type.h @@ -0,0 +1,24 @@ +#ifndef TYPE_H +#define TYPE_H + +// Return values (should be applied to the entire code). +#define FPSE_OK 0 +#define FPSE_ERR -1 +#define FPSE_WARN 1 + + +typedef signed char INT8; +typedef signed short int INT16; +typedef signed long int INT32; + +typedef unsigned char UINT8; +typedef unsigned short int UINT16; +typedef unsigned long int UINT32; + +#ifdef __GNUC__ +#define INT64 long long +#else +#define INT64 __int64 +#endif + +#endif diff --git a/cdrmooby28/CDDAData.cpp b/cdrmooby28/CDDAData.cpp new file mode 100644 index 0000000..9c31c92 --- /dev/null +++ b/cdrmooby28/CDDAData.cpp @@ -0,0 +1,253 @@ +/************************************************************************ + +Copyright mooby 2002 +Copyright tehpola 2010 + +CDRMooby2 CDDAData.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include "CDDAData.hpp" + +using namespace std; + +extern std::string programName; + +static sem_t audioReady; +#define REPEATALL 0 +#define REPEATONE 1 +#define PLAYONE 2 +static int repeatPref = REPEATALL; + +static void* CDDAThread(void* userData){ + return NULL; +} + +// this callback repeats one track over and over +int CDDACallbackRepeat( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + /*PaTimestamp outTime,*/ void *userData ) +{ + unsigned int i; +/* Cast data passed through stream to our structure type. */ + PlayCDDAData* data = (PlayCDDAData*)userData; + short* out = (short*)outputBuffer; + + data->theCD->seek(data->CDDAPos); + short* buffer = (short*)data->theCD->getBuffer(); + + buffer += data->frameOffset; + + float volume = data->volume; + + // buffer the data + for( i=0; iframeOffset += 4; + + // at the end of a frame, get the next one + if (data->frameOffset == bytesPerFrame) + { + data->CDDAPos += CDTime(0,0,1); + + // when at the end of this track, loop to the start + // of this track + if (data->CDDAPos == data->CDDAEnd) + { + data->CDDAPos = data->CDDAStart; + } + + data->theCD->seek(data->CDDAPos); + data->frameOffset = 0; + buffer = (short*)data->theCD->getBuffer(); + } + } + return 0; +} + +// this callback plays through one track once and stops +int CDDACallbackOneTrackStop( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + /*PaTimestamp outTime,*/ void *userData ) +{ + unsigned int i; +/* Cast data passed through stream to our structure type. */ + PlayCDDAData* data = (PlayCDDAData*)userData; + short* out = (short*)outputBuffer; + short* buffer; + + // seek to the current CDDA read position + if (!data->endOfTrack) + { + data->theCD->seek(data->CDDAPos); + buffer = (short*)data->theCD->getBuffer(); + } + else + { + buffer = (short*)data->nullAudio; + } + + buffer += data->frameOffset; + + float volume = data->volume; + + // buffer the data + for( i=0; iframeOffset += 4; + + // at the end of a frame, get the next one + if (data->frameOffset == bytesPerFrame) + { + data->CDDAPos += CDTime(0,0,1); + + // when at the end of this track, use null audio + if (data->CDDAPos == data->CDDAEnd) + { + data->endOfTrack = true; + buffer = (short*)data->nullAudio; + data->CDDAPos -= CDTime(0,0,1); + data->frameOffset = 0; + } + // not at end of track, just do normal buffering + else + { + data->theCD->seek(data->CDDAPos); + data->frameOffset = 0; + buffer = (short*)data->theCD->getBuffer(); + } + } + } + return 0; +} + +PlayCDDAData::PlayCDDAData(const std::vector &ti, const CDTime &gapLength) + : stream(NULL), volume(1), + frameOffset(0), theCD(NULL), trackList(ti), playing(false), + repeat(false), endOfTrack(false), pregapLength(gapLength) +{ + memset(nullAudio, 0, sizeof(nullAudio)); + + live = true; + LWP_SemInit(&audioReady, 1, 1); + LWP_SemInit(&firstAudio, 0, 1); + LWP_CreateThread(&audioThread, CDDAThread, this, + audioStack, audioStackSize, audioPriority); +} + +PlayCDDAData::~PlayCDDAData() +{ + if (playing) stop(); + live = false; + LWP_SemPost(firstAudio); + LWP_SemDestroy(audioReady); + LWP_SemDestroy(firstAudio); + LWP_JoinThread(audioThread, NULL); + delete theCD; +} + +// initialize the CDDA file data and initalize the audio stream +void PlayCDDAData::openFile(const std::string& file, int type) +{ + std::string extension; + theCD = FileInterfaceFactory(file, extension, type); + theCD->setPregap(pregapLength, trackList[2].trackStart); + // disable extra caching on the file interface + theCD->setCacheMode(FileInterface::oldMode); +} + +// start playing the data +int PlayCDDAData::play(const CDTime& startTime) +{ + CDTime localStartTime = startTime; + + // if play was called with the same time as the previous call, + // dont restart it. this fixes a problem with FPSE's play call. + // of course, if play is called with a different track, + // stop playing the current stream. + if (playing) + { + if (startTime == InitialTime) + { + return 0; + } + else + { + stop(); + } + } + + InitialTime = startTime; + + + // figure out which track to play to set the end time + if ( repeatPref != REPEATALL ) + { + unsigned int i = 1; + while ( (i < (trackList.size() - 1)) && (startTime > trackList[i].trackStart) ) + { + i++; + } + // adjust the start time if it's blatantly off from the start time... + if (localStartTime > trackList[i].trackStart) + { + if ( (localStartTime - trackList[i].trackStart) > CDTime(0,2,0)) + { + localStartTime = trackList[i].trackStart; + } + } + else + { + if ( (trackList[i].trackStart - localStartTime) > CDTime(0,2,0)) + { + localStartTime = trackList[i].trackStart; + } + } + CDDAStart = localStartTime; + CDDAEnd = trackList[i].trackStart + trackList[i].trackLength; + } + else //repeatPref == REPEATALL + { + CDDAEnd = trackList[trackList.size() - 1].trackStart + + trackList[trackList.size() - 1].trackLength; + CDDAStart = trackList[2].trackStart; + if (localStartTime > CDDAEnd) + { + localStartTime = CDDAStart; + } + } + + // set the cdda position, start and end times + CDDAPos = localStartTime; + + endOfTrack = false; + + playing = true; + + // open a stream - pass in this CDDA object as the user data. + // depending on the play mode, use a different callback + LWP_SemPost(firstAudio); + + return 0; +} + +// close the stream - nice and simple +int PlayCDDAData::stop() +{ + if (playing) + { + playing = false; + } + return 0; +} + diff --git a/cdrmooby28/CDDAData.hpp b/cdrmooby28/CDDAData.hpp new file mode 100644 index 0000000..298af00 --- /dev/null +++ b/cdrmooby28/CDDAData.hpp @@ -0,0 +1,113 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 CDDAData.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + + +#ifndef CDDADATA_HPP +#define CDDADATA_HPP + +#include "FileInterface.hpp" +#include "CDTime.hpp" +#include "TrackInfo.hpp" + +#include +#include +#include + +// CDDA data virtual base class +class CDDAData +{ +public: + CDDAData() {} + virtual ~CDDAData() {} + virtual void openFile(const std::string& file, int type) = 0; + virtual int play(const CDTime& startTime) = 0; + virtual int stop() = 0; + virtual bool isPlaying(void) {return false;} + virtual CDTime playTime(void) {return CDTime();} +}; + +// if there's no CDDA data, just return sensible values +class NoCDDAData : public CDDAData +{ +public: + NoCDDAData() {} + virtual ~NoCDDAData() {} + virtual void openFile(const std::string& file, int type) {} + virtual int play(const CDTime& startTime) {return 0;} + virtual int stop() {return 0;} +}; + +// for really playing CDDA data. +class PlayCDDAData : public CDDAData +{ +public: + // ti is the list of track lengths. + // sets the volume from whatever is stored in the preferences + PlayCDDAData(const std::vector &ti, const CDTime &gapLength); + + // cleans up + virtual ~PlayCDDAData(); + + // opens the file and readies the plugin for playing + virtual void openFile(const std::string& file, int type); + // plays data starting at startTime + virtual int play(const CDTime& startTime); + // stops playing + virtual int stop(); + + virtual bool isPlaying(void) {return playing;} + virtual CDTime playTime(void) {return CDDAPos;} + + // All the data members are public so they can be accessed by the PortAudio + // callback + + char* stream; + + bool live; + sem_t firstAudio; + + lwp_t audioThread; + static const int audioPriority = 128; + static const int audioStackSize = 1024; + unsigned char audioStack[audioStackSize]; + + // the volume as set in the configuration window + float volume; + // the current position of playing + CDTime CDDAPos; + // the end time of this track + CDTime CDDAEnd; + // the start time taken from play() + CDTime CDDAStart; + CDTime InitialTime; + // the offset into the frame that it's currently playing from + unsigned long frameOffset; + // a FileInterface for getting the data from + FileInterface* theCD; + // the track list of the CD for calculating times n such + std::vector trackList; + // if true, it's playing. + bool playing; + // if true, the track will repeat when it's done playing + bool repeat; + // a buffer of null audio if repeat is off + char nullAudio[bytesPerFrame]; + // if true and repeating one track, this is at the end of the currently playing track + bool endOfTrack; + // length of the pregap between tracks 1 and 2 + CDTime pregapLength; + // time of the pregap + CDTime pregapTime; +}; + +#endif diff --git a/cdrmooby28/CDInterface.hpp b/cdrmooby28/CDInterface.hpp new file mode 100644 index 0000000..18b62f8 --- /dev/null +++ b/cdrmooby28/CDInterface.hpp @@ -0,0 +1,163 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 CDInterface.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + +#ifndef CDINTERFACE_HPP +#define CDINTERFACE_HPP + +#include +#include + +#include "TrackInfo.hpp" +#include "SubchannelData.hpp" +#include "CDDAData.hpp" +#include "TrackParser.hpp" +#include "FileInterface.hpp" + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +}; + +extern TDTNFormat tdtnformat; +extern std::string programName; + +// a container class for holding all the CD info needed +class CDInterface +{ +public: + CDInterface() + : scd(NULL), + cdda(NULL), image(NULL) + { + // based on the program name, decide what order to return the + // track info. fyi, tester is my testing/development program. + tdtnformat = fsmint; + } + + // opens the file + inline void open(const std::string& str); + + // cleans up + ~CDInterface() + { + if (cdda) + delete cdda; + if (image) + delete image; + if (scd) + delete scd; + } + + // returns the number of tracks - 1 because trackList[0] is + // the full CD length + inline unsigned long getNumTracks() const + {return trackList.size() - 1;} + + // returns the TrackInfo for trackNum + inline TrackInfo getTrackInfo(const unsigned long trackNum) const + throw(Exception); + + // seeks the data pointer to time + inline void moveDataPointer(const CDTime& time) throw(Exception) + { + image->seek(time); + scd->seek(time); + } + // returns the pointer to the data buffer + inline unsigned char* readDataPointer() const + {return image->getBuffer();} + // returns the pointer to the subchannel data + inline unsigned char* readSubchannelPointer() const + {return scd->get();} + // returns the CD length + inline CDTime getCDLength() {return image->getCDLength();} + + // starts CDDA playing at time + inline int playTrack(const CDTime& time) {return cdda->play(time);} + // stops CDDA playing + inline int stopTrack() {return cdda->stop();} + // returns the time of the sector that's currently being read + inline CDTime readTime(void) + { + if (cdda->isPlaying()) + return cdda->playTime(); + else + return image->getSeekTime(); + } + // returns whether or not the CDDA is playing + inline bool isPlaying (void) {return cdda->isPlaying();} + +private: + // a vector of track info that stores the start, end, and length of each track + std::vector trackList; + + // the subchannel data for the cd + SubchannelData* scd; + // the CDDA data for the cd + CDDAData* cdda; + // the interface to the CD image itself + FileInterface* image; +}; + +// initalizes all the data for CDInterface based on a file name from +// CDOpen +inline void CDInterface::open(const std::string& str) +{ + // use the FIFactory to make the FileInterface + std::string extension; + image = FileInterfaceFactory(str, extension, FILE_BROWSER_ISO_FILE_PTR); + + std::string fileroot = str; + fileroot.erase(fileroot.rfind(extension)); + + TrackParser* tp = TrackParserFactory(fileroot, image); + tp->parse(); + tp->postProcess(image->getCDLength()); + trackList = tp->getTrackList(); + delete tp; + + // if there is more than one track, initalize the CDDA data + if (trackList.size() > 2) + { + cdda = new PlayCDDAData(trackList, tp->getPregapLength()); + cdda->openFile(str, FILE_BROWSER_CDDA_FILE_PTR); + } + else + { + cdda = new NoCDDAData(); + } + + // build the subchannel data + scd = SubchannelDataFactory(fileroot, FILE_BROWSER_SUB_FILE_PTR); + + if (trackList.size() > 2) + { + image->setPregap(tp->getPregapLength(), trackList[2].trackStart); + } + +} + +// returns the TrackInfo for trackNum if it exists +inline TrackInfo CDInterface::getTrackInfo(const unsigned long trackNum) const + throw(Exception) +{ + if (trackNum >= trackList.size()) + { + std::ostringstream ost; + ost << trackNum << std::endl; + Exception e(std::string("Track number out of bounds") + ost.str()); + THROW(e); + } + return trackList[trackNum]; +} + +#endif diff --git a/cdrmooby28/CDTime.hpp b/cdrmooby28/CDTime.hpp new file mode 100644 index 0000000..4128cb8 --- /dev/null +++ b/cdrmooby28/CDTime.hpp @@ -0,0 +1,485 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 CDTime.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + + +#ifndef CDTIME_HPP +#define CDTIME_HPP + +#include "Utils.hpp" +#include "Exception.hpp" + +#include +#include +extern "C" { + #include + #include + #include + #include + #include + #include +} + +// MSFTime is a container for minute, second, and frame +class MSFTime +{ +public: + // default 0:0:0 + MSFTime() : minute(0), sec(0), frame(0) {} + + // various constructors... + MSFTime(const unsigned char m, const unsigned char s, const unsigned char f) + : minute(m), sec(s), frame(f) {} + + MSFTime(const unsigned char* msf, const TDTNFormat format) + : minute(0), sec(0), frame(0) + {setMSF(msf, format);} + + MSFTime(const MSFTime& r) : minute(r.minute), sec(r.sec), frame(r.frame) {} + + inline void setMSF(const unsigned char m, const unsigned char s, const unsigned char f) + {minute = m; sec = s; frame = f;} + + // sets this MSF time based on format. format tells the order of the + // frame, min and sec in the char* and whether or not it's integer or BCD + inline void setMSF(const unsigned char* msf, const TDTNFormat format) + { + if (format == msfbcd) + { + minute = BCDToInt(msf[0]); + sec = BCDToInt(msf[1]); + frame = BCDToInt(msf[2]); + } + else if (format == msfint) + { + minute = msf[0]; + sec = msf[1]; + frame = msf[2]; + } + else if (format == fsmbcd) + { + minute = BCDToInt(msf[2]); + sec = BCDToInt(msf[1]); + frame = BCDToInt(msf[0]); + } + else if (format == fsmint) + { + minute = msf[2]; + sec = msf[1]; + frame = msf[0]; + } + } + + inline unsigned char m() const + {return minute;} + + inline unsigned char s() const + {return sec;} + + inline unsigned char f() const + {return frame;} + + inline friend std::ostream& operator<<(std::ostream& o, const MSFTime& m); + inline friend std::istream& operator>>(std::istream& i, MSFTime& m); + + // Note that this does NOT return a reference + inline unsigned char operator[](const size_t index) const + throw(Exception) + { + switch(index) + { + case 0: return minute; + case 1: return sec; + case 2: return frame; + default: + { + Exception e("Index out of range"); + THROW(e); + } + } + } + +private: + unsigned char minute; + unsigned char sec; + unsigned char frame; +}; + +// CDTime contains all the data conversions, operations, and types needed for +// calculating any type of time used in this plugin +class CDTime +{ +public: + // CDTime holds the time in 3 ways - msf, absoluteByte, and absoluteFrame. + // This enum tells what conversions have been done on the data. + enum conversionType + { + msf = 0x01, + abByte = 0x02, + abFrame = 0x04, + allTypes = 0x07 + }; + + CDTime() + : conversions(0), absoluteByte(0), absoluteFrame(0) + {} + + CDTime(const CDTime& r) + : conversions(r.conversions), MSF(r.MSF), absoluteByte(r.absoluteByte), absoluteFrame(r.absoluteFrame) + {} + + CDTime(const unsigned char m, const unsigned char s, const unsigned char f) + : conversions(msf), MSF(m, s, f), absoluteByte(0), absoluteFrame(0) + {convertTime();} + + CDTime(const unsigned char* msftime, const TDTNFormat format) + : conversions(msf), MSF(msftime, format), absoluteByte(0), absoluteFrame(0) + { + convertTime(); + } + + explicit CDTime(const MSFTime& msftime) + : conversions(msf), MSF(msftime), absoluteByte(0), absoluteFrame(0) + {convertTime();} + + // converts a time like 00:00:00 to a CD time + explicit CDTime(const std::string& str) + : conversions(msf), absoluteByte(0), absoluteFrame(0) + { + MSF.setMSF(atoi(str.substr(0,2).c_str()), atoi(str.substr(3, 2).c_str()), + atoi(str.substr(6, 2).c_str())); + convertTime(); + } + + // constructor for absoluteByte and absoluteFrame + CDTime(const unsigned long absoluteAddr, const conversionType ct); + + // math and comparison operators + inline bool operator<(const CDTime& r) const; + inline bool operator>(const CDTime& r) const; + inline bool operator==(const CDTime& r) const; + inline bool operator!=(const CDTime& r) const; + inline bool operator<=(const CDTime& r) const; + inline bool operator>=(const CDTime& r) const; + + // using the default operator= + inline CDTime& operator+=(const CDTime& r); + inline CDTime& operator-=(const CDTime& r); + inline CDTime operator+(const CDTime& r) const; + inline CDTime operator-(const CDTime& r) const; + + // access and set operators + inline MSFTime getMSF() const; + inline CDTime& setMSF(const MSFTime& r); + + // this one is special - it converts the MSFTime into the TDTNFormat format + // and stores it in an internal buffer, then returns a pointer to that buffer. + // This is really useful for GetTD. + inline unsigned char* getMSFbuf(const TDTNFormat format = msfint) const; + + inline unsigned long getAbsoluteByte() const; + inline CDTime& setAbsoluteByte(const unsigned long ab); + + inline unsigned long getAbsoluteFrame() const; + inline CDTime& setAbsoluteFrame(const unsigned long af); + + inline friend std::ostream& operator<<(std::ostream& o, const CDTime& cdt); + inline friend std::istream& operator>>(std::istream& i, CDTime& m); + +private: + // based on what conversions have already been done on the data, convertTime + // sets whatever data members have not been set yet. + inline void convertTime() + throw(Exception); + + // Data members + + // this holds what conversions that have already been done on the data (with bitmasks) + unsigned char conversions; + + // the time data + MSFTime MSF; + unsigned long absoluteByte; + unsigned long absoluteFrame; + // used for converting time to unsigned char[3] + unsigned char MSFbuf[3]; +}; + +inline std::ostream& operator<<(std::ostream& o, const MSFTime& m) +{ + o << std::setfill('0') << std::setw(2) << (int)m.m() + << ':' << std::setw(2) << (int)m.s() + << ':' << std::setw(2) << (int)m.f(); + return o; +} + +inline std::istream& operator>>(std::istream& i, MSFTime& m) +{ + std::ios::iostate state = i.exceptions(); + i.exceptions(std::ios::failbit|std::ios::badbit|std::ios::eofbit); + try + { + char c; + int minute, sec, frame; + i >> minute >> c >> sec >> c >> frame; + m.minute = minute; + m.sec = sec; + m.frame = frame; + } + catch(...) + { + i.setstate(std::ios::failbit); + } + i.exceptions(state); + return i; +} + +inline CDTime::CDTime(const unsigned long absoluteAddr, const conversionType ct) + : conversions(0), absoluteByte(0), absoluteFrame(0) +{ + if (ct == abByte) + { + conversions = ct; + absoluteByte = absoluteAddr; + convertTime(); + } + else if (ct == abFrame) + { + conversions = ct; + absoluteFrame = absoluteAddr; + convertTime(); + } +} + +inline bool CDTime::operator<(const CDTime& r) const +{ + return absoluteByte < r.absoluteByte; +} + +inline bool CDTime::operator>(const CDTime& r) const +{ + return absoluteByte > r.absoluteByte; +} + +inline bool CDTime::operator==(const CDTime& r) const +{ + return absoluteByte == r.absoluteByte; +} + +inline bool CDTime::operator!=(const CDTime& r) const +{ + return absoluteByte != r.absoluteByte; +} + +inline bool CDTime::operator<=(const CDTime& r) const +{ + return absoluteByte <= r.absoluteByte; +} + +inline bool CDTime::operator>=(const CDTime& r) const +{ + return absoluteByte >= r.absoluteByte; +} + +inline CDTime& CDTime::operator+=(const CDTime& r) +{ + absoluteByte += r.absoluteByte; + conversions = abByte; + convertTime(); + return *this; +} + +inline CDTime& CDTime::operator-=(const CDTime& r) +{ + absoluteByte -= r.absoluteByte; + conversions = abByte; + convertTime(); + return *this; +} + +inline CDTime CDTime::operator+(const CDTime& r) const +{ + CDTime temp(*this); + return (temp += r); +} + +inline CDTime CDTime::operator-(const CDTime& r) const +{ + CDTime temp(*this); + return (temp -= r); +} + +inline MSFTime CDTime::getMSF() const +{ + return MSF; +} + +inline CDTime& CDTime::setMSF(const MSFTime& r) +{ + MSF = r; + conversions = msf; + convertTime(); + return *this; +} + +inline unsigned char* CDTime::getMSFbuf(const TDTNFormat format) const +{ + CDTime& thisCDTime = const_cast(*this); + if (format == msfbcd) + { + thisCDTime.MSFbuf[0] = intToBCD(MSF.m()); + thisCDTime.MSFbuf[1] = intToBCD(MSF.s()); + thisCDTime.MSFbuf[2] = intToBCD(MSF.f()); + } + else if (format == fsmbcd) + { + thisCDTime.MSFbuf[0] = intToBCD(MSF.f()); + thisCDTime.MSFbuf[1] = intToBCD(MSF.s()); + thisCDTime.MSFbuf[2] = intToBCD(MSF.m()); + } + else if (format == fsmint) + { + thisCDTime.MSFbuf[0] = MSF.f(); + thisCDTime.MSFbuf[1] = MSF.s(); + thisCDTime.MSFbuf[2] = MSF.m(); + } + else if (format == msfint) + { + thisCDTime.MSFbuf[0] = MSF.m(); + thisCDTime.MSFbuf[1] = MSF.s(); + thisCDTime.MSFbuf[2] = MSF.f(); + } + return (unsigned char*)&MSFbuf; +} + + +inline unsigned long CDTime::getAbsoluteByte() const +{ + return absoluteByte; +} + +inline CDTime& CDTime::setAbsoluteByte(const unsigned long ab) +{ + absoluteByte = ab; + conversions = abByte; + convertTime(); + return *this; +} + +inline unsigned long CDTime::getAbsoluteFrame() const +{ + return absoluteFrame; +} + +inline CDTime& CDTime::setAbsoluteFrame(const unsigned long af) +{ + absoluteFrame = af; + conversions = abFrame; + convertTime(); + return *this; +} + + +// set all the times for the conversions that have not been done yet. +// at the end of the function, all the conversions should be done. +inline void CDTime::convertTime() + throw(Exception) +{ + // if no times are set, throw an error + if (conversions == 0) + { + Exception e("Cannot perform time conversion"); + THROW(e); + } + if (conversions & msf) + { + if (! (conversions & abByte)) + { + absoluteByte = MSF.m() * bytesPerMinute + + MSF.s() * bytesPerSecond + + MSF.f() * bytesPerFrame; + } + if (! (conversions & abFrame)) + { + absoluteFrame = MSF.m() * framesPerMinute + + MSF.s() * framesPerSecond + + MSF.f(); + } + } + else if (conversions & abByte) + { + if (! (conversions & msf)) + { + unsigned char m = absoluteByte / bytesPerMinute; + unsigned char s = (absoluteByte - m * bytesPerMinute) / bytesPerSecond; + unsigned char f = (absoluteByte - m * bytesPerMinute - s * bytesPerSecond) / + bytesPerFrame; + MSF.setMSF(m, s, f); + } + if (! (conversions & abFrame)) + { + absoluteFrame = absoluteByte / bytesPerFrame; + } + } + else if (conversions & abFrame) + { + if (! (conversions & msf)) + { + unsigned char m = absoluteFrame / framesPerMinute; + unsigned char s = (absoluteFrame - m * framesPerMinute) / framesPerSecond; + unsigned char f = absoluteFrame - m * framesPerMinute - s * framesPerSecond; + MSF.setMSF(m, s, f); + } + if (! (conversions & abByte)) + { + absoluteByte = absoluteFrame * bytesPerFrame; + } + } + else + { + Exception e("Unknown conversion type"); + THROW(e); + } + conversions |= allTypes; +} + +inline std::ostream& operator<<(std::ostream& o, const CDTime& cdt) +{ + if (cdt.conversions == 0) + { + o << "Time not set" << std::endl; + return o; + } + if (cdt.conversions & CDTime::msf) + { + o << "MSF: " << cdt.MSF << std::endl; + } + if (cdt.conversions & CDTime::abByte) + { + o << "Absolute byte: " << cdt.absoluteByte << std::endl; + } + if (cdt.conversions & CDTime::abFrame) + { + o << "Absolute frame: " << cdt.absoluteFrame << std::endl; + } + return o; +} + + +inline std::istream& operator>>(std::istream& i, CDTime& cdt) +{ + i >> cdt.MSF; + cdt.convertTime(); + return i; +} +#endif + diff --git a/cdrmooby28/Exception.hpp b/cdrmooby28/Exception.hpp new file mode 100644 index 0000000..e62ca29 --- /dev/null +++ b/cdrmooby28/Exception.hpp @@ -0,0 +1,56 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 Exception.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#ifndef EXCEPTION_HPP +#define EXCEPTION_HPP + +#include +#include +#include +#include + +// the exception data for the plugin. stores the line number too +// for easy debugging +class Exception +{ +public: + Exception() : line(0) {} + + explicit Exception(const std::string& str) + : line(0) {error.push_back(str);} + + inline void setLine(const unsigned long l) {line = l;} + inline void setFile(const std::string& str) {file = str;} + inline void addText(const std::string& str) {error.push_back(str);} + inline std::string text() {std::ostringstream str; str << *this; return str.str();} + + inline friend std::ostream& operator<<(std::ostream& o, const Exception& m); + +private: + unsigned long line; + std::string file; + std::vector error; +}; + +inline std::ostream& operator<<(std::ostream& o, const Exception& m) +{ + std::vector::size_type index; + for(index = 0; index < m.error.size(); index++) + o << m.error[index]<< std::endl; + o << "On line: " << m.line << std::endl + << "In file: " << m.file << std::endl; + return o; +} + +#define THROW(e) e.setLine(__LINE__); e.setFile(__FILE__); moobyMessage(e.text().c_str()); throw(e); + +#endif diff --git a/cdrmooby28/FileInterface.cpp b/cdrmooby28/FileInterface.cpp new file mode 100644 index 0000000..40f7eab --- /dev/null +++ b/cdrmooby28/FileInterface.cpp @@ -0,0 +1,185 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 FileInterface.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include "FileInterface.hpp" +#include "TrackParser.hpp" +#include "Utils.hpp" + +#include + +#include + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-DVD.h" +#include "../fileBrowser/fileBrowser-CARD.h" +extern fileBrowser_file isoFile; +extern fileBrowser_file cddaFile; +extern fileBrowser_file subFile; +}; + +// leave this here or the unrarlib will complain about errors +using namespace std; + +FileInterface::FileInterface(const unsigned long requestedFrames, + const unsigned long requiredFrames) : + filePtr(NULL), + bufferPointer(NULL), + pregapTime (CDTime(99,59,74)), + pregapLength (CDTime(0,0,0)), + cacheMode(oldMode) +{ + fileBuffer = NULL; + + cache.setMaxSize(1); + if (requiredFrames != 0) + { + bufferFrames = (requestedFrames < requiredFrames) ? requiredFrames : requestedFrames; + fileBuffer = new unsigned char[bufferFrames * bytesPerFrame]; + } + else + { + bufferFrames = 0; + } +} + + +// given a file name, return the extension of the file and +// return the correct FileInterface for that file type +FileInterface* FileInterfaceFactory(const std::string& filename, + string& extension, int type) +{ + // for every file type that's supported, try to match the extension + FileInterface* image; + char buf[1024]; + memset( buf, '\0', 1024 ); + + if (extensionMatches(filename, ".ccd")) + { + moobyMessage("Please open the image and not the ccd file."); + image = new UncompressedFileInterface(1); + extension = filename.substr(filename.find_last_of('.')); + filename.copy(buf, filename.find_last_of('.')); + image->openFile(buf + string(".img"), type); + } + + // the CUE interface will take the name of the file + // in the cue sheet and open it as an uncompressed file + else if (extensionMatches(filename, ".cue")) + { + moobyMessage("Please open the image and not the cue sheet."); + extension = filename.substr(filename.find_last_of('.')); + CueParser cp(filename); + cp.parse(); + image = new UncompressedFileInterface(1); + + // try to figure out the directory of the image. + // if none is in the cue sheet, + // just use the directory of filename. + std::string::size_type pos = cp.getCDName().rfind('/'); + if (pos == std::string::npos) + { + pos = cp.getCDName().rfind('\\'); + } + if (pos == std::string::npos) + { + pos = filename.rfind('/'); + if (pos == std::string::npos) + pos = filename.rfind('\\'); + image->openFile(std::string(filename).erase(pos + 1) + cp.getCDName(), type); + } + else + { + image->openFile(cp.getCDName(), type); + } + } + // all other file types that aren't directly supported, + // try to open them with UncompressedFileInterface + else + { + if (extensionMatches(filename, ".iso")) + { + moobyMessage("This plugin does not support ISO-9660 images. " + "If this is a binary image, rename it with a \".bin\" extension."); + } + + extension = filename.substr(filename.find_last_of('.')); + image = new UncompressedFileInterface(1); + image->openFile(filename, type); + } + + if (image) + return image; + else + { + Exception e(string("Error opening file: ") + filename); + THROW(e); + } +} + +FileInterface& FileInterface::setPregap(const CDTime& gapLength, + const CDTime& gapTime) +{ + if (pregapLength == CDTime(0,0,0)) + { + pregapLength = gapLength; + pregapTime = gapTime; + CDLength += gapLength; + } + return *this; +} + +// opens the file and calculates the length of the cd +void FileInterface::openFile(const std::string& str, int type) + throw(Exception) +{ + fileBrowser_file tempFile; + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], str.c_str()); + + if(isoFile_open(&tempFile) == FILE_BROWSER_ERROR_NO_FILE) { + Exception e(std::string("Cannot open file: ") + str + "\r\n"); + THROW(e); + } + + if(type==FILE_BROWSER_ISO_FILE_PTR) { + memcpy(&isoFile, &tempFile, sizeof(fileBrowser_file)); + isoFile.attr = type; + filePtr = &isoFile; + } + else if(type==FILE_BROWSER_CDDA_FILE_PTR) { + isoFile_deinit(&cddaFile); + memcpy(&cddaFile, &tempFile, sizeof(fileBrowser_file)); + cddaFile.attr = type; + filePtr = &cddaFile; + } + + isoFile_seekFile(filePtr,0,FILE_BROWSER_SEEK_SET); + fileName = str; + CDLength= CDTime(filePtr->size, CDTime::abByte) + CDTime(0,2,0); + + bufferPos.setMSF(MSFTime(255,255,255)); +} + +// reads data into the cache for UncompressedFileInterface +void UncompressedFileInterface::seekUnbuffered(const CDTime& cdt) + throw(std::exception, Exception) +{ + CDTime seekTime(cdt - CDTime(0,2,0)); + isoFile_seekFile(filePtr,seekTime.getAbsoluteByte(),FILE_BROWSER_SEEK_SET); + isoFile_readFile(filePtr,(char*)fileBuffer,bufferFrames * bytesPerFrame); + bufferPointer = fileBuffer; + bufferPos = cdt; + bufferEnd = cdt + CDTime(bufferFrames, CDTime::abFrame); +} + diff --git a/cdrmooby28/FileInterface.hpp b/cdrmooby28/FileInterface.hpp new file mode 100644 index 0000000..c589d22 --- /dev/null +++ b/cdrmooby28/FileInterface.hpp @@ -0,0 +1,208 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 FileInterface.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + +#ifndef FILEINTERFACE_HPP +#define FILEINTERFACE_HPP + +#include "CDTime.hpp" +#include "TimeCache.hpp" +#include "Frame.hpp" + +#include +#include + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +}; + +// the constants for the number of frames in compressed files as well as +// how large the required buffers are +const unsigned long BZIndexBufferFrames = 10; +const unsigned long BZIndexBufferBytes = BZIndexBufferFrames * bytesPerFrame; +const unsigned long ZTableBufferFrames = 1; +const unsigned long ZTableBufferBytes = ZTableBufferFrames * bytesPerFrame; +const unsigned long UncompressedBufferFrames = 10; +const unsigned long UncompressedBufferBytes = UncompressedBufferFrames * bytesPerFrame; + +// a virtual interface to any CD image type +class FileInterface +{ +public: + // bufferFrames is the number of frames you want + // available at any time. + virtual ~FileInterface() + { + if (bufferFrames != 0) + { + if (fileBuffer) + delete[] fileBuffer; + } + } + + // opens the file + virtual void openFile(const std::string& str, int type) + throw(Exception); + + // seeks to the time cdt in the file and sets the buffer pointer + inline void seek(const CDTime& cdt) + throw(Exception); + + // returns the pointer to the last frame seeked. + inline unsigned char* getBuffer() const + { + if (cacheMode == oldMode) + return bufferPointer; + else if (cacheMode == newMode) + return *holdout; + return 0; //shouldn't happen! + } + + // returns the length of the CD + inline CDTime getCDLength() {return CDLength;} + + // sets up stuffs for pregap + FileInterface& setPregap(const CDTime& gapLength, const CDTime& gapTime); + + // returns the last seeked time + inline CDTime getSeekTime() {return seekTime;} + + // returns the name of the file + inline std::string getFileName() const {return fileName;} + + enum CacheMode + { + oldMode, + newMode + }; + + inline FileInterface& setCacheMode(const CacheMode m) + { cacheMode = m; return *this; } + +protected: + // when seek(CDTime) seeks to a frame out of the buffer, this + // function buffers more data and sets the bufferPointer to + // the requested time + virtual void seekUnbuffered(const CDTime& cdt) + throw(std::exception, Exception) = 0; + + fileBrowser_file *filePtr; + + // the number of frames buffered (0 for RAR) + unsigned long bufferFrames; + // the buffer to the cached data + unsigned char* fileBuffer; + // pointer to the last seeked frame + unsigned char* bufferPointer; + // the length of the CD + CDTime CDLength; + // the start position of the file buffer + CDTime bufferPos; + // the end position of the file buffer + CDTime bufferEnd; + // the last seeked time of this CD + CDTime seekTime; + // the name of the cd image + std::string fileName; + // time of the pregap + CDTime pregapTime; + // length of the pregap + CDTime pregapLength; + + CacheMode cacheMode; + + // the extra cache =) + TimeCache cache; + Frame holdout; + +protected: + // this ensures that the buffer is at least as big as it's required (i.e. .BZ files + // need at least 10 frames buffered). + // for RAR, requiredFrames = 0 + FileInterface(const unsigned long requestedFrames, + const unsigned long requiredFrames); +}; + +// interface to uncompressed files +class UncompressedFileInterface : public FileInterface +{ +public: + explicit UncompressedFileInterface(const unsigned long bf) + : FileInterface(bf, UncompressedBufferFrames) + {} + + virtual ~UncompressedFileInterface() {} + +protected: + virtual void seekUnbuffered(const CDTime& cdt) + throw(std::exception, Exception); + +private: + UncompressedFileInterface(); +}; + +// i optimized this function so the CDTimes don't need to use the timeConvert() function +// with all the + operations. If the data is buffered, it should return very quickly. +// This only ensures that one frame is available at bufferPointer, but that should be +// enough for most things... +inline void FileInterface::seek(const CDTime& cdt) + throw(Exception) +{ + using namespace std; + seekTime = cdt; + if (seekTime >= pregapTime) + seekTime -= pregapLength; + + + if (seekTime < CDLength) + { + if (cacheMode == newMode) + { + // check in the global cache first + if (cache.find(seekTime, holdout)) + { + return; + } + } + + // see if its in the file cache. + // in both of these cases, bufferPointer should point to the data + // requested + if ( (seekTime >= bufferPos) && + ( (seekTime.getAbsoluteFrame() + 1) <= (bufferEnd.getAbsoluteFrame()) ) ) + { + bufferPointer = + fileBuffer + (seekTime.getAbsoluteByte() - bufferPos.getAbsoluteByte()); + } + else + { + seekUnbuffered(seekTime); + } + // insert the new data into the cache + if (cacheMode == newMode) + { + holdout = bufferPointer; + cache.insert(seekTime, holdout); + } + } + else + { + Exception e("Seek past end of disc\r\n"); + THROW(e); + } +} + + // the factory method for creating a FileInterface based only on the filename +FileInterface* FileInterfaceFactory(const std::string& filename, + std::string& extension, int type); + +#endif diff --git a/cdrmooby28/Frame.hpp b/cdrmooby28/Frame.hpp new file mode 100644 index 0000000..ba0bcba --- /dev/null +++ b/cdrmooby28/Frame.hpp @@ -0,0 +1,69 @@ +#ifndef FRAME_HPP +#define FRAME_HPP + +#include +#include +extern "C" { + #include +} +#include "Utils.hpp" + +// one frame of CD data, 2352 bytes +class Frame +{ +public: + // note that the data is uninitialized w/default constructor + Frame() + { + data = new unsigned char[bytesPerFrame]; + } + + explicit Frame(const unsigned char* d) + { + data = new unsigned char[bytesPerFrame]; + memcpy(data, d, bytesPerFrame); + } + + Frame(const Frame& r) + { + data = new unsigned char[bytesPerFrame]; + memcpy(data, r.data, bytesPerFrame); + } + + ~Frame() { delete [] data; } + + Frame& operator=(const Frame& r) + { + memcpy(data, r.data, bytesPerFrame); + return *this; + } + + Frame& operator=(const unsigned char* buf) + { + memcpy(data, buf, bytesPerFrame); + return *this; + } + + Frame& operator=(const char* buf) + { + memcpy(data, buf, bytesPerFrame); + return *this; + } + + int operator==(const Frame& r) + { + return memcmp(data, r.data, bytesPerFrame); + } + + unsigned char* operator*() const + { + return data; + } + +private: + unsigned char* data; +}; + + + +#endif diff --git a/cdrmooby28/Globals.cpp b/cdrmooby28/Globals.cpp new file mode 100644 index 0000000..8d612ea --- /dev/null +++ b/cdrmooby28/Globals.cpp @@ -0,0 +1,32 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 Globals.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include "defines.h" +#include "Utils.hpp" +#include "CDInterface.hpp" + +/** global data for the plugin **/ + +// the cd data +CDInterface* theCD = NULL; + +// a return code +int rc = 0; + +// the format of the TD and TN calls +TDTNFormat tdtnformat = msfint; + +// the name of the emulator that's using the plugin +std::string programName; + +// whether it's using the psemu or fpse interface +EMUMode mode = psemu; diff --git a/cdrmooby28/Open.cpp b/cdrmooby28/Open.cpp new file mode 100644 index 0000000..1f56780 --- /dev/null +++ b/cdrmooby28/Open.cpp @@ -0,0 +1,235 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 Open.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include +#include + +#include "CDInterface.hpp" +#include "defines.h" + +#include "externs.h" +#include + +extern "C" { +#include "../DEBUG.h" +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-DVD.h" +#include "../fileBrowser/fileBrowser-CARD.h" +extern fileBrowser_file isoFile; +} + +using namespace std; + +extern CDInterface* theCD; +extern int rc; +extern TDTNFormat tdtnformat; +extern EMUMode mode; + +int CD_Wait(void) +{ + return FPSE_OK; +} + +void closeIt(void) +{ + if (theCD) + { + delete theCD; + theCD = NULL; + } +} + +long CALLBACK Mooby2CDRclose(void) +{ + closeIt(); + return 0; +} + +void CD_Close(void) +{ + closeIt(); +} + +void openIt(void) +{ + if (theCD) + Mooby2CDRclose(); +/* + std::string theFile; + if (prefs.prefsMap[autorunString] == std::string()) + { + char * returned; + theFile = isoFile->name; + } + else + { + theFile = prefs.prefsMap[autorunString]; + } + prefs.prefsMap[lastrunString] = theFile; + prefs.write();*/ + theCD = new CDInterface(); + try { + theCD->open(&isoFile.name[0]); + } catch(Exception& e) { + closeIt(); + moobyMessage(e.text()); + throw; + } catch(std::exception& e) { + closeIt(); + moobyMessage(e.what()); + THROW(Exception(e.what())); + } +} + +// psemu open call - call open +long CALLBACK Mooby2CDRopen(void) +{ + mode = psemu; + try { + openIt(); + } catch(Exception& e) { + return PSE_CDR_ERR; + } + return PSE_CDR_ERR_SUCCESS; +} + +int CD_Open(unsigned int* par) +{ + mode = fpse; + try { + openIt(); + } catch(Exception& e) { + return FPSE_ERR; + } + return FPSE_OK; +} + +long CALLBACK Mooby2CDRshutdown(void) +{ + return Mooby2CDRclose(); +} + +long CALLBACK Mooby2CDRplay(unsigned char * sector) +{ + return theCD->playTrack(CDTime(sector, msfint)); +} + +int CD_Play(unsigned char * sector) +{ + return theCD->playTrack(CDTime(sector, msfint)); +} + +long CALLBACK Mooby2CDRstop(void) +{ + return theCD->stopTrack(); +} + +int CD_Stop(void) +{ + return theCD->stopTrack(); +} + +long CALLBACK Mooby2CDRgetStatus(struct CdrStat *stat) +{ + if (theCD->isPlaying()) + { + stat->Type = 0x02; + stat->Status = 0x80; + } + else + { + stat->Type = 0x01; + stat->Status = 0x20; + } + MSFTime now = theCD->readTime().getMSF(); + stat->Time[0] = intToBCD(now.m()); + stat->Time[1] = intToBCD(now.s()); + stat->Time[2] = intToBCD(now.f()); + return 0; +} + +char CALLBACK Mooby2CDRgetDriveLetter(void) +{ + return 0; +} + + +long CALLBACK Mooby2CDRinit(void) +{ + theCD=NULL; + return 0; +} + +long CALLBACK Mooby2CDRgetTN(unsigned char *buffer) +{ + buffer[0] = 1; + if (tdtnformat == fsmint) + buffer[1] = (char)theCD->getNumTracks(); + else + buffer[1] = intToBCD((char)theCD->getNumTracks()); + return 0; +} + +int CD_GetTN(char* buffer) +{ + buffer[1] = 1; + buffer[2] = (char)theCD->getNumTracks(); + return FPSE_OK; +} + +unsigned char * CALLBACK Mooby2CDRgetBufferSub(void) +{ + return theCD->readSubchannelPointer(); +} + +unsigned char* CD_GetSeek(void) +{ + return theCD->readSubchannelPointer() + 12; +} + +long CALLBACK Mooby2CDRgetTD(unsigned char track, unsigned char *buffer) +{ + if (tdtnformat == fsmint) + memcpy(buffer, theCD->getTrackInfo(track).trackStart.getMSFbuf(tdtnformat), 3); + else + memcpy(buffer, theCD->getTrackInfo(BCDToInt(track)).trackStart.getMSFbuf(tdtnformat), 3); + return 0; +} + +int CD_GetTD(char* result, int track) +{ + MSFTime now = theCD->getTrackInfo(BCDToInt(track)).trackStart.getMSF(); + result[1] = now.m(); + result[2] = now.s(); + + return FPSE_OK; +} + +long CALLBACK Mooby2CDRreadTrack(unsigned char *time) +{ + CDTime now(time, msfbcd); + theCD->moveDataPointer(now); + return 0; +} + +unsigned char* CD_Read(unsigned char* time) +{ + CDTime now(time, msfint); + theCD->moveDataPointer(now); + return theCD->readDataPointer() + 12; +} + +unsigned char * CALLBACK Mooby2CDRgetBuffer(void) +{ + return theCD->readDataPointer() + 12; +} diff --git a/cdrmooby28/SubchannelData.cpp b/cdrmooby28/SubchannelData.cpp new file mode 100644 index 0000000..7aecd15 --- /dev/null +++ b/cdrmooby28/SubchannelData.cpp @@ -0,0 +1,231 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 SubchannelData.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include "SubchannelData.hpp" + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +#include "../fileBrowser/fileBrowser-libfat.h" +#include "../fileBrowser/fileBrowser-DVD.h" +#include "../fileBrowser/fileBrowser-CARD.h" +extern fileBrowser_file subFile; +}; + +using namespace std; + +#include + +// tries to open the subchannel files to determine which +// one to use +SubchannelData* SubchannelDataFactory(const std::string& fileroot, int type) +{ + SubchannelData* scd = NULL; + + fileBrowser_file tempFile; + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], (fileroot + std::string(".sub")).c_str()); + + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) + { + scd = new SUBSubchannelData(); + scd->openFile(fileroot + std::string(".sub"), type); + return scd; + } + + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], (fileroot + std::string(".sbi")).c_str()); + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) + { + scd = new SBISubchannelData(); + scd->openFile(fileroot + std::string(".sbi"), type); + return scd; + } + + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], (fileroot + std::string(".m3s")).c_str()); + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) + { + scd = new M3SSubchannelData(); + scd->openFile(fileroot + std::string(".m3s"), type); + return scd; + } + + scd = new NoSubchannelData(); + return scd; +} + +SUBSubchannelData::SUBSubchannelData() : filePtr(NULL), enableCache(0) +{ + // set the cache to be the size given in the prefs + //cache.setMaxSize(atoi(prefs.prefsMap[cacheSizeString].c_str())); +} + +// SUB files read from the file whenever data is needed +void SUBSubchannelData::openFile(const string& file, int type) + throw(Exception) +{ + fileBrowser_file tempFile; + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], file.c_str()); + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) { + isoFile_deinit(&subFile); + memcpy(&subFile, &tempFile, sizeof(fileBrowser_file)); + subFile.attr = type; + filePtr = &subFile; + } +} + +void SUBSubchannelData::seek(const CDTime& cdt) + throw(Exception) +{ + // seek in the file for the data requested and set the subframe + // data + try + { + // try the cache first + if (enableCache && cache.find(cdt, sf)) + { + return; + } + + isoFile_seekFile(filePtr,(cdt.getAbsoluteFrame() - 150) * SubchannelFrameSize,FILE_BROWSER_SEEK_SET); + isoFile_readFile(filePtr,(char*)sf.subData, SubchannelFrameSize); + + + if (enableCache) + cache.insert(cdt, sf); + } + catch(...) + { + sf.setTime(CDTime(cdt)); + } +} + +// opens the SBI file and caches all the subframes in a map +void SBISubchannelData::openFile(const std::string& file, int type) + throw(Exception) +{ + fileBrowser_file tempFile; + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], file.c_str()); + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) { + isoFile_deinit(&subFile); + memcpy(&subFile, &tempFile, sizeof(fileBrowser_file)); + subFile.attr = type; + filePtr = &subFile; + } + + try + { + unsigned char buffer[4]; + isoFile_seekFile(filePtr,0,FILE_BROWSER_SEEK_SET); + isoFile_readFile(filePtr,(char*)&buffer, 4); + + if (string((char*)&buffer) != string("SBI")) + { + Exception e(file + string(" isn't an SBI file")); + THROW(e); + } + for(unsigned int i = 0; i < filePtr->size; i+=4) + { + isoFile_seekFile(filePtr,i,FILE_BROWSER_SEEK_SET); + isoFile_readFile(filePtr,(char*)&buffer, 4); + + CDTime now((unsigned char*)&buffer, msfbcd); + SubchannelFrame subf(now); + // numbers are BCD in file, so only convert the + // generated subchannel data + switch(buffer[3]) + { + case 1: + isoFile_readFile(filePtr,(char*)&subf.subData[12], 10); + break; + case 2: + isoFile_readFile(filePtr,(char*)&subf.subData[15], 3); + break; + case 3: + isoFile_readFile(filePtr,(char*)&subf.subData[19], 3); + break; + default: + Exception e("Unknown buffer type in SBI file"); + THROW(e); + break; + } + subMap[now] = subf; + } + } + catch(Exception&) + { + throw; + } +} + +// if the data is in the map, return it. otherwise, make up data +void SBISubchannelData::seek(const CDTime& cdt) + throw(Exception) +{ + map::iterator itr = subMap.find(cdt); + if (itr == subMap.end()) + { + sf.setTime(cdt); + } + else + { + sf = (*itr).second; + } +} + +// opens and caches the M3S data +void M3SSubchannelData::openFile(const std::string& file, int type) + throw(Exception) +{ + fileBrowser_file tempFile; + memset(&tempFile, 0, sizeof(fileBrowser_file)); + strcpy(&tempFile.name[0], file.c_str()); + if(isoFile_open(&tempFile) != FILE_BROWSER_ERROR_NO_FILE) { + isoFile_deinit(&subFile); + memcpy(&subFile, &tempFile, sizeof(fileBrowser_file)); + subFile.attr = type; + filePtr = &subFile; + } + + CDTime t(3,0,0); + char buffer[16]; + for(unsigned int i = 0; i < filePtr->size; i+=4) + { + isoFile_seekFile(filePtr,i,FILE_BROWSER_SEEK_SET); + isoFile_readFile(filePtr,(char*)&buffer, 16); + + SubchannelFrame subf(t); + memcpy(&subf.subData[12], buffer, 16); + subMap[t] = subf; + t += CDTime(0,0,1); + if (t == CDTime(4,0,0)) + break; + } + +} + +// if no data is found, create data. otherwise, return the data found. +void M3SSubchannelData::seek(const CDTime& cdt) + throw(Exception) +{ + map::iterator itr = subMap.find(cdt); + if (itr == subMap.end()) + { + sf.setTime(cdt); + } + else + { + sf = (*itr).second; + } +} diff --git a/cdrmooby28/SubchannelData.hpp b/cdrmooby28/SubchannelData.hpp new file mode 100644 index 0000000..3a861a0 --- /dev/null +++ b/cdrmooby28/SubchannelData.hpp @@ -0,0 +1,217 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 SubchannelData.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + +#ifndef SUBCHANNELDATA_HPP +#define SUBCHANNELDATA_HPP + +#include "CDTime.hpp" +#include "Exception.hpp" +#include "Utils.hpp" +#include "TimeCache.hpp" + +#include +#include + +extern "C" { +#include "../fileBrowser/fileBrowser.h" +}; + +// so the funny thing is the subchannel is actually 98 bytes long, but +// the first two are sync/identifier blocks, so 96 is ok for this. +// that and CloneCD Sub files don't write those two blocks... +const int SubchannelFrameSize = 96; + + +// one subchannel frame holds 96 bytes of subchannel data +class SubchannelFrame +{ +public: + SubchannelFrame() + { + subData = new unsigned char[SubchannelFrameSize]; + memset(subData, 0, SubchannelFrameSize); + } + + explicit SubchannelFrame(const CDTime& time) + { + subData = new unsigned char[SubchannelFrameSize]; + memset(subData, 0, SubchannelFrameSize); + setTime(time); + } + + SubchannelFrame(const SubchannelFrame& r) + { + subData = new unsigned char[SubchannelFrameSize]; + memcpy(subData, r.subData, SubchannelFrameSize); + } + + ~SubchannelFrame() { if (subData) delete [] subData;} + + SubchannelFrame& operator=(const SubchannelFrame& r) + { + memcpy(subData, r.subData, SubchannelFrameSize); + return *this; + } + + inline void clear() {memset(subData, 0, SubchannelFrameSize);} + + + // in case it's not clear, here i'm faking the Q subchannel data. + // i'll explain... All integers should be in BCD format + inline SubchannelFrame& setTime(const CDTime& time) + { + CDTime localTime(time - CDTime(0,2,0)); + + // the control and Q mode bits. this subchannel frame + // is mode 1 + subData[12] = 0x41; + // track number + subData[13] = 0x01; + // index... 0 is reserved (pause) so 1 is ok + subData[14] = 0x01; + // track relative address - time of this sector relative to the track start + memcpy(subData + 15, (localTime).getMSFbuf(msfbcd), 3); + // zero, cause that's what it is. + subData[18] = 0x00; + // absolute frame address, from the start of the disc + memcpy(subData + 19, (time).getMSFbuf(msfbcd), 3); + return *this; + } + + inline unsigned char* getBuffer() const {return subData;} + + unsigned char* subData; +}; + + +// virtual base class for storing subchannel data +class SubchannelData +{ +public: + SubchannelData() {} + virtual void openFile(const std::string& file, int type) + throw(Exception) = 0; + virtual void seek(const CDTime& cdt) + throw(Exception) = 0; + inline unsigned char* get(void) const {return sf.subData;} + virtual ~SubchannelData() {} +protected: + SubchannelFrame sf; +}; + +// disables the subchannel data outright +class DisabledSubchannelData : public SubchannelData +{ +public: + DisabledSubchannelData() + { + delete [] sf.subData; + sf.subData = NULL; + } + virtual void openFile(const std::string& file, int type) + throw(Exception) {} + virtual void seek(const CDTime& cdt) throw(Exception) + {} + virtual ~DisabledSubchannelData() {} +}; + +// makes up data if there is no subchannel data file +class NoSubchannelData : public SubchannelData +{ +public: + NoSubchannelData() {} + virtual void openFile(const std::string& file, int type) + throw(Exception) {} + virtual void seek(const CDTime& cdt) throw(Exception) + {sf.setTime(cdt);} + virtual ~NoSubchannelData() {} +}; + +// reads a CloneCD SUB file for the subchannel data. +// the .SUB file stores all subchannel data for a disc, +// each block is the last 96 bytes of the full 98 byte data. +class SUBSubchannelData : public SubchannelData +{ +public: + SUBSubchannelData(); + virtual void openFile(const std::string& file, int type) + throw(Exception); + virtual void seek(const CDTime& cdt) + throw(Exception); + virtual ~SUBSubchannelData() {} +private: + fileBrowser_file *filePtr; + + // the extra cache =) + TimeCache cache; + bool enableCache; +}; + +/* + reads an SBI file for subchannel data, caches that info + internally and makes up any data not in that cache. + + the first 4 characters of the file are "SBI" and a null character '\0' + + each record is like this: + 3 bytes: the data in MSF/BCD format + 1 byte: a switch + 1 - all 10 Q channel subframe data starting + at subframe[12] + 2 - 3 bytes of the track relative address + at subframe[15] + 3 - 3 bytes of the track absolute address, + at subframe[19] +*/ +class SBISubchannelData : public SubchannelData +{ +public: + SBISubchannelData() : filePtr(NULL) {} + virtual void openFile(const std::string& file, int type) + throw(Exception); + virtual void seek(const CDTime& cdt) + throw(Exception); + virtual ~SBISubchannelData() {} +private: + fileBrowser_file *filePtr; + std::map subMap; +}; + +/* + reads an M3S file for subchannel data, caches that info + internally and makes up any data not in that cache. + + M3s stores all the subchannel data for minute 3 of the disc + in 16 byte blocks. You only need the first 10 of the + 16 bytes, read into subframe[12] to be OK though. once you + hit minute 4, there's no more data. +*/ +class M3SSubchannelData : public SubchannelData +{ +public: + M3SSubchannelData() : filePtr(NULL) {} + virtual void openFile(const std::string& file, int type) + throw(Exception); + virtual void seek(const CDTime& cdt) + throw(Exception); + virtual ~M3SSubchannelData() {} +private: + fileBrowser_file *filePtr; + std::map subMap; +}; + +// determines what kind of subchannel data is available based only +// on file names +SubchannelData* SubchannelDataFactory(const std::string& fileroot, int type); + +#endif diff --git a/cdrmooby28/TimeCache.hpp b/cdrmooby28/TimeCache.hpp new file mode 100644 index 0000000..7e91767 --- /dev/null +++ b/cdrmooby28/TimeCache.hpp @@ -0,0 +1,89 @@ +#ifndef TIMECACHE_HPP +#define TIMECACHE_HPP + +#include "CDTime.hpp" +#include +#include + +/* + * This is an LRU cache for any type of file data this plugin can store. + * It's a map of time to data... + */ + +template +class TimeCache +{ +public: + TimeCache() : maxSize(10) {} + + explicit TimeCache(size_t size) { setMaxSize(size); } + + TimeCache& setMaxSize(size_t size) + { + maxSize = size; + if (maxSize < 1) + maxSize = 1; + while (cache.size() > maxSize) + popOne(); + return *this; + } + + size_t getMaxSize() const + { return maxSize; } + + // return true if found (and set Data d) + bool find (const CDTime& time, Data& d) + { + // try to find the data in the cache first + // if it's there, return it and set it as the most recent + typename CacheMap::iterator itr = cache.find(time); + if (itr != cache.end()) + { + d = (*itr).second.first; + // splice will move the item in the LRUList to the front and + // keep the iterator valid + order.splice(order.begin(), order, + (*itr).second.second, (*itr).second.second); + return true; + } + else + { + return false; + } + } + + // insert this as the LRU data + void insert(const CDTime& time, const Data& d) + { + // are we full? push out the oldest data + while (cache.size() >= maxSize) + popOne(); + + order.push_front(time); + cache[time] = CacheItem(d, order.begin()); + } + +private: + // remove the oldest item from the cache + void popOne() + { + CDTime toast = order.back(); + order.pop_back(); + cache.erase(cache.find(toast)); + } + + // maxSizeimum size of the cache + size_t maxSize; + + // the list is ordered from first to last starting with + // the most recently used data item. + typedef std::list LRUList; + LRUList order; + + // the map simply holds the time and data pairs + typedef std::pair CacheItem; + typedef std::map CacheMap; + CacheMap cache; +}; + +#endif // TIMECACHE_HPP diff --git a/cdrmooby28/TrackInfo.hpp b/cdrmooby28/TrackInfo.hpp new file mode 100644 index 0000000..1773f8c --- /dev/null +++ b/cdrmooby28/TrackInfo.hpp @@ -0,0 +1,44 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 TrackInfo.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + +#ifndef TRACKINFO_HPP +#define TRACKINFO_HPP + +#include "CDTime.hpp" + +#include + +// This class stores all the information we need to know about one track. +// It's just a glorified struct. +class TrackInfo +{ +public: + TrackInfo() : trackNumber(0) {} + + explicit TrackInfo(const CDTime& tl) + : trackNumber(0), trackStart(0, CDTime::abFrame), trackLength(tl) {} + + inline friend std::ostream& operator<<(std::ostream& o, const TrackInfo& ti) + { + o << std::setw(2) << ti.trackNumber << ' ' << ti.trackStart.getMSF() + << ' ' << ti.trackEnd.getMSF() << ' ' << ti.trackLength.getMSF() << std::endl; + return o; + } + + unsigned long trackNumber; + CDTime trackStart; + CDTime trackEnd; + CDTime trackLength; +}; + +#endif diff --git a/cdrmooby28/TrackParser.cpp b/cdrmooby28/TrackParser.cpp new file mode 100644 index 0000000..d774310 --- /dev/null +++ b/cdrmooby28/TrackParser.cpp @@ -0,0 +1,270 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 TrackParser.cpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#include "TrackParser.hpp" +#include "Utils.hpp" + +using namespace std; + + +TrackParser* TrackParserFactory(const std::string& filename, + const FileInterface* fi) +{ + // try to open a track listing sheet + std::string thisFile; + if ( (thisFile = CCDParser::fileExists(filename)) != std::string()) + return new CCDParser(thisFile); + else if ( (thisFile = CueParser::fileExists(filename)) != std::string()) + return new CueParser(thisFile); + else + return new NullParser(fi->getFileName()); +} + + // just opens the file for parsing +TrackParser::TrackParser(const std::string& filename) + : cuename(filename), pregapLength(CDTime(0,0,0)) +{ + if (!filename.empty()) theCueSheet.open(filename.c_str()); +} + + + // post processing on the list +void TrackParser::postProcess(const CDTime& CDLength) +{ + vector::size_type index; + + CDTime thisCDLength(CDLength); + + // and if there's a pregap flag, add that time + thisCDLength += pregapLength; + + // calculate the track lengths, except for the last track + // which needs CDLength + // The track length is the start time of the next track - the start time of this track - + // 1 frame + if (tiv.size() > 0) + { + for(index = 0; index < tiv.size() - 1; index++) + { + tiv[index].trackLength = tiv[index + 1].trackStart - + tiv[index].trackStart; + } + // finally, at the end of the disc, there's a 2 second gap as well... + tiv[index].trackLength = thisCDLength - CDTime(0,2,0) - tiv[index].trackStart; + } + // if there is no cue sheet, just make a single track with length CDLength. + else + { + tiv.insert(tiv.begin(), TrackInfo(thisCDLength - CDTime(0,2,0))); + } + + // set the ending time + for(index = 0; index < tiv.size(); index++) + { + // there's an extra 2 seconds not accounted for somewhere.... + tiv[index].trackStart += CDTime(0,2,0); + // and the track end is 1 frame less... + tiv[index].trackEnd = tiv[index].trackStart + tiv[index].trackLength - CDTime(0,0,1); + } + + // insert the total length at tiv[0] + TrackInfo track0; + track0.trackEnd = tiv[tiv.size()-1].trackEnd + CDTime(0,0,1); + track0.trackStart = track0.trackEnd; + track0.trackLength = track0.trackEnd; + track0.trackNumber = 0; + tiv.insert(tiv.begin(), track0); +} + +std::ostream& operator<<(std::ostream& o, const TrackParser& cp) +{ + vector::size_type index; + for (index = 0; index < cp.tiv.size(); index++) + { + o << cp.tiv[index] << endl; + } + return o; +} + + +NullParser::NullParser(const std::string& filename) + : TrackParser(filename) +{} + +// parses a CUE file +void CueParser::parse() throw(Exception) +{ + if (!theCueSheet) + { + // if there's a file error here, then there's either a file error + // or there's no cue sheet. in either case, we'll ignore it. + // a cue sheet is nice, but not necessary + return; + } + + bool doneReading = false; + + theCueSheet.exceptions(ios::eofbit|ios::badbit|ios::failbit); + string thisLine; + + try + { + TrackInfo thisTrack; + + getline(theCueSheet, thisLine); + doneReading = true; + // the file name is whatever is in the " marks + std::string::size_type firstpos = thisLine.find('"'); + std::string::size_type lastpos = thisLine.rfind('"'); + cuefilename = thisLine.substr(firstpos + 1, lastpos - firstpos - 1); + + while(theCueSheet) + { + getline(theCueSheet, thisLine); + string firstWord = word(thisLine, 1); + if (firstWord == "TRACK") + { + thisTrack.trackNumber = atoi(word(thisLine,2).c_str()); + doneReading = false; + } + else if (firstWord == "PREGAP") + { + pregapLength = CDTime(word(thisLine,2)); + } + else if (firstWord == "INDEX") + { + // we need INDEX 01 + if (atoi(word(thisLine,2).c_str()) == 1) + { + thisTrack.trackStart = CDTime(word(thisLine,3)); + thisTrack.trackStart += pregapLength; + tiv.push_back(thisTrack); + thisTrack = TrackInfo(); + doneReading = true; + } + } + else + { + // whatever, we'll just skip this... + } + } + } + catch(std::exception& e) + { + if (!doneReading) + { + Exception exc(string("Error reading cue sheet ") + cuename); + exc.addText(string(e.what())); + THROW(exc); + } + } +} + +std::string CueParser::fileExists(const std::string& file) +{ + { + std::ifstream is; + std::string cueName = file + std::string(".cue"); + is.open(cueName.c_str()); + if (is) + { + return cueName; + } + } + return string(); +} + +// parses a CCD file +void CCDParser::parse() throw(Exception) +{ + if (!theCueSheet) + { + // if there's a file error here, then there's either a file error + // or there's no cue sheet. in either case, we'll ignore it. + // a cue sheet is nice, but not necessary + return; + } + + bool doneReading = false; + theCueSheet.exceptions(ios::eofbit|ios::badbit|ios::failbit); + string thisLine; + + try + { + TrackInfo thisTrack; + + doneReading = false; + + // the file name is whatever the .ccd is changed to .img + cuefilename = cuename.substr(0,cuename.rfind('.')) + std::string(".img"); + + while(theCueSheet) + { + getline(theCueSheet, thisLine); + string firstWord = word(thisLine, 1); + if (firstWord == "[TRACK") + { + thisTrack.trackNumber = atoi(word(thisLine,2).c_str()); + } + else if (firstWord == "INDEX") + { + // we need INDEX 01 + if (atoi(word(thisLine,2).c_str()) == 1) + { + // the number after the = sign is the + // absolute frame + std::string frame(thisLine.substr(thisLine.find('=')+1)); + thisTrack.trackStart = CDTime(atoi(frame.c_str()), CDTime::abFrame); + tiv.push_back(thisTrack); + thisTrack = TrackInfo(); + doneReading = true; + } + } + else + { + // whatever, we'll just skip this... + } + } + } + catch(std::exception& e) + { + if (!doneReading) + { + Exception exc(string("Error reading cue sheet ") + cuename); + exc.addText(string(e.what())); + THROW(exc); + } + } +} + +std::string CCDParser::fileExists(const std::string& file) +{ + { + std::ifstream is; + std::string ccdName = file + std::string(".ccd"); + is.open(ccdName.c_str()); + if (is) + { + return ccdName; + } + } + { + std::ifstream is; + std::string ccdName = file + std::string(".CCD"); + is.open(ccdName.c_str()); + if (is) + { + return ccdName; + } + } + return std::string(); +} diff --git a/cdrmooby28/TrackParser.hpp b/cdrmooby28/TrackParser.hpp new file mode 100644 index 0000000..72da5f6 --- /dev/null +++ b/cdrmooby28/TrackParser.hpp @@ -0,0 +1,119 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 TrackParser.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + + +#ifndef TRACKPARSER_HPP +#define TRACKPARSER_HPP + +#include +#include +#include + +#include "TrackInfo.hpp" +#include "FileInterface.hpp" + +// TrackParser is the base class for reading CUE and CCD-type time sheets. +// It also sets up the list of tracks and times +class TrackParser +{ +public: + // attempts to open the cue file 'filename' + explicit TrackParser(const std::string& filename); + + virtual ~TrackParser() {} + // parses the cue file, if any. throws when there's a read error + virtual void parse() throw(Exception) = 0; + + // this needs the total CD length to correctly determine + // the start times and length of each track + void postProcess(const CDTime& CDLength); + + // accessors + // returns the track listing + // track[0] is the total length + // track[1...n] is the length of that track + inline std::vector getTrackList() const {return tiv;} + // returns the name of the CD as determined by the cue sheet (if any) + inline std::string getCDName() const {return cuefilename;} + + friend std::ostream& operator<<(std::ostream& o, const TrackParser& cp); + + CDTime getPregapLength() const { return pregapLength; } + +private: + TrackParser(const TrackParser& r); + TrackParser& operator=(const TrackParser& r); + +protected: + // the file itself + std::ifstream theCueSheet; + // the name of the .cue or .ccd file + std::string cuename; + // the name if the image file given in the cue sheet + std::string cuefilename; + // track info vector with start and end times and such... + std::vector tiv; + // length of the pregap (if any) + CDTime pregapLength; +}; + +// this is for no track list +class NullParser : public TrackParser +{ +public: + explicit NullParser(const std::string& filename = std::string()); + + virtual ~NullParser() {} + + virtual void parse() throw(Exception) {} +}; + +// this parses CDRWin CUE files +class CueParser : public TrackParser +{ +public: + explicit CueParser(const std::string& filename) + : TrackParser(filename) + {} + + virtual ~CueParser() {} + + // this is the only real function here - parses the cue sheet into + // the internal data members + virtual void parse() throw(Exception); + + // returns a string with a CUE file name if that file exists + static std::string fileExists(const std::string& file); +}; + +// this parses CloneCD CCD files +class CCDParser : public TrackParser +{ +public: + explicit CCDParser(const std::string& filename) + : TrackParser(filename) + {} + + virtual ~CCDParser() {} + + // this is the only real function here - parses the cue sheet into + // the internal data members + virtual void parse() throw(Exception); + + // returns a string with a CCD file name if that file exists + static std::string fileExists(const std::string& file); +}; + +// factory method for building track parser +TrackParser* TrackParserFactory(const std::string& filename, const FileInterface* fi); + +#endif diff --git a/cdrmooby28/Utils.hpp b/cdrmooby28/Utils.hpp new file mode 100644 index 0000000..dc98a65 --- /dev/null +++ b/cdrmooby28/Utils.hpp @@ -0,0 +1,152 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 utils.hpp +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#ifndef UTILS_HPP +#define UTILS_HPP + +#include +#include + +/* + This file is for any utility function or constant that has use outside the scope of any + single file +*/ + +// specifies how you want the MSF time formatted +// msf/fsm -> if time is specified in minute, second, frame or backwards +// int/bcd -> integer or binary coded decimal format +enum TDTNFormat +{ + msfint, + fsmint, + fsmbcd, + msfbcd +}; + +// a quick way to tell which API set is being used +enum EMUMode +{ + psemu, + fpse +}; + +// converts uchar in c to BCD character +#define intToBCD(c) (unsigned char)((c%10) | ((c/10)<<4)) + +// converts BCD number in c to uchar +#define BCDToInt(c) (unsigned char)((c & 0x0F) + 10 * ((c & 0xF0) >> 4)) + +static const std::string theUsualSuspects = + "Common image files (*.{bz,bz.index,Z,Z.table,bin,bwi,img,iso,rar})"; + +// CD time constants +static const unsigned long secondsPerMinute = 60; +static const unsigned long framesPerSecond = 75; +static const unsigned long framesPerMinute = framesPerSecond * secondsPerMinute; +static const unsigned long bytesPerFrame = 2352; +static const unsigned long bytesPerSecond = bytesPerFrame * framesPerSecond; +static const unsigned long bytesPerMinute = bytesPerSecond * secondsPerMinute; + +extern "C" { + void SysPrintf(const char *fmt, ...); +} + +inline void moobyMessage(const std::string& message) +{ + SysPrintf("%s\r\n",message.c_str()); +} + +inline void moobyMessage(const char* message) +{ + SysPrintf("%s\r\n",message); +} + +inline char* moobyFileChooser(const char* message, const char* filespec, + const std::string& last = std::string()) +{ + return NULL; +} + +inline int moobyAsk(const char* message) +{ + return 0; +} + +// since most binary data is stored little endian, this flips +// the data bits for big endian systems +template +inline void flipBits(T& num) +{ + char* front = (char*)# + char* end = front + sizeof(T) - 1; + while (front < end) + { + char t; + t = *front; + *front = *end; + *end = t; + front++; + end--; + } +} + +// given a string and a number, returns the ' ' delimited word +// at position num +inline std::string word(const std::string& str, const unsigned long num) +{ + if (str == std::string()) + return str; + + unsigned long i; + std::string::size_type startpos = 0; + std::string::size_type endpos = 0; + + for(i = 0; i < num; i++) + { + startpos = str.find_first_not_of(' ', endpos); + if (startpos == std::string::npos) + return std::string(); + + endpos = str.find_first_of(' ', startpos); + if (endpos == std::string::npos) + { + endpos = str.size(); + } + } + return str.substr(startpos, endpos - startpos); +} + +// turns a string into its lowercase... +inline std::string tolcstr(const std::string& s) +{ + std::string::size_type i; + std::string toReturn(s); + for (i = 0; i < s.size(); i++) + toReturn[i] = tolower(s[i]); + return toReturn; +} + +// tries to match the extension ext to the end of the file name +inline bool extensionMatches(const std::string& file, const std::string& ext) +{ + if (file.size() < ext.size()) return false; + return (tolcstr(file.substr(file.size() - ext.size())) == ext); +} + +// returns what the name of the program running this plugin is. +inline std::string getProgramName(void) +{ + //std::string toReturn; + return "WiiSXRX"; +} + +#endif diff --git a/cdrmooby28/defines.h b/cdrmooby28/defines.h new file mode 100644 index 0000000..c9b08f8 --- /dev/null +++ b/cdrmooby28/defines.h @@ -0,0 +1,148 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 defines.h +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#ifndef __DEFINES_H +#define __DEFINES_H + +#define CALLBACK + +#include + +// PSEMU DEFINES + +// header version +#define _PPDK_HEADER_VERSION 1 + +#define PLUGIN_VERSION 1 + +// plugin type returned by PSEgetLibType (types can be merged if plugin is multi type!) +#define PSE_LT_CDR 1 + +// every function in DLL if completed sucessfully should return this value +#define PSE_ERR_SUCCESS 0 +// undefined error but fatal one, that kills all functionality +#define PSE_ERR_FATAL -1 + +// XXX_Init return values +// Those return values apply to all libraries + +// initialization went OK +#define PSE_INIT_ERR_SUCCESS 0 + +// this driver is not configured +#define PSE_INIT_ERR_NOTCONFIGURED -2 + +// this driver can not operate properly on this hardware or hardware is not detected +#define PSE_INIT_ERR_NOHARDWARE -3 + + +/* CDR PlugIn */ + +// CDR_Test return values + +// sucess, everything configured, and went OK. +#define PSE_CDR_ERR_SUCCESS 0 + +// ERRORS +#define PSE_CDR_ERR -40 +// this driver is not configured +#define PSE_CDR_ERR_NOTCONFIGURED PSE_CDR_ERR - 0 +// if this driver is unable to read data from medium +#define PSE_CDR_ERR_NOREAD PSE_CDR_ERR - 1 + +// WARNINGS +#define PSE_CDR_WARN 40 +// if this driver emulates lame mode ie. can read only 2048 tracks and sector header is emulated +// this might happen to CDROMS that do not support RAW mode reading - surelly it will kill many games +#define PSE_CDR_WARN_LAMECD PSE_CDR_WARN + 0 + + + + + + +// FPSE DEFINES + +// Return values (should be applied to the entire code). +#define FPSE_OK 0 +#define FPSE_ERR -1 +#define FPSE_WARN 1 + +typedef signed char INT8; +typedef short int INT16; + +typedef unsigned char UINT8; +typedef unsigned short int UINT16; + +typedef long int INT32; +typedef unsigned long int UINT32; + +#define INT64 long long + +#define FPSE_CDROM 5 + + +// New MDEC from GPU plugin. +typedef struct { + int (*MDEC0_Read)(); + int (*MDEC0_Write)(); + int (*MDEC1_Read)(); + int (*MDEC1_Write)(); + int (*MDEC0_DmaExec)(); + int (*MDEC1_DmaExec)(); +} MDEC_Export; + +// cdr stat struct +struct CdrStat +{ + unsigned long Type; + unsigned long Status; + unsigned char Time[3]; // current playing time +}; + +// Main Struct for initialization +typedef struct { + UINT8 *SystemRam; // Pointer to the PSX system ram + UINT32 Flags; // Flags to plugins + UINT32 *IrqPulsePtr; // Pointer to interrupt pending reg + MDEC_Export MDecAltern; // Use another MDEC engine + int (*ReadCfg)(); // Read an item from INI + int (*WriteCfg)(); // Write an item to INI + void (*FlushRec)(); // Tell where the RAM is changed +} FPSElinux; + +// Info about a plugin +typedef struct { + UINT8 PlType; // Plugin type: GPU, SPU or Controllers + UINT8 VerLo; // Version High + UINT8 VerHi; // Version Low + UINT8 TestResult; // Returns if it'll work or not + char Author[64]; // Name of the author + char Name[64]; // Name of plugin + char Description[1024]; // Description to put in the edit box +} FPSEAbout; + +typedef struct { // NOT bcd coded + u8 minute; + u8 second; + u8 frame; +} cdvdLoc; + +typedef struct { + u8 strack; + u8 etrack; +} cdvdTN; + +#define PS2E_LT_CDVD 0x8 + + +#endif //__DEFINES_H diff --git a/cdrmooby28/externs.h b/cdrmooby28/externs.h new file mode 100644 index 0000000..e53297f --- /dev/null +++ b/cdrmooby28/externs.h @@ -0,0 +1,81 @@ +/************************************************************************ + +Copyright mooby 2002 + +CDRMooby2 externs.h +http://mooby.psxfanatics.com + + This file is protected by the GNU GPL which should be included with + the source code distribution. + +************************************************************************/ + +#ifndef EXTERNS_H +#define EXTERNS_H + +#include "defines.h" + +// sets all the callbacks as extern "c" for linux compatability +extern "C" +{ + +char * CALLBACK PSEgetLibName(void); +unsigned long CALLBACK PSEgetLibType(void); +unsigned long CALLBACK PSEgetLibVersion(void); + +void CALLBACK Mooby2CDRabout(void); +long CALLBACK Mooby2CDRtest(void); +long CALLBACK Mooby2CDRconfigure(void); +long CALLBACK Mooby2CDRclose(void); +long CALLBACK Mooby2CDRopen(void); +long CALLBACK Mooby2CDRshutdown(void); +long CALLBACK Mooby2CDRplay(unsigned char * sector); +long CALLBACK Mooby2CDRstop(void); +long CALLBACK Mooby2CDRgetStatus(struct CdrStat *stat) ; +char CALLBACK Mooby2CDRgetDriveLetter(void); +long CALLBACK Mooby2CDRinit(void); +long CALLBACK Mooby2CDRgetTN(unsigned char *buffer); +unsigned char * CALLBACK Mooby2CDRgetBufferSub(void); +long CALLBACK Mooby2CDRgetTD(unsigned char track, unsigned char *buffer); +long CALLBACK Mooby2CDRreadTrack(unsigned char *time); +unsigned char * CALLBACK Mooby2CDRgetBuffer(void); + +/* FPSE stuff, we don't use it in WiiSX */ +void CD_About(UINT32 *par); +int CD_Wait(void); +void CD_Close(void); +int CD_Open(unsigned int* par); +int CD_Play(unsigned char * sector); +int CD_Stop(void); +int CD_GetTN(char* result); +unsigned char* CD_GetSeek(void); +unsigned char* CD_Read(unsigned char* time); +int CD_GetTD(char* result, int track); +int CD_Configure(UINT32 *par); + +/* PS2 callbacks */ + +u32 CALLBACK PS2EgetLibType(void); +u32 CALLBACK PS2EgetLibVersion(void); +char* CALLBACK PS2EgetLibName(void); + +s32 CALLBACK CDVDinit(); +s32 CALLBACK CDVDopen(); +void CALLBACK CDVDclose(); +void CALLBACK CDVDshutdown(); +s32 CALLBACK CDVDreadTrack(cdvdLoc *Time); + +// return can be NULL (for async modes) +u8* CALLBACK CDVDgetBuffer(); +s32 CALLBACK CDVDgetTN(cdvdTN *Buffer); +s32 CALLBACK CDVDgetTD(u8 Track, cdvdLoc *Buffer); + +// extended funcs +void CALLBACK CDVDconfigure(); +void CALLBACK CDVDabout(); +s32 CALLBACK CDVDtest(); + + +} + +#endif diff --git a/cdrmooby28/notes.txt b/cdrmooby28/notes.txt new file mode 100644 index 0000000..a7d1bf2 --- /dev/null +++ b/cdrmooby28/notes.txt @@ -0,0 +1,124 @@ +and 2.8 + +- there was a bug that was preventing the config window from ever returning - it would disappear but never close. i say *was* cause it's fixed =) +- use the "Enable subchannel option" to turn on/off subchannel data reading. some games work better with it off rather than on. +- upgraded PortAudio to version 0.18.1 (for CD-DA audio) +- added an experimental caching option. it's pretty much just a huge LRU cache for previously read data from the image. try it and see if you like it. +- other random fixes... i dont quite remember them all =) + + +yeah, yeah... 2.7 + +- fixed a bug that was causing games without a track listing file (.cue, .ccd) to crash with the error "read past end of disc". just a lesson to keep those files when you're making your disc images =) +- the rar library is now using assembly optimized code. +- fixed (yet another) off by one problem, this time in the internally generated subchannel data. +- found a bug where if it seeked to the end of disk, sometimes it would get stuck there... oops + + +CDRMooby 2.6 + +- the total cd length was returning 0:0:0.. oops =) i doubt this affects any compatability, but it's nice to have it fixed. +- by request, added a config option to alter the autorun settings. autorun images are now persistent until changed or cleared with the config settings or manually. this lets you use autorun with epsxecutor and other frontends. + + +CDRMooby 2.5 + +sorry for the lack of communication folks, been on a hiatus of sorts lately... and sorry about 2.4 which ended up causing more problems than it fixed. anyway, here's the scoop on the latest stuff: + +- Fixed an off-by-one-frame subchannel problem that was causing XA playback to stop in certain games. Big thanks to the Peops CDR freely available source code for helping me find this one =) +- Fixed some mishandled pregap data that was messing with CDDA timing. +- Previously, only SUB subchannel files could be used because the plugin would fail to find any of the other subchannel file types. +- Linked with FLTK 1.1.3 + + +CDRMooby 2.4 + +I think this is fixed CDDA data better than any previous version =) + + +CDRMooby 2.3 + +This release is dedicated to people who understand that problems get fixed when accompanied by DETAILED EXPLANATIONS of what went wrong. To the rest of you out there, don't complain unless you're willing to help. By the way, it seems many of you don't know that I have a forum of my own hosted by emufanatics at http://www.emufanatics.com/forums/viewforum.php?f=29 so use it. + +- fixes CDDA problems. If you still have trouble, describe the problem IN DETAIL at my forum... + + + +CDRMooby 2.2 + +Do any of you use the Linux binaries? I just switched to Debian and I'm much happier for doing so. However Linux binaries that use C++ libraries don't translate well across Linuxes. In other words, this Linux binary probably won't work for everyone. And to make things worse for you Linux users, I got rid of make and replaced it with (the much superior) Jam (http://www.perforce.com/jam/jam.html) to make compiling the plugin more difficult for the rest of you. So no complaints from the peanut gallery if the Linux version doesn't work. + +- Added .CCD support - experimental at best, but will probably work in most cases +- Added PCSX2 interface. I've only tried one demo image and it worked, so consider this experimental too. +- Added some new CDDA play modes - play one track (and stop), repeat one track, repeat all tracks - selectable in the config menu. Choose whatever mode you prefer or is appropriate for the game. A serious shortcoming of the PSX CD emulation is the lack of pause and changing the repeat mode. I'm not sure if this is a BIOS function or CD hardware function or whatever, but it would be nice to fix someday... +- New config stuff: In Windows, the configuration settings are now stored in the registry. There's also a new key called "autorun" that, if set, the plugin will automatically use the image listed there without prompting for a file (a nice feature for you frontend people). Also, the plugin keeps track of the last file you ran and makes that the default when starting the emulator. +- The file chooser defaults to files that I know work well with the plugin. There still is the *.* option available, but I suggest you don't use it. +- Linked with FLTK 1.1.2, now with fewer bugs =) + +CDRMooby 2.1 + +Because of complaints that I didn't change the version number last time, it's different now... + +- fixed a bug with FILE NAMES IN ALL CAPS (but why you would use them is beyond me...) +- fixed the linux bug with windows not closing when they should +- linked with FLTK 1.1.0 fixing various bugs, including a nasty drag-n-drop bug... + + + +CDRMooby 2.01 + +re-linked it with the latest FLTK which fixes some bugs with the file selection. this also includes a bug fix with linux and bz and z compressed images. + + + +CDRMooby2 - The Real Deal + +Yes, after a long wait, this is the full release... New features since 1.6... + +Real subchannel support. Automatically detects subchannel files when they're available. Just make sure they're in the same directory as the image and named the same. +New GUIs, audio handling thanks to external libraries. Use the favorites tab in the file selection window to speed up finding your images. +CDDA Volume is now controllable from the config menu. +Better compatability with all emus, especially CD-DA audio. + +that's the new stuff... otherwise, it should behave similarly (tho better) than the last version. the rest is for those who dont have a clue what this does... + +THIS PLUGIN RUNS CD IMAGES, NOT CDS THEMSELVES. + The images MUST be in raw (2352 byte/frame) format or in one of the compressed formats - RAR (2.x only), Z.table or .bz.index (both available in the config menu) + When using a .CUE sheet, CD-DA is available (for games which have it) + - CD-DA volume is available in the config menu + Subchannel support using .sub (CloneCD), .sbi or .m3s (Pete's plugin) + Very stable and compatable + +BRAND NEW LOOK!!! Now uses FLTK for dialog boxes... + When selecting an image, you can add a directory to the favorites tab to quickly get back there in the future! + Volume settings are persistant from session to session. + +ENTIRELY REWRITTEN FROM SCRATCH!!! + Uses C++ for nearly everything, external libraries for guis, audio, and compression. + GPL'd code for anyone out there to see. + +For those of you who are using 1.6 or one of the beta versions, please upgrade to this version!!! + +If you have any questions or bugs, PLEASE let me know so I can squish them like the annoying pests they are: +http://mooby.psxfanatics.com + + +Info for building it n such... + +For this plugin, I used the following external libraries: + + zlib v1.1.4: http://www.gzip.org/zlib/ (windows only) + bzlib v1.02: http://sources.redhat.com/bzip2/ (windows only) + portaudio v18: http://www.portaudio.com/ + fltk v1.1.0rc5: http://www.fltk.org/ + unrarlib v.40: http://www.unrarlib.org/ + +FYI, I include the bzlib and zlib files because I've taken out alot of unnecessary files from the distro, not because I edited them. Well, I did change the name of the zlib compress.c file to zcompress.c, but that was it... + +If you're trying to build.... + +the windows version: + get portaudio and fltk from the sites above and build them... then set environment variables 'fltkdir' and 'portaudiodir' with the root directory where you put them (i.e. if the libs are in d:/fltk/libs then the env var would be d:/fltk). it should compile fine after that... + +for linux: + build and install fltk, then build portaudio and set the path appropriately in the makefile. if you have bzlib and zlib installed, it should compile just fine... diff --git a/cdrom.c b/cdrom.c new file mode 100644 index 0000000..c0464d5 --- /dev/null +++ b/cdrom.c @@ -0,0 +1,1079 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Handles all CD-ROM registers and functions. +*/ + +#include "cdrom.h" + +/* CD-ROM magic numbers */ +#define CdlSync 0 +#define CdlNop 1 +#define CdlSetloc 2 +#define CdlPlay 3 +#define CdlForward 4 +#define CdlBackward 5 +#define CdlReadN 6 +#define CdlStandby 7 +#define CdlStop 8 +#define CdlPause 9 +#define CdlInit 10 // 0xa +#define CdlMute 11 // 0xb +#define CdlDemute 12 // 0xc +#define CdlSetfilter 13 // 0xd +#define CdlSetmode 14 // 0xe +#define CdlGetmode 15 // 0xf +#define CdlGetlocL 16 // 0x10 +#define CdlGetlocP 17 // 0x11 +#define CdlReadT 18 // 0x12 +#define CdlGetTN 19 // 0x13 +#define CdlGetTD 20 // 0x14 +#define CdlSeekL 21 // 0x15 +#define CdlSeekP 22 // 0x16 +#define CdlSetclock 23 // 0x17 +#define CdlGetclock 24 // 0x18 +#define CdlTest 25 // 0x19 +#define CdlID 26 // 0x1a +#define CdlReadS 27 // 0x1b +#define CdlReset 28 // 0x1c +#define CdlGetQ 29 // 0x1d +#define CdlReadToc 30 // 0x1e + +#define AUTOPAUSE 249 +#define READ_ACK 250 +#define READ 251 +#define REPPLAY_ACK 252 +#define REPPLAY 253 +#define ASYNC 254 +/* don't set 255, it's reserved */ + +char *CmdName[0x100]= { + "CdlSync", "CdlNop", "CdlSetloc", "CdlPlay", + "CdlForward", "CdlBackward", "CdlReadN", "CdlStandby", + "CdlStop", "CdlPause", "CdlInit", "CdlMute", + "CdlDemute", "CdlSetfilter", "CdlSetmode", "CdlGetmode", + "CdlGetlocL", "CdlGetlocP", "CdlReadT", "CdlGetTN", + "CdlGetTD", "CdlSeekL", "CdlSeekP", "CdlSetclock", + "CdlGetclock", "CdlTest", "CdlID", "CdlReadS", + "CdlReset", NULL, "CDlReadToc", NULL +}; + +unsigned char Test04[] = { 0 }; +unsigned char Test05[] = { 0 }; +unsigned char Test20[] = { 0x98, 0x06, 0x10, 0xC3 }; +unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F }; +unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; + +// cdr.Stat: +#define NoIntr 0 +#define DataReady 1 +#define Complete 2 +#define Acknowledge 3 +#define DataEnd 4 +#define DiskError 5 +// 1x = 75 sectors per second +// PSXCLK = 1 sec in the ps +// so (PSXCLK / 75) / BIAS = cdr read time (linuzappz) +#define cdReadTime ((PSXCLK / 75) / BIAS) + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +static struct CdrStat stat; +static struct SubQ *subq; + +#define CDR_INT(eCycle) { \ + psxRegs.interrupt|= 0x4; \ + psxRegs.intCycle[2+1] = eCycle; \ + psxRegs.intCycle[2] = psxRegs.cycle; } + +#define CDREAD_INT(eCycle) { \ + psxRegs.interrupt|= 0x40000; \ + psxRegs.intCycle[2+16+1] = eCycle; \ + psxRegs.intCycle[2+16] = psxRegs.cycle; } + +#define StartReading(type) { \ + cdr.Reading = type; \ + cdr.FirstSector = 1; \ + cdr.Readed = 0xff; \ + AddIrqQueue(READ_ACK, 0x800); \ +} + +#define StopReading() { \ + if (cdr.Reading) { \ + cdr.Reading = 0; \ + psxRegs.interrupt&=~0x40000; \ + } \ +} + +#define StopCdda() { \ + if (cdr.Play) { \ + if (!Config.Cdda) CDR_stop(); \ + cdr.StatP&=~0x80; \ + cdr.Play = 0; \ + } \ +} + +#define SetResultSize(size) { \ + cdr.ResultP = 0; \ + cdr.ResultC = size; \ + cdr.ResultReady = 1; \ +} + +void ReadTrack() { + cdr.Prev[0] = itob(cdr.SetSector[0]); + cdr.Prev[1] = itob(cdr.SetSector[1]); + cdr.Prev[2] = itob(cdr.SetSector[2]); + +#ifdef CDR_LOG + CDR_LOG("ReadTrack() Log: KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]); +#endif + cdr.RErr = CDR_readTrack(cdr.Prev); +} + + +void AddIrqQueue(unsigned char irq, unsigned long ecycle) { + cdr.Irq = irq; + if (cdr.Stat) { + cdr.eCycle = ecycle; + } else { + CDR_INT(ecycle); + } +} + +void cdrInterrupt() { + int i; + unsigned char Irq = cdr.Irq; + + if (cdr.Stat) { + CDR_INT(0x800); + return; + } + + cdr.Irq = 0xff; + cdr.Ctrl&=~0x80; + + switch (Irq) { + case CdlSync: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlNop: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + i = stat.Status; + if (CDR_getStatus(&stat) != -1) { + if (stat.Type == 0xff) cdr.Stat = DiskError; + if (stat.Status & 0x10) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x11; + cdr.Result[0]&=~0x02; + } + else if (i & 0x10) { + cdr.StatP |= 0x2; + cdr.Result[0]|= 0x2; + CheckCdrom(); + } + } + break; + + case CdlSetloc: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlPlay: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + cdr.StatP|= 0x80; +// if ((cdr.Mode & 0x5) == 0x5) AddIrqQueue(REPPLAY, cdReadTime); + break; + + case CdlForward: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlBackward: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlStandby: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlStop: + cdr.CmdProcess = 0; + SetResultSize(1); + cdr.StatP&=~0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; +// cdr.Stat = Acknowledge; + break; + + case CdlPause: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlPause + 0x20, 0x800); + cdr.Ctrl|= 0x80; + break; + + case CdlPause + 0x20: + SetResultSize(1); + cdr.StatP&=~0x20; + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlInit: + SetResultSize(1); + cdr.StatP = 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; +// if (!cdr.Init) { + AddIrqQueue(CdlInit + 0x20, 0x800); +// } + break; + + case CdlInit + 0x20: + SetResultSize(1); + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + cdr.Init = 1; + break; + + case CdlMute: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlDemute: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlSetfilter: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlSetmode: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlGetmode: + SetResultSize(6); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Result[1] = cdr.Mode; + cdr.Result[2] = cdr.File; + cdr.Result[3] = cdr.Channel; + cdr.Result[4] = 0; + cdr.Result[5] = 0; + cdr.Stat = Acknowledge; + break; + + case CdlGetlocL: + SetResultSize(8); +// for (i=0; i<8; i++) cdr.Result[i] = itob(cdr.Transfer[i]); + for (i=0; i<8; i++) cdr.Result[i] = cdr.Transfer[i]; + cdr.Stat = Acknowledge; + break; + + case CdlGetlocP: + SetResultSize(8); + subq = (struct SubQ*) CDR_getBufferSub(); + if (subq != NULL) { + cdr.Result[0] = subq->TrackNumber; + cdr.Result[1] = subq->IndexNumber; + memcpy(cdr.Result+2, subq->TrackRelativeAddress, 3); + memcpy(cdr.Result+5, subq->AbsoluteAddress, 3); + } else { + cdr.Result[0] = 1; + cdr.Result[1] = 1; + cdr.Result[2] = cdr.Prev[0]; + cdr.Result[3] = itob((btoi(cdr.Prev[1])) - 2); + cdr.Result[4] = cdr.Prev[2]; + memcpy(cdr.Result+5, cdr.Prev, 3); + } + cdr.Stat = Acknowledge; + break; + + case CdlGetTN: + cdr.CmdProcess = 0; + SetResultSize(3); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + if (CDR_getTN(cdr.ResultTN) == -1) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + } else { + cdr.Stat = Acknowledge; + cdr.Result[1] = itob(cdr.ResultTN[0]); + cdr.Result[2] = itob(cdr.ResultTN[1]); + } + break; + + case CdlGetTD: + cdr.CmdProcess = 0; + cdr.Track = btoi(cdr.Param[0]); + SetResultSize(4); + cdr.StatP|= 0x2; + if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) { + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + } else { + cdr.Stat = Acknowledge; + cdr.Result[0] = cdr.StatP; + cdr.Result[1] = itob(cdr.ResultTD[2]); + cdr.Result[2] = itob(cdr.ResultTD[1]); + cdr.Result[3] = itob(cdr.ResultTD[0]); + } + break; + + case CdlSeekL: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.StatP|= 0x40; + cdr.Stat = Acknowledge; + cdr.Seeked = 1; + AddIrqQueue(CdlSeekL + 0x20, 0x800); + break; + + case CdlSeekL + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.StatP&=~0x40; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlSeekP: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.StatP|= 0x40; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlSeekP + 0x20, 0x800); + break; + + case CdlSeekP + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.StatP&=~0x40; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case CdlTest: + cdr.Stat = Acknowledge; + switch (cdr.Param[0]) { + case 0x20: // System Controller ROM Version + SetResultSize(4); + memcpy(cdr.Result, Test20, 4); + break; + case 0x22: + SetResultSize(8); + memcpy(cdr.Result, Test22, 4); + break; + case 0x23: case 0x24: + SetResultSize(8); + memcpy(cdr.Result, Test23, 4); + break; + } + break; + + case CdlID: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlID + 0x20, 0x800); + break; + + case CdlID + 0x20: + SetResultSize(8); + if (CDR_getStatus(&stat) == -1) { + cdr.Result[0] = 0x00; // 0x00 Game CD + cdr.Result[1] = 0x00; // 0x00 loads CD + } + else { + if (stat.Type == 2) { + cdr.Result[0] = 0x08; // 0x08 audio cd + cdr.Result[1] = 0x10; // 0x10 enter cd player + } + else { + cdr.Result[0] = 0x00; // 0x00 game CD + cdr.Result[1] = 0x00; // 0x00 loads CD + } + } + if (!LoadCdBios) cdr.Result[1] |= 0x80; //0x80 leads to the menu in the bios + + cdr.Result[2] = 0x00; + cdr.Result[3] = 0x00; +// strncpy((char *)&cdr.Result[4], "PCSX", 4); +#ifdef HW_RVL + strncpy((char *)&cdr.Result[4], "WSX ", 4); +#else + strncpy((char *)&cdr.Result[4], "GCSX", 4); +#endif + cdr.Stat = Complete; + break; + + case CdlReset: + SetResultSize(1); + cdr.StatP = 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + break; + + case CdlReadToc: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Acknowledge; + AddIrqQueue(CdlReadToc + 0x20, 0x800); + break; + + case CdlReadToc + 0x20: + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = Complete; + break; + + case AUTOPAUSE: + cdr.OCUP = 0; +/* SetResultSize(1); + StopCdda(); + StopReading(); + cdr.OCUP = 0; + cdr.StatP&=~0x20; + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + cdr.Stat = DataEnd; +*/ AddIrqQueue(CdlPause, 0x400); + break; + + case READ_ACK: + if (!cdr.Reading) return; + + SetResultSize(1); + cdr.StatP|= 0x2; + cdr.Result[0] = cdr.StatP; + if (cdr.Seeked == 0) { + cdr.Seeked = 1; + cdr.StatP|= 0x40; + } + cdr.StatP|= 0x20; + cdr.Stat = Acknowledge; + + ReadTrack(); + +// CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + CDREAD_INT(0x40000); + break; + + case REPPLAY_ACK: + cdr.Stat = Acknowledge; + cdr.Result[0] = cdr.StatP; + SetResultSize(1); + AddIrqQueue(REPPLAY, cdReadTime); + break; + + case REPPLAY: + if ((cdr.Mode & 5) != 5) break; +/* if (CDR_getStatus(&stat) == -1) { + cdr.Result[0] = 0; + cdr.Result[1] = 0; + cdr.Result[2] = 0; + cdr.Result[3] = 0; + cdr.Result[4] = 0; + cdr.Result[5] = 0; + cdr.Result[6] = 0; + cdr.Result[7] = 0; + } else memcpy(cdr.Result, &stat.Track, 8); + cdr.Stat = 1; + SetResultSize(8); + AddIrqQueue(REPPLAY_ACK, cdReadTime); +*/ break; + + case 0xff: + return; + + default: + cdr.Stat = Complete; + break; + } + + if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) { + psxHu32ref(0x1070)|= SWAP32((u32)0x4); + psxRegs.interrupt|= 0x80000000; + } + +#ifdef CDR_LOG + CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq); +#endif +} + +void cdrReadInterrupt() { + u8 *buf; + + if (!cdr.Reading) return; + + if (cdr.Stat) { + CDREAD_INT(0x800); + return; + } + +#ifdef CDR_LOG + CDR_LOG("cdrReadInterrupt() Log: KEY END"); +#endif + + cdr.OCUP = 1; + SetResultSize(1); + cdr.StatP|= 0x22; + cdr.StatP&=~0x40; + cdr.Result[0] = cdr.StatP; + + buf = CDR_getBuffer(); + if (buf == NULL) { + cdr.RErr = -1; +#ifdef CDR_LOG + fprintf(emuLog, "cdrReadInterrupt() Log: err\n"); +#endif + memset(cdr.Transfer, 0, 2340); + cdr.Stat = DiskError; + cdr.Result[0]|= 0x01; + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + return; + } + + memcpy(cdr.Transfer, buf, 2340); + cdr.Stat = DataReady; + +#ifdef CDR_LOG + fprintf(emuLog, "cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]); +#endif + + if ((cdr.Muted == 1) && (cdr.Mode & 0x40) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA + if ((cdr.Transfer[4+2] & 0x4) && + ((cdr.Mode&0x8) ? (cdr.Transfer[4+1] == cdr.Channel) : 1) && + (cdr.Transfer[4+0] == cdr.File)) { + int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector); + + if (!ret) { + SPU_playADPCMchannel(&cdr.Xa); + cdr.FirstSector = 0; + } + else cdr.FirstSector = -1; + } + } + + cdr.SetSector[2]++; + if (cdr.SetSector[2] == 75) { + cdr.SetSector[2] = 0; + cdr.SetSector[1]++; + if (cdr.SetSector[1] == 60) { + cdr.SetSector[1] = 0; + cdr.SetSector[0]++; + } + } + + cdr.Readed = 0; + + if ((cdr.Transfer[4+2] & 0x80) && (cdr.Mode & 0x2)) { // EOF +#ifdef CDR_LOG + CDR_LOG("cdrReadInterrupt() Log: Autopausing read\n"); +#endif +// AddIrqQueue(AUTOPAUSE, 0x800); + AddIrqQueue(CdlPause, 0x800); + } + else { + ReadTrack(); + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + } + psxHu32ref(0x1070)|= SWAP32((u32)0x4); + psxRegs.interrupt|= 0x80000000; +} + +/* +cdrRead0: + bit 0 - 0 REG1 command send / 1 REG1 data read + bit 1 - 0 data transfer finish / 1 data transfer ready/in progress + bit 2 - unknown + bit 3 - unknown + bit 4 - unknown + bit 5 - 1 result ready + bit 6 - 1 dma ready + bit 7 - 1 command being processed +*/ + +unsigned char cdrRead0(void) { + if (cdr.ResultReady) cdr.Ctrl|= 0x20; + else cdr.Ctrl&=~0x20; + + if (cdr.OCUP) cdr.Ctrl|= 0x40; +// else cdr.Ctrl&=~0x40; + + // what means the 0x10 and the 0x08 bits? i only saw it used by the bios + cdr.Ctrl|=0x18; + +#ifdef CDR_LOG + CDR_LOG("cdrRead0() Log: CD0 Read: %x\n", cdr.Ctrl); +#endif + return psxHu8(0x1800) = cdr.Ctrl; +} + +/* +cdrWrite0: + 0 - to send a command / 1 - to get the result +*/ + +void cdrWrite0(unsigned char rt) { +#ifdef CDR_LOG + CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt); +#endif + cdr.Ctrl = rt | (cdr.Ctrl & ~0x3); + + if (rt == 0) { + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 0; + } +} + +unsigned char cdrRead1(void) { + if (cdr.ResultReady) { // && cdr.Ctrl & 0x1) { + psxHu8(0x1801) = cdr.Result[cdr.ResultP++]; + if (cdr.ResultP == cdr.ResultC) cdr.ResultReady = 0; + } else psxHu8(0x1801) = 0; +#ifdef CDR_LOG + CDR_LOG("cdrRead1() Log: CD1 Read: %x\n", psxHu8(0x1801)); +#endif + return psxHu8(0x1801); +} + +void cdrWrite1(unsigned char rt) { + int i; + +#ifdef CDR_LOG + CDR_LOG("cdrWrite1() Log: CD1 write: %x (%s)\n", rt, CmdName[rt]); +#endif +// psxHu8(0x1801) = rt; + cdr.Cmd = rt; + cdr.OCUP = 0; + +#ifdef CDRCMD_DEBUG + SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]); + if (cdr.ParamC) { + SysPrintf(" Param[%d] = {", cdr.ParamC); + for (i=0;i cdr.ResultTN[1]) cdr.CurTrack = cdr.ResultTN[1]; + if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) { + int tmp = cdr.ResultTD[2]; + cdr.ResultTD[2] = cdr.ResultTD[0]; + cdr.ResultTD[0] = tmp; + if (!Config.Cdda) CDR_play(cdr.ResultTD); + } + } + } + else if (!Config.Cdda) CDR_play(cdr.SetSector); + cdr.Play = 1; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlForward: + if (cdr.CurTrack < 0xaa) cdr.CurTrack++; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlBackward: + if (cdr.CurTrack > 1) cdr.CurTrack--; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadN: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(1); + break; + + case CdlStandby: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlStop: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlPause: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x40000); + break; + + case CdlReset: + case CdlInit: + StopCdda(); + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlMute: + cdr.Muted = 0; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlDemute: + cdr.Muted = 1; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetfilter: + cdr.File = cdr.Param[0]; + cdr.Channel = cdr.Param[1]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSetmode: +#ifdef CDR_LOG + CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]); +#endif + cdr.Mode = cdr.Param[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetmode: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocL: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetlocP: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTN: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlGetTD: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekL: +// ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlSeekP: +// ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0]; + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlTest: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlID: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + case CdlReadS: + cdr.Irq = 0; + StopReading(); + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + StartReading(2); + break; + + case CdlReadToc: + cdr.Ctrl|= 0x80; + cdr.Stat = NoIntr; + AddIrqQueue(cdr.Cmd, 0x800); + break; + + default: +#ifdef CDR_LOG + CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd); +#endif + return; + } + if (cdr.Stat != NoIntr) { + psxHu32ref(0x1070)|= SWAP32((u32)0x4); + psxRegs.interrupt|= 0x80000000; + } +} + +unsigned char cdrRead2(void) { + unsigned char ret; + + if (cdr.Readed == 0) { + ret = 0; + } else { + ret = *cdr.pTransfer++; + } + +#ifdef CDR_LOG + CDR_LOG("cdrRead2() Log: CD2 Read: %x\n", ret); +#endif + return ret; +} + +void cdrWrite2(unsigned char rt) { +#ifdef CDR_LOG + CDR_LOG("cdrWrite2() Log: CD2 write: %x\n", rt); +#endif + if (cdr.Ctrl & 0x1) { + switch (rt) { + case 0x07: + cdr.ParamP = 0; + cdr.ParamC = 0; + cdr.ResultReady = 1; //0; + cdr.Ctrl&= ~3; //cdr.Ctrl = 0; + break; + + default: + cdr.Reg2 = rt; + break; + } + } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) { + cdr.Param[cdr.ParamP++] = rt; + cdr.ParamC++; + } +} + +unsigned char cdrRead3(void) { + if (cdr.Stat) { + if (cdr.Ctrl & 0x1) psxHu8(0x1803) = cdr.Stat | 0xE0; + else psxHu8(0x1803) = 0xff; + } else psxHu8(0x1803) = 0; +#ifdef CDR_LOG + CDR_LOG("cdrRead3() Log: CD3 Read: %x\n", psxHu8(0x1803)); +#endif + return psxHu8(0x1803); +} + +void cdrWrite3(unsigned char rt) { +#ifdef CDR_LOG + CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt); +#endif + if (rt == 0x07 && cdr.Ctrl & 0x1) { + cdr.Stat = 0; + + if (cdr.Irq == 0xff) { cdr.Irq = 0; return; } + if (cdr.Irq) CDR_INT(cdr.eCycle); + if (cdr.Reading && !cdr.ResultReady) + CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime); + + return; + } + if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) { + cdr.Readed = 1; + cdr.pTransfer = cdr.Transfer; + + switch (cdr.Mode&0x30) { + case 0x10: + case 0x00: cdr.pTransfer+=12; break; + default: break; + } + } +} + +void psxDma3(u32 madr, u32 bcr, u32 chcr) { + u32 cdsize; + u8 *ptr; + +#ifdef CDR_LOG + CDR_LOG("psxDma3() Log: *** DMA 3 *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); +#endif + + switch (chcr) { + case 0x11000000: + case 0x11400100: + if (cdr.Readed == 0) { +#ifdef CDR_LOG + CDR_LOG("psxDma3() Log: *** DMA 3 *** NOT READY\n"); +#endif + break; + } + + cdsize = (bcr & 0xffff) * 4; + + ptr = (u8*)PSXM(madr); + if (ptr == NULL) { +#ifdef CPU_LOG + CDR_LOG("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n"); +#endif + break; + } + memcpy(ptr, cdr.pTransfer, cdsize); + psxCpu->Clear(madr, cdsize/4); + cdr.pTransfer+= cdsize; + + break; + default: +#ifdef CDR_LOG + CDR_LOG("psxDma3() Log: Unknown cddma %lx\n", chcr); +#endif + break; + } + + HW_DMA3_CHCR &= SWAP32(~0x01000000); + DMA_INTERRUPT(3); +} + +void cdrReset() { + memset(&cdr, 0, sizeof(cdr)); + cdr.CurTrack=1; + cdr.File=1; cdr.Channel=1; +} + +int cdrFreeze(gzFile f, int Mode) { + uintptr_t tmp; + + gzfreeze(&cdr, sizeof(cdr)); + + if (Mode == 1) tmp = cdr.pTransfer - cdr.Transfer; + gzfreezel(&tmp); + if (Mode == 0) cdr.pTransfer = cdr.Transfer + tmp; + + return 0; +} + + diff --git a/cdrom.h b/cdrom.h new file mode 100644 index 0000000..fa4af89 --- /dev/null +++ b/cdrom.h @@ -0,0 +1,95 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __CDROM_H__ +#define __CDROM_H__ + +#include "psxcommon.h" +#include "decode_xa.h" +#include "r3000a.h" +#include "plugins.h" +#include "psxmem.h" +#include "psxhw.h" + +typedef struct { + unsigned char OCUP; + unsigned char Reg1Mode; + unsigned char Reg2; + unsigned char CmdProcess; + unsigned char Ctrl; + unsigned char Stat; + + unsigned char StatP; + + unsigned char Transfer[2352]; + unsigned char *pTransfer; + + unsigned char Prev[4]; + unsigned char Param[8]; + unsigned char Result[8]; + + unsigned char ParamC; + unsigned char ParamP; + unsigned char ResultC; + unsigned char ResultP; + unsigned char ResultReady; + unsigned char Cmd; + unsigned char Readed; + unsigned long Reading; + + unsigned char ResultTN[6]; + unsigned char ResultTD[4]; + unsigned char SetSector[4]; + unsigned char SetSectorSeek[4]; + unsigned char Track; + int Play; + int CurTrack; + int Mode, File, Channel, Muted; + int Reset; + int RErr; + int FirstSector; + + xa_decode_t Xa; + + int Init; + + unsigned char Irq; + unsigned long eCycle; + + int Seeked; + + char Unused[4083]; +} cdrStruct; + +cdrStruct cdr; + +void cdrReset(); +void cdrInterrupt(); +void cdrReadInterrupt(); +unsigned char cdrRead0(void); +unsigned char cdrRead1(void); +unsigned char cdrRead2(void); +unsigned char cdrRead3(void); +void cdrWrite0(unsigned char rt); +void cdrWrite1(unsigned char rt); +void cdrWrite2(unsigned char rt); +void cdrWrite3(unsigned char rt); +int cdrFreeze(gzFile f, int Mode); + +#endif /* __CDROM_H__ */ diff --git a/coff.h b/coff.h new file mode 100644 index 0000000..6305473 --- /dev/null +++ b/coff.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __COFF_H__ +#define __COFF_H__ + +/********************** FILE HEADER **********************/ + +struct external_filehdr { + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + unsigned long f_timdat; /* time & date stamp */ + unsigned long f_symptr; /* file pointer to symtab */ + unsigned long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ +}; + +#define FILHDR struct external_filehdr +#define FILHSZ sizeof(FILHDR) + +#endif /* __COFF_H__ */ diff --git a/coredebug.h b/coredebug.h new file mode 100644 index 0000000..0bacf4d --- /dev/null +++ b/coredebug.h @@ -0,0 +1,65 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Specficies which logs should be activated. +* Ryan TODO: These should ALL be definable with configure flags. +*/ + +#ifndef __CORE_DEBUG_H__ +#define __CORE_DEBUG_H__ + +#include +#include + +extern char *disRNameCP0[]; + +char* disR3000AF(u32 code, u32 pc); + +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) +extern FILE *emuLog; +#endif + +//#define GTE_DUMP + +#ifdef GTE_DUMP +FILE *gteLog; +#endif + +//#define LOG_STDOUT + +//#define PAD_LOG __Log +//#define GTE_LOG __Log +//#define CDR_LOG __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); __Log + +//#define PSXHW_LOG __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); __Log +//#define PSXBIOS_LOG __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); __Log +//#define PSXDMA_LOG __Log +//#define PSXMEM_LOG __Log("%8.8lx %8.8lx: ", psxRegs.pc, psxRegs.cycle); __Log +//#define PSXCPU_LOG __Log + +//#define CDRCMD_DEBUG + +#if defined (PSXCPU_LOG) || defined(PSXDMA_LOG) || defined(CDR_LOG) || defined(PSXHW_LOG) || \ + defined(PSXBIOS_LOG) || defined(PSXMEM_LOG) || defined(GTE_LOG) || defined(PAD_LOG) +#define EMU_LOG __Log +#endif + +#endif /* __DEBUG_H__ */ diff --git a/decode_xa.c b/decode_xa.c new file mode 100644 index 0000000..5757428 --- /dev/null +++ b/decode_xa.c @@ -0,0 +1,367 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* XA audio decoding functions (Kazzuya). +*/ + +#include "decode_xa.h" + +#define _FIXED + +#define NOT(_X_) (!(_X_)) +#define XACLAMP(_X_,_MI_,_MA_) {if(_X_<_MI_)_X_=_MI_;if(_X_>_MA_)_X_=_MA_;} + +#define SH 4 +#define SHC 10 + +//============================================ +//=== ADPCM DECODING ROUTINES +//============================================ + +#ifndef _FIXED +static float K0[4] = { + 0.0, + 0.9375, + 1.796875, + 1.53125 +}; + +static float K1[4] = { + 0.0, + 0.0, + -0.8125, + -0.859375 +}; +#else +static int K0[4] = { + 0.0 * (1<y0 = 0; + decp->y1 = 0; +} + +//=========================================== +#ifndef _FIXED +#define IK0(fid) ((int)((-K0[fid]) * (1<> 4) & 0x0f; + range = (filter_range >> 0) & 0x0f; + + fy0 = decp->y0; + fy1 = decp->y1; + + for (i = BLKSIZ/4; i; --i) { + s32 y; + s32 x0, x1, x2, x3; + + y = *blockp++; + x3 = (short)( y & 0xf000) >> range; x3 <<= SH; + x2 = (short)((y << 4) & 0xf000) >> range; x2 <<= SH; + x1 = (short)((y << 8) & 0xf000) >> range; x1 <<= SH; + x0 = (short)((y << 12) & 0xf000) >> range; x0 <<= SH; + + x0 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x0; + x1 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x1; + x2 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x2; + x3 -= (IK0(filterid) * fy0 + (IK1(filterid) * fy1)) >> SHC; fy1 = fy0; fy0 = x3; + + XACLAMP( x0, -32768<> SH; destp += inc; + XACLAMP( x1, -32768<> SH; destp += inc; + XACLAMP( x2, -32768<> SH; destp += inc; + XACLAMP( x3, -32768<> SH; destp += inc; + } + decp->y0 = fy0; + decp->y1 = fy1; +} + +static int headtable[4] = {0,2,8,10}; + +//=========================================== +static void xa_decode_data( xa_decode_t *xdp, unsigned char *srcp ) { + const u8 *sound_groupsp; + const u8 *sound_datap, *sound_datap2; + int i, j, k, nbits; + u16 data[4096], *datap; + short *destp; + + destp = xdp->pcm; + nbits = xdp->nbits == 4 ? 4 : 2; + + if (xdp->stereo) { // stereo + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (u16)sound_datap2[0] | + (u16)(sound_datap2[4] << 8); + } + + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp+0, 2 ); + + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (u16)sound_datap2[0] | + (u16)(sound_datap2[4] << 8); + } + ADPCM_DecodeBlock16( &xdp->right, sound_groupsp[headtable[i]+1], data, + destp+1, 2 ); + + destp += 28*2; + } + } + } else { // level B/C + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (u16)(sound_datap2[ 0] & 0x0f) | + ((u16)(sound_datap2[ 4] & 0x0f) << 4) | + ((u16)(sound_datap2[ 8] & 0x0f) << 8) | + ((u16)(sound_datap2[12] & 0x0f) << 12); + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp+0, 2 ); + + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (u16)(sound_datap2[ 0] >> 4) | + ((u16)(sound_datap2[ 4] >> 4) << 4) | + ((u16)(sound_datap2[ 8] >> 4) << 8) | + ((u16)(sound_datap2[12] >> 4) << 12); + } + ADPCM_DecodeBlock16( &xdp->right, sound_groupsp[headtable[i]+1], data, + destp+1, 2 ); + + destp += 28*2; + } + } + } + } else { // mono + if ((xdp->nbits == 8) && (xdp->freq == 37800)) { // level A + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (u16)sound_datap2[0] | + (u16)(sound_datap2[4] << 8); + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp, 1 ); + + destp += 28; + + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 14; k++, sound_datap2 += 8) { + *(datap++) = (u16)sound_datap2[0] | + (u16)(sound_datap2[4] << 8); + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+1], data, + destp, 1 ); + + destp += 28; + } + } + } else { // level B/C + for (j=0; j < 18; j++) { + sound_groupsp = srcp + j * 128; // sound groups header + sound_datap = sound_groupsp + 16; // sound data just after the header + + for (i=0; i < nbits; i++) { + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (u16)(sound_datap2[ 0] & 0x0f) | + ((u16)(sound_datap2[ 4] & 0x0f) << 4) | + ((u16)(sound_datap2[ 8] & 0x0f) << 8) | + ((u16)(sound_datap2[12] & 0x0f) << 12); + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+0], data, + destp, 1 ); + + destp += 28; + + datap = data; + sound_datap2 = sound_datap + i; + for (k=0; k < 7; k++, sound_datap2 += 16) { + *(datap++) = (u16)(sound_datap2[ 0] >> 4) | + ((u16)(sound_datap2[ 4] >> 4) << 4) | + ((u16)(sound_datap2[ 8] >> 4) << 8) | + ((u16)(sound_datap2[12] >> 4) << 12); + } + ADPCM_DecodeBlock16( &xdp->left, sound_groupsp[headtable[i]+1], data, + destp, 1 ); + + destp += 28; + } + } + } + } +} + +//============================================ +//=== XA SPECIFIC ROUTINES +//============================================ +typedef struct { +u8 filenum; +u8 channum; +u8 submode; +u8 coding; + +u8 filenum2; +u8 channum2; +u8 submode2; +u8 coding2; +} xa_subheader_t; + +#define SUB_SUB_EOF (1<<7) // end of file +#define SUB_SUB_RT (1<<6) // real-time sector +#define SUB_SUB_FORM (1<<5) // 0 form1 1 form2 +#define SUB_SUB_TRIGGER (1<<4) // used for interrupt +#define SUB_SUB_DATA (1<<3) // contains data +#define SUB_SUB_AUDIO (1<<2) // contains audio +#define SUB_SUB_VIDEO (1<<1) // contains video +#define SUB_SUB_EOR (1<<0) // end of record + +#define AUDIO_CODING_GET_STEREO(_X_) ( (_X_) & 3) +#define AUDIO_CODING_GET_FREQ(_X_) (((_X_) >> 2) & 3) +#define AUDIO_CODING_GET_BPS(_X_) (((_X_) >> 4) & 3) +#define AUDIO_CODING_GET_EMPHASIS(_X_) (((_X_) >> 6) & 1) + +#define SUB_UNKNOWN 0 +#define SUB_VIDEO 1 +#define SUB_AUDIO 2 + +//============================================ +static int parse_xa_audio_sector( xa_decode_t *xdp, + xa_subheader_t *subheadp, + unsigned char *sectorp, + int is_first_sector ) { + if ( is_first_sector ) { + switch ( AUDIO_CODING_GET_FREQ(subheadp->coding) ) { + case 0: xdp->freq = 37800; break; + case 1: xdp->freq = 18900; break; + default: xdp->freq = 0; break; + } + switch ( AUDIO_CODING_GET_BPS(subheadp->coding) ) { + case 0: xdp->nbits = 4; break; + case 1: xdp->nbits = 8; break; + default: xdp->nbits = 0; break; + } + switch ( AUDIO_CODING_GET_STEREO(subheadp->coding) ) { + case 0: xdp->stereo = 0; break; + case 1: xdp->stereo = 1; break; + default: xdp->stereo = 0; break; + } + + if ( xdp->freq == 0 ) + return -1; + + ADPCM_InitDecode( &xdp->left ); + ADPCM_InitDecode( &xdp->right ); + + xdp->nsamples = 18 * 28 * 8; + if (xdp->stereo == 1) xdp->nsamples /= 2; + } + xa_decode_data( xdp, sectorp ); + + return 0; +} + +//================================================================ +//=== THIS IS WHAT YOU HAVE TO CALL +//=== xdp - structure were all important data are returned +//=== sectorp - data in input +//=== pcmp - data in output +//=== is_first_sector - 1 if it's the 1st sector of the stream +//=== - 0 for any other successive sector +//=== return -1 if error +//================================================================ +s32 xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, int is_first_sector ) { + if (parse_xa_audio_sector(xdp, (xa_subheader_t *)sectorp, sectorp + sizeof(xa_subheader_t), is_first_sector)) + return -1; + + return 0; +} + +/* EXAMPLE: +"nsamples" is the number of 16 bit samples +every sample is 2 bytes in mono and 4 bytes in stereo + +xa_decode_t xa; + + sectorp = read_first_sector(); + xa_decode_sector( &xa, sectorp, 1 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + + while ( --n_sectors ) + { + sectorp = read_next_sector(); + xa_decode_sector( &xa, sectorp, 0 ); + play_wave( xa.pcm, xa.freq, xa.nsamples ); + } +*/ diff --git a/decode_xa.h b/decode_xa.h new file mode 100644 index 0000000..788f0b6 --- /dev/null +++ b/decode_xa.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __DECODE_XA_H__ +#define __DECODE_XA_H__ + +#include "psxcommon.h" + +typedef struct { + s32 y0, y1; +} ADPCM_Decode_t; + +typedef struct { + int freq; + int nbits; + int stereo; + int nsamples; + ADPCM_Decode_t left, right; + short pcm[16384]; +} xa_decode_t; + +s32 xa_decode_sector( xa_decode_t *xdp, + unsigned char *sectorp, + int is_first_sector ); + +#endif diff --git a/disr3000a.c b/disr3000a.c new file mode 100644 index 0000000..9b8aff5 --- /dev/null +++ b/disr3000a.c @@ -0,0 +1,323 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* R3000A disassembler. +*/ + +#include "psxcommon.h" + +char ostr[256]; + +// Names of registers +static char *disRNameGPR[] = { + "r0", "at", "v0", "v1", "a0", "a1","a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5","t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5","s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp","fp", "ra"}; + +char *disRNameCP0[] = { + "Index" , "Random" , "EntryLo0", "EntryLo1", "Context" , "PageMask" , "Wired" , "*Check me*", + "BadVAddr" , "Count" , "EntryHi" , "Compare" , "Status" , "Cause" , "ExceptPC" , "PRevID" , + "Config" , "LLAddr" , "WatchLo" , "WatchHi" , "XContext", "*RES*" , "*RES*" , "*RES*" , + "*RES*" , "*RES* " , "PErr" , "CacheErr", "TagLo" , "TagHi" , "ErrorEPC" , "*RES*" }; + + +// Type deffinition of our functions + +typedef char* (*TdisR3000AF)(u32 code, u32 pc); + +// These macros are used to assemble the disassembler functions +#define MakeDisFg(fn, b) char* fn(u32 code, u32 pc) { b; return ostr; } +#define MakeDisF(fn, b) \ + static char* fn(u32 code, u32 pc) { \ + sprintf (ostr, "%08x %08x:", pc, code); \ + b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ + } + + +#include "r3000a.h" + +#undef _Funct_ +#undef _Rd_ +#undef _Rt_ +#undef _Rs_ +#undef _Sa_ +#undef _Im_ +#undef _Target_ + +#define _Funct_ ((code ) & 0x3F) // The funct part of the instruction register +#define _Rd_ ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _Rt_ ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _Rs_ ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _Sa_ ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _Im_ ( code & 0xFFFF) // The immediate part of the instruction register + +#define _Target_ ((pc & 0xf0000000) + ((code & 0x03ffffff) * 4)) +#define _Branch_ (pc + 4 + ((short)_Im_ * 4)) +#define _OfB_ _Im_, _nRs_ + +#define dName(i) sprintf(ostr+strlen(ostr), " %-7s,", i) +#define dGPR(i) sprintf(ostr+strlen(ostr), " %08x (%s),", psxRegs.GPR.r[i], disRNameGPR[i]) +#define dCP0(i) sprintf(ostr+strlen(ostr), " %08x (%s),", psxRegs.CP0.r[i], disRNameCP0[i]) +#define dHI() sprintf(ostr+strlen(ostr), " %08x (%s),", psxRegs.GPR.n.hi, "hi") +#define dLO() sprintf(ostr+strlen(ostr), " %08x (%s),", psxRegs.GPR.n.lo, "lo") +#define dImm() sprintf(ostr+strlen(ostr), " %08x (%08x),", _Im_, _Im_) +#define dTarget() sprintf(ostr+strlen(ostr), " %08x,", _Target_) +#define dSa() sprintf(ostr+strlen(ostr), " %08x (%08x),", _Sa_, _Sa_) +#define dOfB() sprintf(ostr+strlen(ostr), " %08x (%08x (%s)),", _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_]) +#define dOffset() sprintf(ostr+strlen(ostr), " %08x,", _Branch_) +#define dCode() sprintf(ostr+strlen(ostr), " %08x,", (code >> 6) & 0xffffff) + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +MakeDisF(disADDI, dName("ADDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disADDIU, dName("ADDIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disANDI, dName("ANDI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disORI, dName("ORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTI, dName("SLTI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disSLTIU, dName("SLTIU"); dGPR(_Rt_); dGPR(_Rs_); dImm();) +MakeDisF(disXORI, dName("XORI"); dGPR(_Rt_); dGPR(_Rs_); dImm();) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +MakeDisF(disADD, dName("ADD"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disADDU, dName("ADDU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disAND, dName("AND"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disNOR, dName("NOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disOR, dName("OR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLT, dName("SLT"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSLTU, dName("SLTU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUB, dName("SUB"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disSUBU, dName("SUBU"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disXOR, dName("XOR"); dGPR(_Rd_); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register arithmetic & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +MakeDisF(disDIV, dName("DIV"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disDIVU, dName("DIVU"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULT, dName("MULT"); dGPR(_Rs_); dGPR(_Rt_);) +MakeDisF(disMULTU, dName("MULTU"); dGPR(_Rs_); dGPR(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +MakeDisF(disBGEZ, dName("BGEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGEZAL, dName("BGEZAL"); dGPR(_Rs_); dOffset();) +MakeDisF(disBGTZ, dName("BGTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLEZ, dName("BLEZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZ, dName("BLTZ"); dGPR(_Rs_); dOffset();) +MakeDisF(disBLTZAL, dName("BLTZAL"); dGPR(_Rs_); dOffset();) + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +MakeDisF(disSLL, if (code) { dName("SLL"); dGPR(_Rd_); dGPR(_Rt_); dSa(); } else { dName("NOP"); }) +MakeDisF(disSRA, dName("SRA"); dGPR(_Rd_); dGPR(_Rt_); dSa();) +MakeDisF(disSRL, dName("SRL"); dGPR(_Rd_); dGPR(_Rt_); dSa();) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +MakeDisF(disSLLV, dName("SLLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRAV, dName("SRAV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) +MakeDisF(disSRLV, dName("SRLV"); dGPR(_Rd_); dGPR(_Rt_); dGPR(_Rs_);) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +MakeDisF(disLUI, dName("LUI"); dGPR(_Rt_); dImm();) + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMFHI, dName("MFHI"); dGPR(_Rd_); dHI();) +MakeDisF(disMFLO, dName("MFLO"); dGPR(_Rd_); dLO();) + +/********************************************************* +* Move from GPR to HI/LO * +* Format: OP rd * +*********************************************************/ +MakeDisF(disMTHI, dName("MTHI"); dHI(); dGPR(_Rs_);) +MakeDisF(disMTLO, dName("MTLO"); dLO(); dGPR(_Rs_);) + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +MakeDisF(disBREAK, dName("BREAK")) +MakeDisF(disRFE, dName("RFE")) +MakeDisF(disSYSCALL, dName("SYSCALL")) +MakeDisF(disHLE, dName("HLE")) + + +MakeDisF(disRTPS, dName("RTPS")) +MakeDisF(disOP , dName("OP")) +MakeDisF(disNCLIP, dName("NCLIP")) +MakeDisF(disDPCS, dName("DPCS")) +MakeDisF(disINTPL, dName("INTPL")) +MakeDisF(disMVMVA, dName("MVMVA")) +MakeDisF(disNCDS , dName("NCDS")) +MakeDisF(disCDP , dName("CDP")) +MakeDisF(disNCDT , dName("NCDT")) +MakeDisF(disNCCS , dName("NCCS")) +MakeDisF(disCC , dName("CC")) +MakeDisF(disNCS , dName("NCS")) +MakeDisF(disNCT , dName("NCT")) +MakeDisF(disSQR , dName("SQR")) +MakeDisF(disDCPL , dName("DCPL")) +MakeDisF(disDPCT , dName("DPCT")) +MakeDisF(disAVSZ3, dName("AVSZ3")) +MakeDisF(disAVSZ4, dName("AVSZ4")) +MakeDisF(disRTPT , dName("RTPT")) +MakeDisF(disGPF , dName("GPF")) +MakeDisF(disGPL , dName("GPL")) +MakeDisF(disNCCT , dName("NCCT")) + +MakeDisF(disMFC2, dName("MFC2"); dGPR(_Rt_);) +MakeDisF(disCFC2, dName("CFC2"); dGPR(_Rt_);) +MakeDisF(disMTC2, dName("MTC2"); dGPR(_Rt_);) +MakeDisF(disCTC2, dName("CTC2"); dGPR(_Rt_);) + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +MakeDisF(disBEQ, dName("BEQ"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) +MakeDisF(disBNE, dName("BNE"); dGPR(_Rs_); dGPR(_Rt_); dOffset();) + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +MakeDisF(disJ, dName("J"); dTarget();) +MakeDisF(disJAL, dName("JAL"); dTarget(); dGPR(31);) + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +MakeDisF(disJR, dName("JR"); dGPR(_Rs_);) +MakeDisF(disJALR, dName("JALR"); dGPR(_Rs_); dGPR(_Rd_)) + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ +MakeDisF(disLB, dName("LB"); dGPR(_Rt_); dOfB();) +MakeDisF(disLBU, dName("LBU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLH, dName("LH"); dGPR(_Rt_); dOfB();) +MakeDisF(disLHU, dName("LHU"); dGPR(_Rt_); dOfB();) +MakeDisF(disLW, dName("LW"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWL, dName("LWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWR, dName("LWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disLWC2, dName("LWC2"); dGPR(_Rt_); dOfB();) +MakeDisF(disSB, dName("SB"); dGPR(_Rt_); dOfB();) +MakeDisF(disSH, dName("SH"); dGPR(_Rt_); dOfB();) +MakeDisF(disSW, dName("SW"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWL, dName("SWL"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWR, dName("SWR"); dGPR(_Rt_); dOfB();) +MakeDisF(disSWC2, dName("SWC2"); dGPR(_Rt_); dOfB();) + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +MakeDisF(disMFC0, dName("MFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disMTC0, dName("MTC0"); dCP0(_Rd_); dGPR(_Rt_);) +MakeDisF(disCFC0, dName("CFC0"); dGPR(_Rt_); dCP0(_Rd_);) +MakeDisF(disCTC0, dName("CTC0"); dCP0(_Rd_); dGPR(_Rt_);) + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +MakeDisF(disNULL, dName("*** Bad OP ***");) + + +TdisR3000AF disR3000A_SPECIAL[] = { // Subset of disSPECIAL + disSLL , disNULL , disSRL , disSRA , disSLLV , disNULL , disSRLV , disSRAV , + disJR , disJALR , disNULL, disNULL, disSYSCALL, disBREAK , disNULL , disNULL , + disMFHI, disMTHI , disMFLO, disMTLO, disNULL , disNULL , disNULL , disNULL , + disMULT, disMULTU, disDIV , disDIVU, disNULL , disNULL , disNULL , disNULL , + disADD , disADDU , disSUB , disSUBU, disAND , disOR , disXOR , disNOR , + disNULL, disNULL , disSLT , disSLTU, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL , + disNULL, disNULL , disNULL, disNULL, disNULL , disNULL , disNULL , disNULL}; + +MakeDisF(disSPECIAL, disR3000A_SPECIAL[_Funct_](code, pc)) + +TdisR3000AF disR3000A_BCOND[] = { // Subset of disBCOND + disBLTZ , disBGEZ , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disBLTZAL, disBGEZAL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL , disNULL , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBCOND, disR3000A_BCOND[_Rt_](code, pc)) + +TdisR3000AF disR3000A_COP0[] = { // Subset of disCOP0 + disMFC0, disNULL, disCFC0, disNULL, disMTC0, disNULL, disCTC0, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disRFE , disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disCOP0, disR3000A_COP0[_Rs_](code, pc)) + +TdisR3000AF disR3000A_BASIC[] = { // Subset of disBASIC (based on rs) + disMFC2, disNULL, disCFC2, disNULL, disMTC2, disNULL, disCTC2, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, + disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL, disNULL}; + +MakeDisF(disBASIC, disR3000A_BASIC[_Rs_](code, pc)) + +TdisR3000AF disR3000A_COP2[] = { // Subset of disR3000F_COP2 (based on funct) + disBASIC, disRTPS , disNULL , disNULL , disNULL, disNULL , disNCLIP, disNULL, + disNULL , disNULL , disNULL , disNULL , disOP , disNULL , disNULL , disNULL, + disDPCS , disINTPL, disMVMVA, disNCDS , disCDP , disNULL , disNCDT , disNULL, + disNULL , disNULL , disNULL , disNCCS , disCC , disNULL , disNCS , disNULL, + disNCT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disSQR , disDCPL , disDPCT , disNULL , disNULL, disAVSZ3, disAVSZ4, disNULL, + disRTPT , disNULL , disNULL , disNULL , disNULL, disNULL , disNULL , disNULL, + disNULL , disNULL , disNULL , disNULL , disNULL, disGPF , disGPL , disNCCT }; + +MakeDisF(disCOP2, disR3000A_COP2[_Funct_](code, pc)) + +TdisR3000AF disR3000A[] = { + disSPECIAL , disBCOND , disJ , disJAL , disBEQ , disBNE , disBLEZ , disBGTZ , + disADDI , disADDIU , disSLTI , disSLTIU, disANDI, disORI , disXORI , disLUI , + disCOP0 , disNULL , disCOP2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disNULL , disNULL , disNULL, disNULL, disNULL , disNULL , + disLB , disLH , disLWL , disLW , disLBU , disLHU , disLWR , disNULL , + disSB , disSH , disSWL , disSW , disNULL, disNULL, disSWR , disNULL , + disNULL , disNULL , disLWC2 , disNULL , disNULL, disNULL, disNULL , disNULL , + disNULL , disNULL , disSWC2 , disHLE , disNULL, disNULL, disNULL , disNULL }; + +MakeDisFg(disR3000AF, disR3000A[code >> 26](code, pc)) diff --git a/extendedkeys.h b/extendedkeys.h new file mode 100644 index 0000000..1b6475b --- /dev/null +++ b/extendedkeys.h @@ -0,0 +1,23 @@ + +#ifndef __EXTENDED_KEYS_H__ +#define __EXTENDED_KEYS_H__ + +enum { + PSX_FREEZE_KEY = 0xFFBE/*XK_F1*/, + PSX_NEXT_FREEZE_SLOT_KEY = 0xFFBF/*XK_F2*/, + PSX_DEFROST_KEY = 0xFFC0/*XK_F3*/, + PSX_SHOW_FREEZE_PIC_KEY = 0xFFC1/*XK_F4*/, + PSX_SIO_ALWAYS_ON_KEY = 0xFFC2/*XK_F5*/, + PSX_BW_MDEC_KEY = 0xFFC3/*XK_F6*/, + PSX_XA_AUDIO_ON_KEY = 0xFFC4/*XK_F7*/, + PSX_SNAPSHOT_KEY = 0xFFC5/*XK_F8*/, + PSX_OPEN_SHELL_KEY = 0xFFC6/*XK_F9*/, + PSX_CLOSE_SHELL_KEY = 0xFFC7/*XK_F10*/, + + PSX_STOP_KEY = 0xFF1B/*XK_Escape*/, + + GPU_FULLSCREEN_KEY = 0x0100, + GPU_FPS_DISPLAY_KEY = 0xFFFF/*XK_Delete*/ +}; + +#endif //__EXTENDED_KEYS_H__ diff --git a/franspu/cube_audio.c b/franspu/cube_audio.c new file mode 100644 index 0000000..58f1751 --- /dev/null +++ b/franspu/cube_audio.c @@ -0,0 +1,111 @@ +//cube_audio.c AUDIO output via libOGC + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. See also the license.txt file for * + * additional informations. * + * * + ***************************************************************************/ +#include "franspu.h" +#include "../psxcommon.h" + +//////////////////////////////////////////////////////////////////////// +// cube audio globals +//////////////////////////////////////////////////////////////////////// +#include "../Gamecube/DEBUG.h" +#include + + +char audioEnabled; + +static const u32 freq = 44100; +extern unsigned int iVolume; +static AESNDPB* voice = NULL; + +#define NUM_BUFFERS 4 +static struct { void* buffer; u32 len; } buffers[NUM_BUFFERS]; +static u32 fill_buffer, play_buffer; + +static void aesnd_callback(AESNDPB* voice, u32 state); + +void SetVolume(void) +{ + // iVolume goes 1 (loudest) - 4 (lowest); volume goes 255-64 + u16 volume = (4 - iVolume + 1) * 64 - 1; + if (voice) AESND_SetVoiceVolume(voice, volume, volume); +} + +//////////////////////////////////////////////////////////////////////// +// SETUP SOUND +//////////////////////////////////////////////////////////////////////// + +void SetupSound(void) +{ + voice = AESND_AllocateVoice(aesnd_callback); + AESND_SetVoiceFormat(voice, iDisStereo ? VOICE_MONO16 : VOICE_STEREO16); + AESND_SetVoiceFrequency(voice, freq); + SetVolume(); + AESND_SetVoiceStream(voice, true); + fill_buffer = play_buffer = 0; +} + +//////////////////////////////////////////////////////////////////////// +// REMOVE SOUND +//////////////////////////////////////////////////////////////////////// + +void RemoveSound(void) +{ + AESND_SetVoiceStop(voice, true); +} + +//////////////////////////////////////////////////////////////////////// +// GET BYTES BUFFERED +//////////////////////////////////////////////////////////////////////// + +unsigned long SoundGetBytesBuffered(void) +{ + unsigned long bytes_buffered = 0, i = fill_buffer; + while(1) { + bytes_buffered += buffers[i].len; + + if(i == play_buffer) break; + i = (i + NUM_BUFFERS - 1) % NUM_BUFFERS; + } + + return bytes_buffered; +} + +static void aesnd_callback(AESNDPB* voice, u32 state){ + if(state == VOICE_STATE_STREAM) { + if(play_buffer != fill_buffer) { + AESND_SetVoiceBuffer(voice, + buffers[play_buffer].buffer, buffers[play_buffer].len); + play_buffer = (play_buffer + 1) % NUM_BUFFERS; + } + } +} + +//////////////////////////////////////////////////////////////////////// +// FEED SOUND DATA +//////////////////////////////////////////////////////////////////////// +void SoundFeedStreamData(unsigned char* pSound,long lBytes) +{ + if(!audioEnabled) return; + + buffers[fill_buffer].buffer = pSound; + buffers[fill_buffer].len = lBytes; + fill_buffer = (fill_buffer + 1) % NUM_BUFFERS; + + AESND_SetVoiceStop(voice, false); +} + +void pauseAudio(void){ + AESND_Pause(true); +} + +void resumeAudio(void){ + AESND_Pause(false); +} diff --git a/franspu/franspu.c b/franspu/franspu.c new file mode 100644 index 0000000..c972024 --- /dev/null +++ b/franspu/franspu.c @@ -0,0 +1,589 @@ +#include +#include +#include "franspu.h" +#include "../psxcommon.h" +#include "../decode_xa.h" +#include "../Gamecube/DEBUG.h" + +extern void SoundFeedStreamData(unsigned char* pSound,long lBytes); +extern void InitADSR(void); +extern void SetupSound(void); +extern void RemoveSound(void); + +// Actual SPU Buffer +#define NUM_SPU_BUFFERS 4 +unsigned char spuBuffer[NUM_SPU_BUFFERS][7200] __attribute__((aligned(32))); +unsigned int whichBuffer = 0; + +// psx buffer / addresses +unsigned short regArea[10000]; +unsigned short spuMem[256*1024]; +unsigned char * spuMemC; +unsigned char * pSpuBuffer; +unsigned char * pMixIrq=0; + +void (*irqCallback)(void)=0; // func of main emu, called on spu irq +unsigned char * pSpuIrq=0; +int iSPUIRQWait=0; +int iSpuAsyncWait=0; +unsigned int iVolume = 3; + +typedef struct +{ + char szSPUName[8]; + unsigned long ulFreezeVersion; + unsigned long ulFreezeSize; + unsigned char cSPUPort[0x200]; + //unsigned char cSPURam[0x80000]; + xa_decode_t xaS; +} SPUFreeze_t; + +typedef struct +{ + unsigned short spuIrq; + unsigned long pSpuIrq; + unsigned long dummy0; + unsigned long dummy1; + unsigned long dummy2; + unsigned long dummy3; + + SPUCHAN s_chan[MAXCHAN]; + +} SPUOSSFreeze_t; + +// user settings +int iUseXA=1; +int iSoundMuted=0; +int iDisStereo=0; + +// infos struct for each channel +SPUCHAN s_chan[MAXCHAN+1]; // channel + 1 infos (1 is security for fmod handling) +REVERBInfo rvb; + +unsigned long dwNoiseVal=1; // global noise generator +unsigned short spuCtrl=0; // some vars to store psx reg infos +unsigned short spuStat=0; +unsigned short spuIrq=0; +unsigned long spuAddr=0xffffffff; // address into spu mem +int bEndThread=0; // thread handlers +int bSpuInit=0; +int bSPUIsOpen=0; + +int SSumR[NSSIZE]; +int SSumL[NSSIZE]; +int iFMod[NSSIZE]; +short * pS; + +extern void FRAN_SPU_writeRegister(unsigned long reg, unsigned short val); + +// START SOUND... called by main thread to setup a new sound on a channel +void StartSound(SPUCHAN * pChannel) +{ + pChannel->ADSRX.lVolume=1; // Start ADSR + pChannel->ADSRX.State=0; + pChannel->ADSRX.EnvelopeVol=0; + pChannel->pCurr=pChannel->pStart; // set sample start + pChannel->s_1=0; // init mixing vars + pChannel->s_2=0; + pChannel->iSBPos=28; + pChannel->bNew=0; // init channel flags + pChannel->bStop=0; + pChannel->bOn=1; + pChannel->SB[29]=0; // init our interpolation helpers + pChannel->SB[30]=0; + pChannel->spos=0x10000L; + pChannel->SB[31]=0; // -> no/simple interpolation starts with one 44100 decoding +} + +void VoiceChangeFrequency(SPUCHAN * pChannel) +{ + pChannel->iUsedFreq=pChannel->iActFreq; // -> take it and calc steps + pChannel->sinc=pChannel->iRawPitch<<4; + if(!pChannel->sinc) pChannel->sinc=1; +} + +void FModChangeFrequency(SPUCHAN * pChannel,int ns) +{ + int NP=pChannel->iRawPitch; + NP=((32768L+iFMod[ns])*NP)/32768L; + if(NP>0x3fff) NP=0x3fff; + if(NP<0x1) NP=0x1; + NP=(44100L*NP)/(4096L); // calc frequency + pChannel->iActFreq=NP; + pChannel->iUsedFreq=NP; + pChannel->sinc=(((NP/10)<<16)/4410); + if(!pChannel->sinc) pChannel->sinc=1; + iFMod[ns]=0; +} + +// noise handler... just produces some noise data +int iGetNoiseVal(SPUCHAN * pChannel) +{ + int fa; + if((dwNoiseVal<<=1)&0x80000000L) + { + dwNoiseVal^=0x0040001L; + fa=((dwNoiseVal>>2)&0x7fff); + fa=-fa; + } + else + fa=(dwNoiseVal>>2)&0x7fff; + // mmm... depending on the noise freq we allow bigger/smaller changes to the previous val + fa=pChannel->iOldNoise+((fa-pChannel->iOldNoise)/((0x001f-((spuCtrl&0x3f00)>>9))+1)); + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + pChannel->iOldNoise=fa; + pChannel->SB[29] = fa; // -> store noise val in "current sample" slot + return fa; +} + +void StoreInterpolationVal(SPUCHAN * pChannel,int fa) +{ + if(pChannel->bFMod==2) // fmod freq channel + pChannel->SB[29]=fa; + else + { + if((spuCtrl&0x4000)==0) + fa=0; // muted? + else // else adjust + { + if(fa>32767L) fa=32767L; + if(fa<-32767L) fa=-32767L; + } + pChannel->SB[29]=fa; // no interpolation + } +} + +// here is the main job handler... direct func call (calculates 1 msec of sound) +void SPU_async_1ms(SPUCHAN * pChannel,int *SSumL, int *SSumR, int *iFMod) +{ + int ch; // Channel loop + int ns; // Samples loop + unsigned int i; // Internal loop + int s_1,s_2,fa; + unsigned char * start; + int predict_nr,shift_factor,flags,s; + const int f[5][2] = {{0,0},{60,0},{115,-52},{98,-55},{122,-60}}; + + memset(SSumL,0,NSSIZE*sizeof(int)); + memset(SSumR,0,NSSIZE*sizeof(int)); + + // main channel loop + for(ch=0;chbNew) StartSound(pChannel); // start new sound + if(!pChannel->bOn) continue; // channel not playing? next + if(pChannel->iActFreq!=pChannel->iUsedFreq) // new psx frequency? + VoiceChangeFrequency(pChannel); + + ns=0; + while(nsbFMod==1 && iFMod[ns]) // fmod freq channel + FModChangeFrequency(pChannel,ns); + while(pChannel->spos>=0x10000L) + { + if(pChannel->iSBPos==28) // 28 reached? + { + start=pChannel->pCurr; // set up the current pos + if (start == (unsigned char*)-1) // special "stop" sign + { + pChannel->bOn=0; // -> turn everything off + pChannel->ADSRX.lVolume=0; + pChannel->ADSRX.EnvelopeVol=0; + goto ENDX; // -> and done for this channel + } + pChannel->iSBPos=0; + s_1=pChannel->s_1; + s_2=pChannel->s_2; + predict_nr=(int)*start;start++; + shift_factor=predict_nr&0xf; + predict_nr >>= 4; + flags=(int)*start;start++; + + for (i=0;i<28;start++) + { + s=((((int)*start)&0xf)<<12); + if(s&0x8000) s|=0xffff0000; + fa=(s >> shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + s=((((int)*start) & 0xf0) << 8); + pChannel->SB[i++]=fa; + if(s&0x8000) s|=0xffff0000; + fa=(s>>shift_factor); + fa=fa + ((s_1 * f[predict_nr][0])>>6) + ((s_2 * f[predict_nr][1])>>6); + s_2=s_1;s_1=fa; + pChannel->SB[i++]=fa; + } + + // irq check + if((u32)irqCallback && (spuCtrl&0x40)) // some callback and irq active? + { + if((pSpuIrq > start-16 && // irq address reached? + pSpuIrq <= start) || + ((flags&1) && // special: irq on looping addr, when stop/loop flag is set + (pSpuIrq > pChannel->pLoop-16 && + pSpuIrq <= pChannel->pLoop))) + { + pChannel->iIrqDone=1; // -> debug flag + irqCallback(); // -> call main emu + + } + } + + // flag handler + if((flags&4) && (!pChannel->bIgnoreLoop)) + pChannel->pLoop=start-16; // loop address + if(flags&1) // 1: stop/loop + { + // We play this block out first... + if(flags!=3 || pChannel->pLoop==NULL) // PETE: if we don't check exactly for 3, loop hang ups will happen (DQ4, for example) + start = (unsigned char*)-1; // and checking if pLoop is set avoids crashes, yeah + else + start = pChannel->pLoop; + } + + pChannel->pCurr=start; // store values for next cycle + pChannel->s_1=s_1; + pChannel->s_2=s_2; + } + + + + fa=pChannel->SB[pChannel->iSBPos++]; // get sample data + StoreInterpolationVal(pChannel,fa); // store val for later interpolation + pChannel->spos -= 0x10000L; + } + + if(pChannel->bNoise) + fa=iGetNoiseVal(pChannel); // get noise val + else + fa=pChannel->SB[29]; // get interpolation val + + pChannel->sval=(MixADSR(pChannel)*fa)>>10; // mix adsr + + if(pChannel->bFMod==2) // fmod freq channel + iFMod[ns]=pChannel->sval; // -> store 1T sample data, use that to do fmod on next channel + else // no fmod freq channel + { + SSumL[ns]+=(pChannel->sval*pChannel->iLeftVolume)>>14; + SSumR[ns]+=(pChannel->sval*pChannel->iRightVolume)>>14; + } + + // ok, go on until 1 ms data of this channel is collected + ns++; + pChannel->spos += pChannel->sinc; + } + ENDX: ; + } + + // here we have another 1 ms of sound data + + // Mix XA + if(XAPlay!=XAFeed || XARepeat) MixXA(); + + if(iDisStereo) { + // Mono Mix + for(i=0;i 32767) l = 32767; + + r = *SSumR++; + if(r < -32767) r = -32767; + else if(r > 32767) r = 32767; + + *pS++ = (l + r) / 2; + } + } else { + // Stereo Mix + for(i=0;i 32767) d = 32767; + *pS++ = d; + + d = *SSumR++; + if(d < -32767) d = -32767; + else if(d > 32767) d = 32767; + *pS++ = d; + } + } +} + +void FRAN_SPU_async(unsigned long cycle) +{ + if( iSoundMuted > 0 ) return; + if(SoundGetBytesBuffered() > 8*1024) return; + if(iSpuAsyncWait) + { + iSpuAsyncWait++; + if(iSpuAsyncWait<=64) return; + iSpuAsyncWait=0; + } + int i; + int t=(cycle?32:40); /* cycle 1=NTSC 16 ms, 0=PAL 20 ms; do two frames */for (i=0;ifreq)) + FeedXA(xap); // call main XA feeder +} + +// SPUINIT: this func will be called first by the main emu +long FRAN_SPU_init(void) +{ + spuMemC=(unsigned char *)spuMem; // just small setup + memset((void *)s_chan,0,MAXCHAN*sizeof(SPUCHAN)); + memset((void *)&rvb,0,sizeof(REVERBInfo)); + InitADSR(); + return 0; +} + +// SPUOPEN: called by main emu after init +s32 FRAN_SPU_open(void) +{ + int i; + if(bSPUIsOpen) return 0; // security for some stupid main emus + iUseXA=1; + spuIrq=0; + spuAddr=0xffffffff; + bEndThread=0; + spuMemC=(unsigned char *)spuMem; + pMixIrq=0; + pSpuIrq=0; + iSPUIRQWait=0; + memset((void *)s_chan,0,(MAXCHAN+1)*sizeof(SPUCHAN)); + + SetupSound(); // setup sound (before init!) + + //Setup streams + pSpuBuffer = spuBuffer[whichBuffer]; // alloc mixing buffer + XAStart = (unsigned long *)memalign(32,44100*4); // alloc xa buffer + XAPlay = XAStart; + XAFeed = XAStart; + XAEnd = XAStart + 44100; + for(i=0;i init sustain + s_chan[i].iIrqDone=0; + s_chan[i].pLoop=spuMemC; + s_chan[i].pStart=spuMemC; + s_chan[i].pCurr=spuMemC; + } + + // Setup timers + memset(SSumR,0,NSSIZE*sizeof(int)); // init some mixing buffers + memset(SSumL,0,NSSIZE*sizeof(int)); + memset(iFMod,0,NSSIZE*sizeof(int)); + pS=(short *)pSpuBuffer; // setup soundbuffer pointer + + bSPUIsOpen=1; + return PSE_SPU_ERR_SUCCESS; +} + +// SPUCLOSE: called before shutdown +long FRAN_SPU_close(void) +{ + if(!bSPUIsOpen) return 0; // some security + bSPUIsOpen=0; // no more open + + RemoveSound(); // no more sound handling + + // Remove streams + pSpuBuffer=NULL; + free(XAStart); // free XA buffer + XAStart=0; + + return PSE_SPU_ERR_SUCCESS; +} + +// SPUSHUTDOWN: called by main emu on final exit +long FRAN_SPU_shutdown(void) +{ + return PSE_SPU_ERR_SUCCESS; +} + +void LoadStateV5(SPUFreeze_t * pF) +{ + int i;SPUOSSFreeze_t * pFO; + + pFO=(SPUOSSFreeze_t *)(pF+1); + + spuIrq = pFO->spuIrq; + if(pFO->pSpuIrq) { + pSpuIrq = pFO->pSpuIrq+spuMemC; + } + else { + pSpuIrq=0; + } + + for(i=0;is_chan[i],sizeof(SPUCHAN)); + + s_chan[i].pStart+=(unsigned long)spuMemC; + s_chan[i].pCurr+=(unsigned long)spuMemC; + s_chan[i].pLoop+=(unsigned long)spuMemC; + s_chan[i].iIrqDone=0; + } +} + +//////////////////////////////////////////////////////////////////////// + +void LoadStateUnknown(SPUFreeze_t * pF) +{ + int i; + + for(i=0;iszSPUName,"PBOSS"); + pF->ulFreezeVersion=5; + pF->ulFreezeSize=sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t); + + if(ulFreezeMode==2) { + return 1; // info mode? ok, bye + } + // Save State Mode + memcpy(pF->cSPUPort,regArea,0x200); + + // some xa + if(xapGlobal && XAPlay!=XAFeed) { + pF->xaS=*xapGlobal; + } + else { + memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa + } + + pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff + pFO->spuIrq=spuIrq; + + if(pSpuIrq) { + pFO->pSpuIrq = (unsigned long)pSpuIrq-(unsigned long)spuMemC; + } + + for(i=0;is_chan[i],(void *)&s_chan[i],sizeof(SPUCHAN)); + if(pFO->s_chan[i].pStart) { + pFO->s_chan[i].pStart-=(unsigned long)spuMemC; + } + if(pFO->s_chan[i].pCurr) { + pFO->s_chan[i].pCurr-=(unsigned long)spuMemC; + } + if(pFO->s_chan[i].pLoop) { + pFO->s_chan[i].pLoop-=(unsigned long)spuMemC; + } + } + + return 1; + } + + if(ulFreezeMode!=0) { + return 0; // bad mode? bye + } + + // Load State Mode + //memcpy(spuMem,pF->cSPURam,0x80000); // get ram (done in Misc.c) + memcpy(regArea,pF->cSPUPort,0x200); + + if(pF->xaS.nsamples<=4032) { // start xa again + FRAN_SPU_playADPCMchannel(&pF->xaS); + } + + xapGlobal=0; + + if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5) { + LoadStateV5(pF); + } + else { + LoadStateUnknown(pF); + } + + // repair some globals + for(i=0;i<=62;i+=2) { + FRAN_SPU_writeRegister(H_Reverb+i,regArea[(H_Reverb+i-0xc00)>>1]); + } + FRAN_SPU_writeRegister(H_SPUReverbAddr,regArea[(H_SPUReverbAddr-0xc00)>>1]); + FRAN_SPU_writeRegister(H_SPUrvolL,regArea[(H_SPUrvolL-0xc00)>>1]); + FRAN_SPU_writeRegister(H_SPUrvolR,regArea[(H_SPUrvolR-0xc00)>>1]); + + FRAN_SPU_writeRegister(H_SPUctrl,(unsigned short)(regArea[(H_SPUctrl-0xc00)>>1]|0x4000)); + FRAN_SPU_writeRegister(H_SPUstat,regArea[(H_SPUstat-0xc00)>>1]); + FRAN_SPU_writeRegister(H_CDLeft,regArea[(H_CDLeft-0xc00)>>1]); + FRAN_SPU_writeRegister(H_CDRight,regArea[(H_CDRight-0xc00)>>1]); + + // fix to prevent new interpolations from crashing + for(i=0;i +#include + +#include +#include + +#define RRand(range) (random()%range) +#include +#include + +#define DWORD unsigned long +#define LOWORD(l) ((unsigned short)(l)) +#define HIWORD(l) ((unsigned short)(((unsigned long)(l) >> 16) & 0xFFFF)) + +#define PSE_LT_SPU 4 +#define PSE_SPU_ERR_SUCCESS 0 +#define PSE_SPU_ERR -60 +#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1 +#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2 +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +//////////////////////////////////////////////////////////////////////// +// spu defines +//////////////////////////////////////////////////////////////////////// + +// sound buffer sizes +// 400 ms complete sound buffer +#define SOUNDSIZE 70560 +// 137 ms test buffer... if less than that is buffered, a new upload will happen +#define TESTSIZE 24192 +// num of channels +#define MAXCHAN 24 +// ~ 1 ms of data +#define NSSIZE 45 + +extern int SSumR[NSSIZE]; +extern int SSumL[NSSIZE]; +extern int iFMod[NSSIZE]; + +extern int bSPUIsOpen; + + +// byteswappings + +#define SWAPSPU16(x) (((x)>>8 & 0xff) | ((x)<<8 & 0xff00)) +#define SWAPSPU32(x) (((x)>>24 & 0xfful) | ((x)>>8 & 0xff00ul) | ((x)<<8 & 0xff0000ul) | ((x)<<24 & 0xff000000ul)) + +#define HOST2LE16(x) SWAPSPU16(x) +#define HOST2BE16(x) (x) +#define LE2HOST16(x) SWAPSPU16(x) +#define BE2HOST16(x) (x) + +/////////////////////////////////////////////////////////// +// struct defines +/////////////////////////////////////////////////////////// + +// ADSR INFOS PER CHANNEL +typedef struct +{ + int AttackModeExp; + long AttackTime; + long DecayTime; + long SustainLevel; + int SustainModeExp; + long SustainModeDec; + long SustainTime; + int ReleaseModeExp; + unsigned long ReleaseVal; + long ReleaseTime; + long ReleaseStartTime; + long ReleaseVol; + long lTime; + long lVolume; +} ADSRInfo; + +typedef struct +{ + int State; + int AttackModeExp; + int AttackRate; + int DecayRate; + int SustainLevel; + int SustainModeExp; + int SustainIncrease; + int SustainRate; + int ReleaseModeExp; + int ReleaseRate; + int EnvelopeVol; + long lVolume; + long lDummy1; + long lDummy2; +} ADSRInfoEx; + +/////////////////////////////////////////////////////////// + +// MAIN CHANNEL STRUCT +typedef struct +{ + int bNew; // start flag + + int iSBPos; // mixing stuff + int spos; + int sinc; + int SB[32]; // Pete added another 32 dwords in 1.6 ... prevents overflow issues with gaussian/cubic interpolation (thanx xodnizel!), and can be used for even better interpolations, eh? :) + int sval; + + unsigned char * pStart; // start ptr into sound mem + unsigned char * pCurr; // current pos in sound mem + unsigned char * pLoop; // loop ptr in sound mem + + int bOn; // is channel active (sample playing?) + int bStop; // is channel stopped (sample _can_ still be playing, ADSR Release phase) + int iActFreq; // current psx pitch + int iUsedFreq; // current pc pitch + int iLeftVolume; // left volume + int bIgnoreLoop; // ignore loop bit, if an external loop address is used + int iRightVolume; // right volume + int iRawPitch; // raw pitch (0...3fff) + int iIrqDone; // debug irq done flag + int s_1; // last decoding infos + int s_2; + int bNoise; // noise active flag + int bFMod; // freq mod (0=off, 1=sound channel, 2=freq channel) + int iOldNoise; // old noise val for this channel + ADSRInfo ADSR; // active ADSR settings + ADSRInfoEx ADSRX; // next ADSR settings (will be moved to active on sample start) + +} SPUCHAN; + +/////////////////////////////////////////////////////////// + +typedef struct +{ + int StartAddr; // reverb area start addr in samples + int CurrAddr; // reverb area curr addr in samples + + int VolLeft; + int VolRight; + int iLastRVBLeft; + int iLastRVBRight; + int iRVBLeft; + int iRVBRight; + + + int FB_SRC_A; // (offset) + int FB_SRC_B; // (offset) + int IIR_ALPHA; // (coef.) + int ACC_COEF_A; // (coef.) + int ACC_COEF_B; // (coef.) + int ACC_COEF_C; // (coef.) + int ACC_COEF_D; // (coef.) + int IIR_COEF; // (coef.) + int FB_ALPHA; // (coef.) + int FB_X; // (coef.) + int IIR_DEST_A0; // (offset) + int IIR_DEST_A1; // (offset) + int ACC_SRC_A0; // (offset) + int ACC_SRC_A1; // (offset) + int ACC_SRC_B0; // (offset) + int ACC_SRC_B1; // (offset) + int IIR_SRC_A0; // (offset) + int IIR_SRC_A1; // (offset) + int IIR_DEST_B0; // (offset) + int IIR_DEST_B1; // (offset) + int ACC_SRC_C0; // (offset) + int ACC_SRC_C1; // (offset) + int ACC_SRC_D0; // (offset) + int ACC_SRC_D1; // (offset) + int IIR_SRC_B1; // (offset) + int IIR_SRC_B0; // (offset) + int MIX_DEST_A0; // (offset) + int MIX_DEST_A1; // (offset) + int MIX_DEST_B0; // (offset) + int MIX_DEST_B1; // (offset) + int IN_COEF_L; // (coef.) + int IN_COEF_R; // (coef.) +} REVERBInfo; + +/////////////////////////////////////////////////////////// +// SPU.C globals +/////////////////////////////////////////////////////////// + +extern unsigned short regArea[]; +extern unsigned short spuMem[]; +extern unsigned char * spuMemC; +extern unsigned char * pSpuBuffer; +extern unsigned char * pSpuIrq; + +// user settings + +extern int iUseXA; +extern int iSoundMuted; +extern int iDisStereo; + +// MISC + +extern SPUCHAN s_chan[]; +extern REVERBInfo rvb; + +extern unsigned long dwNoiseVal; +extern unsigned short spuCtrl; +extern unsigned short spuStat; +extern unsigned short spuIrq; +extern unsigned long spuAddr; +extern int bEndThread; +extern int bThreadEnded; +extern int bSpuInit; + +extern int SSumR[]; +extern int SSumL[]; +extern short * pS; + +/////////////////////////////////////////////////////////// +// XA.C globals +/////////////////////////////////////////////////////////// +extern xa_decode_t * xapGlobal; +extern unsigned long * XAFeed; +extern unsigned long * XAPlay; +extern unsigned long * XAStart; +extern unsigned long * XAEnd; +extern unsigned long XARepeat; +extern int iLeftXAVol; +extern int iRightXAVol; + +/////////////////////////////////////////////////////////// +// REVERB.C globals +/////////////////////////////////////////////////////////// + +// Register Defines +#define H_SPUReverbAddr 0x0da2 +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUmvolL 0x0d80 +#define H_SPUmvolR 0x0d82 +#define H_SPUrvolL 0x0d84 +#define H_SPUrvolR 0x0d86 +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e +#define H_FMod1 0x0d90 +#define H_FMod2 0x0d92 +#define H_Noise1 0x0d94 +#define H_Noise2 0x0d96 +#define H_RVBon1 0x0d98 +#define H_RVBon2 0x0d9a +#define H_SPUMute1 0x0d9c +#define H_SPUMute2 0x0d9e +#define H_CDLeft 0x0db0 +#define H_CDRight 0x0db2 +#define H_ExtLeft 0x0db4 +#define H_ExtRight 0x0db6 +#define H_Reverb 0x0dc0 +#define H_SPUPitch0 0x0c04 +#define H_SPUPitch1 0x0c14 +#define H_SPUPitch2 0x0c24 +#define H_SPUPitch3 0x0c34 +#define H_SPUPitch4 0x0c44 +#define H_SPUPitch5 0x0c54 +#define H_SPUPitch6 0x0c64 +#define H_SPUPitch7 0x0c74 +#define H_SPUPitch8 0x0c84 +#define H_SPUPitch9 0x0c94 +#define H_SPUPitch10 0x0ca4 +#define H_SPUPitch11 0x0cb4 +#define H_SPUPitch12 0x0cc4 +#define H_SPUPitch13 0x0cd4 +#define H_SPUPitch14 0x0ce4 +#define H_SPUPitch15 0x0cf4 +#define H_SPUPitch16 0x0d04 +#define H_SPUPitch17 0x0d14 +#define H_SPUPitch18 0x0d24 +#define H_SPUPitch19 0x0d34 +#define H_SPUPitch20 0x0d44 +#define H_SPUPitch21 0x0d54 +#define H_SPUPitch22 0x0d64 +#define H_SPUPitch23 0x0d74 + +#define H_SPUStartAdr0 0x0c06 +#define H_SPUStartAdr1 0x0c16 +#define H_SPUStartAdr2 0x0c26 +#define H_SPUStartAdr3 0x0c36 +#define H_SPUStartAdr4 0x0c46 +#define H_SPUStartAdr5 0x0c56 +#define H_SPUStartAdr6 0x0c66 +#define H_SPUStartAdr7 0x0c76 +#define H_SPUStartAdr8 0x0c86 +#define H_SPUStartAdr9 0x0c96 +#define H_SPUStartAdr10 0x0ca6 +#define H_SPUStartAdr11 0x0cb6 +#define H_SPUStartAdr12 0x0cc6 +#define H_SPUStartAdr13 0x0cd6 +#define H_SPUStartAdr14 0x0ce6 +#define H_SPUStartAdr15 0x0cf6 +#define H_SPUStartAdr16 0x0d06 +#define H_SPUStartAdr17 0x0d16 +#define H_SPUStartAdr18 0x0d26 +#define H_SPUStartAdr19 0x0d36 +#define H_SPUStartAdr20 0x0d46 +#define H_SPUStartAdr21 0x0d56 +#define H_SPUStartAdr22 0x0d66 +#define H_SPUStartAdr23 0x0d76 + +#define H_SPULoopAdr0 0x0c0e +#define H_SPULoopAdr1 0x0c1e +#define H_SPULoopAdr2 0x0c2e +#define H_SPULoopAdr3 0x0c3e +#define H_SPULoopAdr4 0x0c4e +#define H_SPULoopAdr5 0x0c5e +#define H_SPULoopAdr6 0x0c6e +#define H_SPULoopAdr7 0x0c7e +#define H_SPULoopAdr8 0x0c8e +#define H_SPULoopAdr9 0x0c9e +#define H_SPULoopAdr10 0x0cae +#define H_SPULoopAdr11 0x0cbe +#define H_SPULoopAdr12 0x0cce +#define H_SPULoopAdr13 0x0cde +#define H_SPULoopAdr14 0x0cee +#define H_SPULoopAdr15 0x0cfe +#define H_SPULoopAdr16 0x0d0e +#define H_SPULoopAdr17 0x0d1e +#define H_SPULoopAdr18 0x0d2e +#define H_SPULoopAdr19 0x0d3e +#define H_SPULoopAdr20 0x0d4e +#define H_SPULoopAdr21 0x0d5e +#define H_SPULoopAdr22 0x0d6e +#define H_SPULoopAdr23 0x0d7e + +#define H_SPU_ADSRLevel0 0x0c08 +#define H_SPU_ADSRLevel1 0x0c18 +#define H_SPU_ADSRLevel2 0x0c28 +#define H_SPU_ADSRLevel3 0x0c38 +#define H_SPU_ADSRLevel4 0x0c48 +#define H_SPU_ADSRLevel5 0x0c58 +#define H_SPU_ADSRLevel6 0x0c68 +#define H_SPU_ADSRLevel7 0x0c78 +#define H_SPU_ADSRLevel8 0x0c88 +#define H_SPU_ADSRLevel9 0x0c98 +#define H_SPU_ADSRLevel10 0x0ca8 +#define H_SPU_ADSRLevel11 0x0cb8 +#define H_SPU_ADSRLevel12 0x0cc8 +#define H_SPU_ADSRLevel13 0x0cd8 +#define H_SPU_ADSRLevel14 0x0ce8 +#define H_SPU_ADSRLevel15 0x0cf8 +#define H_SPU_ADSRLevel16 0x0d08 +#define H_SPU_ADSRLevel17 0x0d18 +#define H_SPU_ADSRLevel18 0x0d28 +#define H_SPU_ADSRLevel19 0x0d38 +#define H_SPU_ADSRLevel20 0x0d48 +#define H_SPU_ADSRLevel21 0x0d58 +#define H_SPU_ADSRLevel22 0x0d68 +#define H_SPU_ADSRLevel23 0x0d78 + +extern int MixADSR(SPUCHAN *ch); +extern unsigned long SoundGetBytesBuffered(void); +extern void FeedXA(xa_decode_t *xap); +extern void MixXA(void); + +#endif diff --git a/franspu/spu_adsr.c b/franspu/spu_adsr.c new file mode 100644 index 0000000..335b172 --- /dev/null +++ b/franspu/spu_adsr.c @@ -0,0 +1,136 @@ + +#include "franspu.h" + +static unsigned long int RateTable[160]; + +/* INIT ADSR */ +void InitADSR(void) +{ + unsigned long r=3,rs=1,rd=0; + int i; + memset(RateTable,0,sizeof(unsigned long)*160); // build the rate table according to Neill's rules (see at bottom of file) + + for(i=32;i<160;i++) // we start at pos 32 with the real values... everything before is 0 + { + if(r<0x3FFFFFFF) + { + r+=rs; + rd++; + if(rd==5) { + rd=1; + rs*=2; + } + } + if(r>0x3FFFFFFF) + r=0x3FFFFFFF; + RateTable[i]=r; + } +} + +static const unsigned long int TableDisp[] = { + -0x18+0+32,-0x18+4+32,-0x18+6+32,-0x18+8+32, // release/decay + -0x18+9+32,-0x18+10+32,-0x18+11+32,-0x18+12+32, + + -0x1B+0+32,-0x1B+4+32,-0x1B+6+32,-0x1B+8+32, // sustain + -0x1B+9+32,-0x1B+10+32,-0x1B+11+32,-0x1B+12+32, +}; + + +/* MIX ADSR */ +int MixADSR(SPUCHAN *ch) +{ + unsigned long int disp; + signed long int EnvelopeVol = ch->ADSRX.EnvelopeVol; + + if(ch->bStop) // should be stopped: + { // do release + if(ch->ADSRX.ReleaseModeExp) + disp = TableDisp[(EnvelopeVol>>28)&0x7]; + else + disp=-0x0C+32; + + EnvelopeVol-=RateTable[ch->ADSRX.ReleaseRate + disp]; + + if(EnvelopeVol<0) + { + EnvelopeVol=0; + ch->bOn=0; + } + + ch->ADSRX.EnvelopeVol=EnvelopeVol; + ch->ADSRX.lVolume=(EnvelopeVol>>=21); + return EnvelopeVol; + } + else // not stopped yet? + { + if(ch->ADSRX.State==0) // -> attack + { + disp = -0x10+32; + if(ch->ADSRX.AttackModeExp) + { + if(EnvelopeVol>=0x60000000) + disp = -0x18+32; + } + EnvelopeVol+=RateTable[ch->ADSRX.AttackRate+disp]; + + if(EnvelopeVol<0) + { + EnvelopeVol=0x7FFFFFFF; + ch->ADSRX.State=1; + } + + ch->ADSRX.EnvelopeVol=EnvelopeVol; + ch->ADSRX.lVolume=(EnvelopeVol>>=21); + return EnvelopeVol; + } + + if(ch->ADSRX.State==1) // -> decay + { + disp = TableDisp[(EnvelopeVol>>28)&0x7]; + EnvelopeVol-=RateTable[ch->ADSRX.DecayRate+disp]; + + if(EnvelopeVol<0) + EnvelopeVol=0; + if(EnvelopeVol <= ch->ADSRX.SustainLevel) + ch->ADSRX.State=2; + + ch->ADSRX.EnvelopeVol=EnvelopeVol; + ch->ADSRX.lVolume=(EnvelopeVol>>=21); + return EnvelopeVol; + } + + if(ch->ADSRX.State==2) // -> sustain + { + if(ch->ADSRX.SustainIncrease) + { + disp = -0x10+32; + if(ch->ADSRX.SustainModeExp) + { + if(EnvelopeVol>=0x60000000) + disp = -0x18+32; + } + EnvelopeVol+=RateTable[ch->ADSRX.SustainRate+disp]; + + if(EnvelopeVol<0) + EnvelopeVol=0x7FFFFFFF; + } + else + { + if(ch->ADSRX.SustainModeExp) + disp = TableDisp[((EnvelopeVol>>28)&0x7)+8]; + else + disp=-0x0F+32; + + EnvelopeVol-=RateTable[ch->ADSRX.SustainRate+disp]; + + if(EnvelopeVol<0) + EnvelopeVol=0; + } + + ch->ADSRX.EnvelopeVol=EnvelopeVol; + ch->ADSRX.lVolume=(EnvelopeVol>>=21); + return EnvelopeVol; + } + } + return 0; +} diff --git a/franspu/spu_dma.c b/franspu/spu_dma.c new file mode 100644 index 0000000..800ef79 --- /dev/null +++ b/franspu/spu_dma.c @@ -0,0 +1,46 @@ +#include "franspu.h" + +// READ DMA (one value) +unsigned short FRAN_SPU_readDMA(void) +{ + unsigned short s=LE2HOST16(spuMem[spuAddr>>1]); + spuAddr+=2; + if(spuAddr>=0x80000) spuAddr=0; + return s; +} + +// READ DMA (many values) +void FRAN_SPU_readDMAMem(unsigned short * pusPSXMem,int iSize) +{ + if (spuAddr+(iSize<<1)>=0x80000) + { + memcpy(pusPSXMem,&spuMem[spuAddr>>1],0x7ffff-spuAddr+1); + memcpy(pusPSXMem+(0x7ffff-spuAddr+1),spuMem,(iSize<<1)-(0x7ffff-spuAddr+1)); + spuAddr=(iSize<<1)-(0x7ffff-spuAddr+1); + } else { + memcpy(pusPSXMem,&spuMem[spuAddr>>1],iSize<<1); + spuAddr+=(iSize<<1); + } +} + +// WRITE DMA (one value) +void FRAN_SPU_writeDMA(unsigned short val) +{ + spuMem[spuAddr>>1] = HOST2LE16(val); + spuAddr+=2; + if(spuAddr>=0x80000) spuAddr=0; +} + +// WRITE DMA (many values) +void FRAN_SPU_writeDMAMem(unsigned short * pusPSXMem,int iSize) +{ + if (spuAddr+(iSize<<1)>0x7ffff) + { + memcpy(&spuMem[spuAddr>>1],pusPSXMem,0x7ffff-spuAddr+1); + memcpy(spuMem,pusPSXMem+(0x7ffff-spuAddr+1),(iSize<<1)-(0x7ffff-spuAddr+1)); + spuAddr=(iSize<<1)-(0x7ffff-spuAddr+1); + } else { + memcpy(&spuMem[spuAddr>>1],pusPSXMem,iSize<<1); + spuAddr+=(iSize<<1); + } +} diff --git a/franspu/spu_registers.c b/franspu/spu_registers.c new file mode 100644 index 0000000..d59c72b --- /dev/null +++ b/franspu/spu_registers.c @@ -0,0 +1,299 @@ +#include "franspu.h" + +// we have a timebase of 1.020408f ms, not 1 ms... so adjust adsr defines +#define ATTACK_MS 494L +#define DECAYHALF_MS 286L +#define DECAY_MS 572L +#define SUSTAIN_MS 441L +#define RELEASE_MS 437L + +// SOUND ON register write +void SoundOn(int start,int end,unsigned short val) // SOUND ON PSX COMAND +{ + int ch; + for(ch=start;ch>=1) // loop channels + { + if((val&1) && s_chan[ch].pStart) // mmm... start has to be set before key on !?! + { + s_chan[ch].bIgnoreLoop=0; + s_chan[ch].bNew=1; + } + } +} + +// SOUND OFF register write +void SoundOff(int start,int end,unsigned short val) // SOUND OFF PSX COMMAND +{ + int ch; + for(ch=start;ch>=1) // loop channels + { + if(val&1) // && s_chan[i].bOn) mmm... + s_chan[ch].bStop=1; + } +} + +// FMOD register write +void FModOn(int start,int end,unsigned short val) // FMOD ON PSX COMMAND +{ + int ch; + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> fmod on/off + { + if(ch>0) + { + s_chan[ch].bFMod=1; // --> sound channel + s_chan[ch-1].bFMod=2; // --> freq channel + } + } + else + s_chan[ch].bFMod=0; // --> turn off fmod + } +} + +// NOISE register write +void NoiseOn(int start,int end,unsigned short val) // NOISE ON PSX COMMAND +{ + int ch; + for(ch=start;ch>=1) // loop channels + { + if(val&1) // -> noise on/off + s_chan[ch].bNoise=1; + else + s_chan[ch].bNoise=0; + } +} + +// LEFT VOLUME register write +// please note: sweep and phase invert are wrong... but I've never seen +// them used +void SetVolumeL(unsigned char ch,short vol) // LEFT VOLUME +{ + if(vol&0x8000) // sweep? + { + short sInc=1; // -> sweep up? + if(vol&0x2000) sInc=-1; // -> or down? + if(vol&0x1000) vol^=0xffff; // -> mmm... phase inverted? have to investigate this + vol=((vol&0x7f)+1)/2; // -> sweep: 0..127 -> 0..64 + vol+=vol/(2*sInc); // -> HACK: we don't sweep right now, so we just raise/lower the volume by the half! + vol*=128; + } + else // no sweep: + { + if(vol&0x4000) // -> mmm... phase inverted? have to investigate this + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + s_chan[ch].iLeftVolume=vol; // store volume +} + +// RIGHT VOLUME register write +void SetVolumeR(unsigned char ch,short vol) // RIGHT VOLUME +{ + if(vol&0x8000) // comments... see above :) + { + short sInc=1; + if(vol&0x2000) sInc=-1; + if(vol&0x1000) vol^=0xffff; + vol=((vol&0x7f)+1)/2; + vol+=vol/(2*sInc); + vol*=128; + } + else + { + if(vol&0x4000) + vol=0x3fff-(vol&0x3fff); + } + + vol&=0x3fff; + s_chan[ch].iRightVolume=vol; +} + +// PITCH register write +void SetPitch(int ch,unsigned short val) // SET PITCH +{ + int NP; + if(val>0x3fff) + NP=0x3fff; // get pitch val + else + NP=val; + + s_chan[ch].iRawPitch=NP; + + NP=(44100L*NP)/4096L; // calc frequency + if(NP<1) NP=1; // some security + s_chan[ch].iActFreq=NP; // store frequency +} + +// WRITE REGISTERS: called by main emu +void FRAN_SPU_writeRegister(unsigned long reg, unsigned short val) +{ + const unsigned long r=reg&0xfff; + + regArea[(r-0xc00)>>1] = val; + + if(r>=0x0c00 && r<0x0d80) // some channel info? + { + int ch=(r>>4)-0xc0; // calc channel + switch(r&0x0f) + { + case 0: + SetVolumeL((unsigned char)ch,val); // l volume + break; + case 2: + SetVolumeR((unsigned char)ch,val); // r volume + break; + case 4: + SetPitch(ch,val); // pitch + break; + case 6: + s_chan[ch].pStart=spuMemC+((unsigned long) val<<3); // start + break; + case 8: // level with pre-calcs + { + const unsigned long lval=val; + s_chan[ch].ADSRX.AttackModeExp=(lval&0x8000)?1:0; + s_chan[ch].ADSRX.AttackRate = ((lval>>8) & 0x007f)^0x7f; + s_chan[ch].ADSRX.DecayRate = 4*(((lval>>4) & 0x000f)^0x1f); + s_chan[ch].ADSRX.SustainLevel = (lval & 0x000f) << 27; + break; + } + case 10: // adsr times with pre-calcs + { + const unsigned long lval=val; + s_chan[ch].ADSRX.SustainModeExp = (lval&0x8000)?1:0; + s_chan[ch].ADSRX.SustainIncrease= (lval&0x4000)?0:1; + s_chan[ch].ADSRX.SustainRate = ((lval>>6) & 0x007f)^0x7f; + s_chan[ch].ADSRX.ReleaseModeExp = (lval&0x0020)?1:0; + s_chan[ch].ADSRX.ReleaseRate = 4*((lval & 0x001f)^0x1f); + break; + } + case 12: // adsr volume... mmm have to investigate this + break; + case 14: // loop? + s_chan[ch].pLoop=spuMemC+((unsigned long) val<<3); + s_chan[ch].bIgnoreLoop=1; + break; + } + return; + } + + switch(r) + { + case H_SPUaddr : spuAddr = (unsigned long) val<<3; break; + case H_SPUdata: + spuMem[spuAddr>>1] = HOST2LE16(val); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + break; + case H_SPUctrl : spuCtrl=val; break; + case H_SPUstat : spuStat=val & 0xf800; break; + case H_SPUReverbAddr: + if(val==0xFFFF || val<=0x200) { + rvb.StartAddr=rvb.CurrAddr=0; + } else { + const long iv=(unsigned long)val<<2; + if(rvb.StartAddr!=iv) + { + rvb.StartAddr=(unsigned long)val<<2; + rvb.CurrAddr=rvb.StartAddr; + } + } + break; + case H_SPUirqAddr : spuIrq = val; pSpuIrq=spuMemC+((unsigned long) val<<3); break; + case H_SPUrvolL : rvb.VolLeft=val; break; + case H_SPUrvolR : rvb.VolRight=val; break; + case H_SPUon1 : SoundOn(0,16,val); break; + case H_SPUon2 : SoundOn(16,24,val); break; + case H_SPUoff1 : SoundOff(0,16,val); break; + case H_SPUoff2 : SoundOff(16,24,val); break; + case H_CDLeft : iLeftXAVol=val & 0x7fff; break; + case H_CDRight : iRightXAVol=val & 0x7fff; break; + case H_FMod1 : FModOn(0,16,val); break; + case H_FMod2 : FModOn(16,24,val); break; + case H_Noise1 : NoiseOn(0,16,val); break; + case H_Noise2 : NoiseOn(16,24,val); break; + case H_RVBon1 : break; + case H_RVBon2 : break; + case H_Reverb+0 : rvb.FB_SRC_A=val; break; + case H_Reverb+2 : rvb.FB_SRC_B=(short)val; break; + case H_Reverb+4 : rvb.IIR_ALPHA=(short)val; break; + case H_Reverb+6 : rvb.ACC_COEF_A=(short)val; break; + case H_Reverb+8 : rvb.ACC_COEF_B=(short)val; break; + case H_Reverb+10 : rvb.ACC_COEF_C=(short)val; break; + case H_Reverb+12 : rvb.ACC_COEF_D=(short)val; break; + case H_Reverb+14 : rvb.IIR_COEF=(short)val; break; + case H_Reverb+16 : rvb.FB_ALPHA=(short)val; break; + case H_Reverb+18 : rvb.FB_X=(short)val; break; + case H_Reverb+20 : rvb.IIR_DEST_A0=(short)val; break; + case H_Reverb+22 : rvb.IIR_DEST_A1=(short)val; break; + case H_Reverb+24 : rvb.ACC_SRC_A0=(short)val; break; + case H_Reverb+26 : rvb.ACC_SRC_A1=(short)val; break; + case H_Reverb+28 : rvb.ACC_SRC_B0=(short)val; break; + case H_Reverb+30 : rvb.ACC_SRC_B1=(short)val; break; + case H_Reverb+32 : rvb.IIR_SRC_A0=(short)val; break; + case H_Reverb+34 : rvb.IIR_SRC_A1=(short)val; break; + case H_Reverb+36 : rvb.IIR_DEST_B0=(short)val; break; + case H_Reverb+38 : rvb.IIR_DEST_B1=(short)val; break; + case H_Reverb+40 : rvb.ACC_SRC_C0=(short)val; break; + case H_Reverb+42 : rvb.ACC_SRC_C1=(short)val; break; + case H_Reverb+44 : rvb.ACC_SRC_D0=(short)val; break; + case H_Reverb+46 : rvb.ACC_SRC_D1=(short)val; break; + case H_Reverb+48 : rvb.IIR_SRC_B1=(short)val; break; + case H_Reverb+50 : rvb.IIR_SRC_B0=(short)val; break; + case H_Reverb+52 : rvb.MIX_DEST_A0=(short)val; break; + case H_Reverb+54 : rvb.MIX_DEST_A1=(short)val; break; + case H_Reverb+56 : rvb.MIX_DEST_B0=(short)val; break; + case H_Reverb+58 : rvb.MIX_DEST_B1=(short)val; break; + case H_Reverb+60 : rvb.IN_COEF_L=(short)val; break; + case H_Reverb+62 : rvb.IN_COEF_R=(short)val; break; + } +} + +// READ REGISTER: called by main emu +unsigned short FRAN_SPU_readRegister(unsigned long reg) +{ + const unsigned long r=reg&0xfff; + + if(r>=0x0c00 && r<0x0d80) + { + switch(r&0x0f) + { + case 12: // get adsr vol + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].bNew) return 1; // we are started, but not processed? return 1 + if(s_chan[ch].ADSRX.lVolume && // same here... we haven't decoded one sample yet, so no envelope yet. return 1 as well + !s_chan[ch].ADSRX.EnvelopeVol) + return 1; + return (unsigned short)(s_chan[ch].ADSRX.EnvelopeVol>>16); + } + + case 14: // get loop address + { + const int ch=(r>>4)-0xc0; + if(s_chan[ch].pLoop==NULL) return 0; + return (unsigned short)((s_chan[ch].pLoop-spuMemC)>>3); + } + } + } + + switch(r) + { + case H_SPUctrl: return spuCtrl; + case H_SPUstat: return spuStat; + case H_SPUaddr: return (unsigned short)(spuAddr>>3); + case H_SPUdata: + { + unsigned short s=LE2HOST16(spuMem[spuAddr>>1]); + spuAddr+=2; + if(spuAddr>0x7ffff) spuAddr=0; + return s; + } + case H_SPUirqAddr: return spuIrq; + } + + return regArea[(r-0xc00)>>1]; +} + diff --git a/franspu/spu_xa.c b/franspu/spu_xa.c new file mode 100644 index 0000000..f78ee68 --- /dev/null +++ b/franspu/spu_xa.c @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////// +// XA GLOBALS +//////////////////////////////////////////////////////////////////////// + +#include "franspu.h" + +xa_decode_t * xapGlobal=0; + +unsigned long * XAFeed = NULL; +unsigned long * XAPlay = NULL; +unsigned long * XAStart = NULL; +unsigned long * XAEnd = NULL; +unsigned long XARepeat = 0; + +int iLeftXAVol = 32767; +int iRightXAVol = 32767; + +// MIX XA +void MixXA(void) +{ + int i; + unsigned long XALastVal = 0; + int leftvol =iLeftXAVol; + int rightvol=iRightXAVol; + int *ssuml=SSumL; + int *ssumr=SSumR; + + for(i=0;i>16)&0xffff)) * rightvol)/32768; + } + + if(XAPlay==XAFeed && XARepeat) + { + XARepeat--; + for(;i>16)&0xffff)) * rightvol)/32768; + } + } +} + +// FEED XA +void FeedXA(xa_decode_t *xap) +{ + int sinc,spos,i,iSize; + + if(!bSPUIsOpen) return; + + xapGlobal = xap; // store info for save states + XARepeat = 100; // set up repeat + + iSize=((44100*xap->nsamples)/xap->freq); // get size + if(!iSize) return; // none? bye + + if(XAFeednsamples << 16) / iSize; // calc freq by num / size + + if(xap->stereo) + { + unsigned long * pS=(unsigned long *)xap->pcm; + unsigned long l=0; + + for(i=0;i=0x10000L) + { + l = *pS++; + spos -= 0x10000L; + } + + *XAFeed++=l; + + if(XAFeed==XAEnd) + XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) + XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } + else + { + unsigned short * pS=(unsigned short *)xap->pcm; + short s=0; + + for(i=0;i=0x10000L) + { + s = *pS++; + spos -= 0x10000L; + } + unsigned long l=s; + + *XAFeed++=(l|(l<<16)); + + if(XAFeed==XAEnd) + XAFeed=XAStart; + if(XAFeed==XAPlay) + { + if(XAPlay!=XAStart) + XAFeed=XAPlay-1; + break; + } + + spos += sinc; + } + } +} diff --git a/gte.c b/gte.c new file mode 100644 index 0000000..5a7c715 --- /dev/null +++ b/gte.c @@ -0,0 +1,2387 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* GTE functions. +*/ + +#include "gte.h" + +#ifdef GTE_DUMP +#define G_OP(name,delay) fprintf(gteLog, "* : %08X : %02d : %s\n", psxRegs.code, delay, name); +#define G_SD(reg) fprintf(gteLog, "+D%02d : %08X\n", reg, psxRegs.CP2D.r[reg]); +#define G_SC(reg) fprintf(gteLog, "+C%02d : %08X\n", reg, psxRegs.CP2C.r[reg]); +#define G_GD(reg) fprintf(gteLog, "-D%02d : %08X\n", reg, psxRegs.CP2D.r[reg]); +#define G_GC(reg) fprintf(gteLog, "-C%02d : %08X\n", reg, psxRegs.CP2C.r[reg]); +#else +#define G_OP(name,delay) +#define G_SD(reg) +#define G_SC(reg) +#define G_GD(reg) +#define G_GC(reg) +#endif + +#define SUM_FLAG if(gteFLAG & 0x7F87E000) gteFLAG |= 0x80000000; + +#if defined(HW_RVL) || defined(HW_DOL) || defined(BIG_ENDIAN) +#define SEL16(n) ((n)^1) +#define SEL8(n) ((n)^3) +#else +#define SEL16(n) (n) +#define SEL8(n) (n) +#endif + +#define gteVX0 ((s16*)psxRegs.CP2D.r)[SEL16(0)] +#define gteVY0 ((s16*)psxRegs.CP2D.r)[SEL16(1)] +#define gteVZ0 ((s16*)psxRegs.CP2D.r)[SEL16(2)] +#define gteVX1 ((s16*)psxRegs.CP2D.r)[SEL16(4)] +#define gteVY1 ((s16*)psxRegs.CP2D.r)[SEL16(5)] +#define gteVZ1 ((s16*)psxRegs.CP2D.r)[SEL16(6)] +#define gteVX2 ((s16*)psxRegs.CP2D.r)[SEL16(8)] +#define gteVY2 ((s16*)psxRegs.CP2D.r)[SEL16(9)] +#define gteVZ2 ((s16*)psxRegs.CP2D.r)[SEL16(10)] +#define gteRGB psxRegs.CP2D.r[6] +#define gteOTZ ((s16*)psxRegs.CP2D.r)[SEL16(7*2)] +#define gteIR0 ((s32*)psxRegs.CP2D.r)[8] +#define gteIR1 ((s32*)psxRegs.CP2D.r)[9] +#define gteIR2 ((s32*)psxRegs.CP2D.r)[10] +#define gteIR3 ((s32*)psxRegs.CP2D.r)[11] +#define gteSXY0 ((s32*)psxRegs.CP2D.r)[12] +#define gteSXY1 ((s32*)psxRegs.CP2D.r)[13] +#define gteSXY2 ((s32*)psxRegs.CP2D.r)[14] +#define gteSXYP ((s32*)psxRegs.CP2D.r)[15] +#define gteSX0 ((s16*)psxRegs.CP2D.r)[SEL16(12*2)] +#define gteSY0 ((s16*)psxRegs.CP2D.r)[SEL16(12*2+1)] +#define gteSX1 ((s16*)psxRegs.CP2D.r)[SEL16(13*2)] +#define gteSY1 ((s16*)psxRegs.CP2D.r)[SEL16(13*2+1)] +#define gteSX2 ((s16*)psxRegs.CP2D.r)[SEL16(14*2)] +#define gteSY2 ((s16*)psxRegs.CP2D.r)[SEL16(14*2+1)] +#define gteSXP ((s16*)psxRegs.CP2D.r)[SEL16(15*2)] +#define gteSYP ((s16*)psxRegs.CP2D.r)[SEL16(15*2+1)] +#define gteSZx ((u16*)psxRegs.CP2D.r)[SEL16(16*2)] +#define gteSZ0 ((u16*)psxRegs.CP2D.r)[SEL16(17*2)] +#define gteSZ1 ((u16*)psxRegs.CP2D.r)[SEL16(18*2)] +#define gteSZ2 ((u16*)psxRegs.CP2D.r)[SEL16(19*2)] +#define gteRGB0 psxRegs.CP2D.r[20] +#define gteRGB1 psxRegs.CP2D.r[21] +#define gteRGB2 psxRegs.CP2D.r[22] +#define gteMAC0 psxRegs.CP2D.r[24] +#define gteMAC1 ((s32*)psxRegs.CP2D.r)[25] +#define gteMAC2 ((s32*)psxRegs.CP2D.r)[26] +#define gteMAC3 ((s32*)psxRegs.CP2D.r)[27] +#define gteIRGB psxRegs.CP2D.r[28] +#define gteORGB psxRegs.CP2D.r[29] +#define gteLZCS psxRegs.CP2D.r[30] +#define gteLZCR psxRegs.CP2D.r[31] + +#define gteR ((u8 *)psxRegs.CP2D.r)[SEL8(6*4)] +#define gteG ((u8 *)psxRegs.CP2D.r)[SEL8(6*4+1)] +#define gteB ((u8 *)psxRegs.CP2D.r)[SEL8(6*4+2)] +#define gteCODE ((u8 *)psxRegs.CP2D.r)[SEL8(6*4+3)] +#define gteC gteCODE + +#define gteR0 ((u8 *)psxRegs.CP2D.r)[SEL8(20*4)] +#define gteG0 ((u8 *)psxRegs.CP2D.r)[SEL8(20*4+1)] +#define gteB0 ((u8 *)psxRegs.CP2D.r)[SEL8(20*4+2)] +#define gteCODE0 ((u8 *)psxRegs.CP2D.r)[SEL8(20*4+3)] +#define gteC0 gteCODE0 + +#define gteR1 ((u8 *)psxRegs.CP2D.r)[SEL8(21*4)] +#define gteG1 ((u8 *)psxRegs.CP2D.r)[SEL8(21*4+1)] +#define gteB1 ((u8 *)psxRegs.CP2D.r)[SEL8(21*4+2)] +#define gteCODE1 ((u8 *)psxRegs.CP2D.r)[SEL8(21*4+3)] +#define gteC1 gteCODE1 + +#define gteR2 ((u8 *)psxRegs.CP2D.r)[SEL8(22*4)] +#define gteG2 ((u8 *)psxRegs.CP2D.r)[SEL8(22*4+1)] +#define gteB2 ((u8 *)psxRegs.CP2D.r)[SEL8(22*4+2)] +#define gteCODE2 ((u8 *)psxRegs.CP2D.r)[SEL8(22*4+3)] +#define gteC2 gteCODE2 + + + +#define gteR11 ((s16*)psxRegs.CP2C.r)[SEL16(0)] +#define gteR12 ((s16*)psxRegs.CP2C.r)[SEL16(1)] +#define gteR13 ((s16*)psxRegs.CP2C.r)[SEL16(2)] +#define gteR21 ((s16*)psxRegs.CP2C.r)[SEL16(3)] +#define gteR22 ((s16*)psxRegs.CP2C.r)[SEL16(4)] +#define gteR23 ((s16*)psxRegs.CP2C.r)[SEL16(5)] +#define gteR31 ((s16*)psxRegs.CP2C.r)[SEL16(6)] +#define gteR32 ((s16*)psxRegs.CP2C.r)[SEL16(7)] +#define gteR33 ((s16*)psxRegs.CP2C.r)[SEL16(8)] +#define gteTRX ((s32*)psxRegs.CP2C.r)[5] +#define gteTRY ((s32*)psxRegs.CP2C.r)[6] +#define gteTRZ ((s32*)psxRegs.CP2C.r)[7] +#define gteL11 ((s16*)psxRegs.CP2C.r)[SEL16(16)] +#define gteL12 ((s16*)psxRegs.CP2C.r)[SEL16(17)] +#define gteL13 ((s16*)psxRegs.CP2C.r)[SEL16(18)] +#define gteL21 ((s16*)psxRegs.CP2C.r)[SEL16(19)] +#define gteL22 ((s16*)psxRegs.CP2C.r)[SEL16(20)] +#define gteL23 ((s16*)psxRegs.CP2C.r)[SEL16(21)] +#define gteL31 ((s16*)psxRegs.CP2C.r)[SEL16(22)] +#define gteL32 ((s16*)psxRegs.CP2C.r)[SEL16(23)] +#define gteL33 ((s16*)psxRegs.CP2C.r)[SEL16(24)] +#define gteRBK ((s32*)psxRegs.CP2C.r)[13] +#define gteGBK ((s32*)psxRegs.CP2C.r)[14] +#define gteBBK ((s32*)psxRegs.CP2C.r)[15] +#define gteLR1 ((s16*)psxRegs.CP2C.r)[SEL16(32)] +#define gteLR2 ((s16*)psxRegs.CP2C.r)[SEL16(33)] +#define gteLR3 ((s16*)psxRegs.CP2C.r)[SEL16(34)] +#define gteLG1 ((s16*)psxRegs.CP2C.r)[SEL16(35)] +#define gteLG2 ((s16*)psxRegs.CP2C.r)[SEL16(36)] +#define gteLG3 ((s16*)psxRegs.CP2C.r)[SEL16(37)] +#define gteLB1 ((s16*)psxRegs.CP2C.r)[SEL16(38)] +#define gteLB2 ((s16*)psxRegs.CP2C.r)[SEL16(39)] +#define gteLB3 ((s16*)psxRegs.CP2C.r)[SEL16(40)] +#define gteRFC ((s32*)psxRegs.CP2C.r)[21] +#define gteGFC ((s32*)psxRegs.CP2C.r)[22] +#define gteBFC ((s32*)psxRegs.CP2C.r)[23] +#define gteOFX ((s32*)psxRegs.CP2C.r)[24] +#define gteOFY ((s32*)psxRegs.CP2C.r)[25] +#define gteH ((u16*)psxRegs.CP2C.r)[SEL16(52)] +#define gteDQA ((s16*)psxRegs.CP2C.r)[SEL16(54)] +#define gteDQB ((s32*)psxRegs.CP2C.r)[28] +#define gteZSF3 ((s16*)psxRegs.CP2C.r)[SEL16(58)] +#define gteZSF4 ((s16*)psxRegs.CP2C.r)[SEL16(60)] +#define gteFLAG psxRegs.CP2C.r[31] + +__inline u32 MFC2(int reg) { + switch(reg) { + case 29: + gteORGB = (((gteIR1 >> 7) & 0x1f)) | + (((gteIR2 >> 7) & 0x1f)<<5) | + (((gteIR3 >> 7) & 0x1f)<<10); +// gteORGB = (gteIR1 ) | +// (gteIR2 << 5) | +// (gteIR3 << 10); +// gteORGB = ((gteIR1 & 0xf80)>>7) | +// ((gteIR2 & 0xf80)>>2) | +// ((gteIR3 & 0xf80)<<3); + return gteORGB; + + default: + return psxRegs.CP2D.r[reg]; + } +} + +__inline void MTC2(u32 value, int reg) { + int a; + + switch(reg) { + case 8: case 9: case 10: case 11: + psxRegs.CP2D.r[reg] = (short)value; + break; + + case 15: + gteSXY0 = gteSXY1; + gteSXY1 = gteSXY2; + gteSXY2 = value; + gteSXYP = value; + break; + + case 16: case 17: case 18: case 19: + psxRegs.CP2D.r[reg] = (value & 0xffff); + break; + + case 28: + psxRegs.CP2D.r[28] = value; + gteIR1 = ((value ) & 0x1f) << 7; + gteIR2 = ((value >> 5) & 0x1f) << 7; + gteIR3 = ((value >> 10) & 0x1f) << 7; +// gteIR1 = (value ) & 0x1f; +// gteIR2 = (value >> 5) & 0x1f; +// gteIR3 = (value >> 10) & 0x1f; +// gteIR1 = ((value ) & 0x1f) << 4; +// gteIR2 = ((value >> 5) & 0x1f) << 4; +// gteIR3 = ((value >> 10) & 0x1f) << 4; + break; + + case 30: + psxRegs.CP2D.r[30] = value; + + a = psxRegs.CP2D.r[30]; + if (a > 0) { + int i; + for (i=31; (a & (1 << i)) == 0 && i >= 0; i--); + psxRegs.CP2D.r[31] = 31 - i; + } else if (a < 0) { + int i; + a^= 0xffffffff; + for (i=31; (a & (1 << i)) == 0 && i >= 0; i--); + psxRegs.CP2D.r[31] = 31 - i; + } else { + psxRegs.CP2D.r[31] = 32; + } + break; + + default: + psxRegs.CP2D.r[reg] = value; + } +} + +void gteMFC2() { + if (!_Rt_) return; + psxRegs.GPR.r[_Rt_] = MFC2(_Rd_); +} + +void gteCFC2() { + if (!_Rt_) return; + psxRegs.GPR.r[_Rt_] = psxRegs.CP2C.r[_Rd_]; +} + +void gteMTC2() { + MTC2(psxRegs.GPR.r[_Rt_], _Rd_); +} + +void gteCTC2() { + psxRegs.CP2C.r[_Rd_] = psxRegs.GPR.r[_Rt_]; +} + +#define _oB_ (psxRegs.GPR.r[_Rs_] + _Imm_) + +void gteLWC2() { + MTC2(psxMemRead32(_oB_), _Rt_); +} + +void gteSWC2() { + psxMemWrite32(_oB_, MFC2(_Rt_)); +} + +__inline float NC_OVERFLOW1(float x) { + if (x<-2147483648.0) {gteFLAG |= 1<<29;} + else if (x> 2147483647.0) {gteFLAG |= 1<<26;} + + return x; +} + +__inline float NC_OVERFLOW2(float x) { + if (x<-2147483648.0) {gteFLAG |= 1<<28;} + else if (x> 2147483647.0) {gteFLAG |= 1<<25;} + + return x; +} + +__inline float NC_OVERFLOW3(float x) { + if (x<-2147483648.0) {gteFLAG |= 1<<27;} + else if (x> 2147483647.0) {gteFLAG |= 1<<24;} + + return x; +} + +__inline float NC_OVERFLOW4(float x) { + if (x<-2147483648.0) {gteFLAG |= 1<<16;} + else if (x> 2147483647.0) {gteFLAG |= 1<<15;} + + return x; +} + +__inline s32 FNC_OVERFLOW1(s64 x) { + if (x< (s64)0xffffffff80000000LL) {gteFLAG |= 1<<29;} + else if (x> 2147483647) {gteFLAG |= 1<<26;} + + return (s32)x; +} + +__inline s32 FNC_OVERFLOW2(s64 x) { + if (x< (s64)0xffffffff80000000LL) {gteFLAG |= 1<<28;} + else if (x> 2147483647) {gteFLAG |= 1<<25;} + + return (s32)x; +} + +__inline s32 FNC_OVERFLOW3(s64 x) { + if (x< (s64)0xffffffff80000000LL) {gteFLAG |= 1<<27;} + else if (x> 2147483647) {gteFLAG |= 1<<24;} + + return (s32)x; +} + +__inline s32 FNC_OVERFLOW4(s64 x) { + if (x< (s64)0xffffffff80000000LL) {gteFLAG |= 1<<16;} + else if (x> 2147483647) {gteFLAG |= 1<<15;} + + return (s32)x; +} + +#define _LIMX(negv, posv, flagb) { \ + if (x < (negv)) { x = (negv); gteFLAG |= (1< (posv)) { x = (posv); gteFLAG |= (1< 2147483647.0) { gteFLAG |= (1<<16); } else + if (x <-2147483648.0) { gteFLAG |= (1<<15); } + + if (x > 1023.0) { x = 1023.0; gteFLAG |= (1<<14); } else + if (x < -1024.0) { x = -1024.0; gteFLAG |= (1<<14); } return (x); +} + +__inline float limG2(float x) { + if (x > 2147483647.0) { gteFLAG |= (1<<16); } else + if (x <-2147483648.0) { gteFLAG |= (1<<15); } + + if (x > 1023.0) { x = 1023.0; gteFLAG |= (1<<13); } else + if (x < -1024.0) { x = -1024.0; gteFLAG |= (1<<13); } return (x); +} + +__inline s32 F12limA1S(s64 x) { _LIMX(-32768<<12, 32767<<12, 24); } +__inline s32 F12limA2S(s64 x) { _LIMX(-32768<<12, 32767<<12, 23); } +__inline s32 F12limA3S(s64 x) { _LIMX(-32768<<12, 32767<<12, 22); } +__inline s32 F12limA1U(s64 x) { _LIMX(0, 32767<<12, 24); } +__inline s32 F12limA2U(s64 x) { _LIMX(0, 32767<<12, 23); } +__inline s32 F12limA3U(s64 x) { _LIMX(0, 32767<<12, 22); } + +__inline s16 FlimA1S(s32 x) { _LIMX(-32768, 32767, 24); } +__inline s16 FlimA2S(s32 x) { _LIMX(-32768, 32767, 23); } +__inline s16 FlimA3S(s32 x) { _LIMX(-32768, 32767, 22); } +__inline s16 FlimA1U(s32 x) { _LIMX(0, 32767, 24); } +__inline s16 FlimA2U(s32 x) { _LIMX(0, 32767, 23); } +__inline s16 FlimA3U(s32 x) { _LIMX(0, 32767, 22); } +__inline u8 FlimB1 (s32 x) { _LIMX(0, 255, 21); } +__inline u8 FlimB2 (s32 x) { _LIMX(0, 255, 20); } +__inline u8 FlimB3 (s32 x) { _LIMX(0, 255, 19); } +__inline u16 FlimC (s32 x) { _LIMX(0, 65535, 18); } +__inline s32 FlimD1 (s32 x) { _LIMX(-1024, 1023, 14); } +__inline s32 FlimD2 (s32 x) { _LIMX(-1024, 1023, 13); } +__inline s32 FlimE (s32 x) { _LIMX(0, 65535, 12); } +//__inline s32 FlimE (s32 x) { _LIMX(0, 4095, 12); } + +__inline s32 FlimG1(s64 x) { + if (x > 2147483647) { gteFLAG |= (1<<16); } else + if (x < (s64)0xffffffff80000000LL) { gteFLAG |= (1<<15); } + + if (x > 1023) { x = 1023; gteFLAG |= (1<<14); } else + if (x < -1024) { x = -1024; gteFLAG |= (1<<14); } return (x); +} + +__inline s32 FlimG2(s64 x) { + if (x > 2147483647) { gteFLAG |= (1<<16); } else + if (x < (s64)0xffffffff80000000LL) { gteFLAG |= (1<<15); } + + if (x > 1023) { x = 1023; gteFLAG |= (1<<13); } else + if (x < -1024) { x = -1024; gteFLAG |= (1<<13); } return (x); +} + +#define MAC2IR() { \ + if (gteMAC1 < (long)(-32768)) { gteIR1=(long)(-32768); gteFLAG|=1<<24;} \ + else \ + if (gteMAC1 > (long)( 32767)) { gteIR1=(long)( 32767); gteFLAG|=1<<24;} \ + else gteIR1=(long)gteMAC1; \ + if (gteMAC2 < (long)(-32768)) { gteIR2=(long)(-32768); gteFLAG|=1<<23;} \ + else \ + if (gteMAC2 > (long)( 32767)) { gteIR2=(long)( 32767); gteFLAG|=1<<23;} \ + else gteIR2=(long)gteMAC2; \ + if (gteMAC3 < (long)(-32768)) { gteIR3=(long)(-32768); gteFLAG|=1<<22;} \ + else \ + if (gteMAC3 > (long)( 32767)) { gteIR3=(long)( 32767); gteFLAG|=1<<22;} \ + else gteIR3=(long)gteMAC3; \ +} + + +#define MAC2IR1() { \ + if (gteMAC1 < (long)0) { gteIR1=(long)0; gteFLAG|=1<<24;} \ + else if (gteMAC1 > (long)(32767)) { gteIR1=(long)(32767); gteFLAG|=1<<24;} \ + else gteIR1=(long)gteMAC1; \ + if (gteMAC2 < (long)0) { gteIR2=(long)0; gteFLAG|=1<<23;} \ + else if (gteMAC2 > (long)(32767)) { gteIR2=(long)(32767); gteFLAG|=1<<23;} \ + else gteIR2=(long)gteMAC2; \ + if (gteMAC3 < (long)0) { gteIR3=(long)0; gteFLAG|=1<<22;} \ + else if (gteMAC3 > (long)(32767)) { gteIR3=(long)(32767); gteFLAG|=1<<22;} \ + else gteIR3=(long)gteMAC3; \ +} + +//********END OF LIMITATIONS**********************************/ + +#define GTE_RTPS1(vn) { \ + gteMAC1 = FNC_OVERFLOW1(((signed long)(gteR11*gteVX##vn + gteR12*gteVY##vn + gteR13*gteVZ##vn)>>12) + gteTRX); \ + gteMAC2 = FNC_OVERFLOW2(((signed long)(gteR21*gteVX##vn + gteR22*gteVY##vn + gteR23*gteVZ##vn)>>12) + gteTRY); \ + gteMAC3 = FNC_OVERFLOW3(((signed long)(gteR31*gteVX##vn + gteR32*gteVY##vn + gteR33*gteVZ##vn)>>12) + gteTRZ); \ +} + +/* gteMAC1 = NC_OVERFLOW1(((signed long)(gteR11*gteVX0 + gteR12*gteVY0 + gteR13*gteVZ0)>>12) + gteTRX); + gteMAC2 = NC_OVERFLOW2(((signed long)(gteR21*gteVX0 + gteR22*gteVY0 + gteR23*gteVZ0)>>12) + gteTRY); + gteMAC3 = NC_OVERFLOW3(((signed long)(gteR31*gteVX0 + gteR32*gteVY0 + gteR33*gteVZ0)>>12) + gteTRZ);*/ + +#if 0 + +#define GTE_RTPS2(vn) { \ + if (gteSZ##vn == 0) { \ + DSZ = 2.0f; gteFLAG |= 1<<17; \ + } else { \ + DSZ = (float)gteH / gteSZ##vn; \ + if (DSZ > 2.0) { DSZ = 2.0f; gteFLAG |= 1<<17; } \ +/* if (DSZ > 2147483647.0) { DSZ = 2.0f; gteFLAG |= 1<<17; }*/ \ + } \ + \ +/* gteSX##vn = limG1(gteOFX/65536.0 + (limA1S(gteMAC1) * DSZ));*/ \ +/* gteSY##vn = limG2(gteOFY/65536.0 + (limA2S(gteMAC2) * DSZ));*/ \ + gteSX##vn = FlimG1(gteOFX/65536.0 + (gteIR1 * DSZ)); \ + gteSY##vn = FlimG2(gteOFY/65536.0 + (gteIR2 * DSZ)); \ +} + +#define GTE_RTPS3() { \ + DSZ = gteDQB/16777216.0 + (gteDQA/256.0) * DSZ; \ + gteMAC0 = DSZ * 16777216.0; \ + gteIR0 = limE(DSZ * 4096.0f); \ +printf("zero %x, %x\n", gteMAC0, gteIR0); \ +} +#endif +//#if 0 +#define GTE_RTPS2(vn) { \ + if (gteSZ##vn == 0) { \ + FDSZ = 2 << 16; gteFLAG |= 1<<17; \ + } else { \ + FDSZ = ((u64)gteH << 32) / ((u64)gteSZ##vn << 16); \ + if ((u64)FDSZ > (2 << 16)) { FDSZ = 2 << 16; gteFLAG |= 1<<17; } \ + } \ + \ + gteSX##vn = FlimG1((gteOFX + (((s64)((s64)gteIR1 << 16) * FDSZ) >> 16)) >> 16); \ + gteSY##vn = FlimG2((gteOFY + (((s64)((s64)gteIR2 << 16) * FDSZ) >> 16)) >> 16); \ +} + +#define GTE_RTPS3() { \ + FDSZ = (s64)((s64)gteDQB + (((s64)((s64)gteDQA << 8) * FDSZ) >> 8)); \ + gteMAC0 = FDSZ; \ + gteIR0 = FlimE(FDSZ >> 12); \ +} +//#endif +// gteMAC0 = (gteDQB/16777216.0 + (gteDQA/256.0) * DSZ) * 16777216.0; +// gteIR0 = limE((gteDQB/16777216.0 + (gteDQA/256.0) * DSZ) * 4096.0); +// gteMAC0 = ((gteDQB >> 24) + (gteDQA >> 8) * DSZ) * 16777216.0; +// gteIR0 = FlimE(((gteDQB >> 24) + (gteDQA >> 8) * DSZ) * 4096.0); + + +void gteRTPS() { + s64 FDSZ; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_RTPS\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("RTPS", 14); + G_SD(0); + G_SD(1); + + G_SD(16); // Store original fifo + G_SD(17); + G_SD(18); + G_SD(19); + + G_SC(0); + G_SC(1); + G_SC(2); + G_SC(3); + G_SC(4); + G_SC(5); + G_SC(6); + G_SC(7); + + G_SC(24); + G_SC(25); + G_SC(26); + G_SC(27); + G_SC(28); + } +#endif + + gteFLAG = 0; + + GTE_RTPS1(0); + + MAC2IR(); + + gteSZx = gteSZ0; + gteSZ0 = gteSZ1; + gteSZ1 = gteSZ2; +// gteSZ2 = limC(gteMAC3); + gteSZ2 = FlimC(gteMAC3); + + gteSXY0 = gteSXY1; + gteSXY1 = gteSXY2; + + GTE_RTPS2(2); + gteSXYP = gteSXY2; + + GTE_RTPS3(); + + SUM_FLAG; + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(8); + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(12); + //G_GD(13); + G_GD(14); + + G_GD(16); + G_GD(17); + G_GD(18); + G_GD(19); + + G_GD(24); + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteRTPT() { + s64 FDSZ; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_RTPT\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("RTPT", 22); + G_SD(0); + G_SD(1); + G_SD(2); + G_SD(3); + G_SD(4); + G_SD(5); + + G_SD(16); // Store original fifo + G_SD(17); + G_SD(18); + G_SD(19); + + G_SC(0); + G_SC(1); + G_SC(2); + G_SC(3); + G_SC(4); + G_SC(5); + G_SC(6); + G_SC(7); + + G_SC(24); + G_SC(25); + G_SC(26); + G_SC(27); + G_SC(28); + } +#endif + + gteFLAG = 0; + + gteSZx = gteSZ2; + + GTE_RTPS1(0); + +// gteSZ0 = limC(gteMAC3); + gteSZ0 = FlimC(gteMAC3); + + gteIR1 = FlimA1S(gteMAC1); + gteIR2 = FlimA2S(gteMAC2); + GTE_RTPS2(0); + + GTE_RTPS1(1); + +// gteSZ1 = limC(gteMAC3); + gteSZ1 = FlimC(gteMAC3); + + gteIR1 = FlimA1S(gteMAC1); + gteIR2 = FlimA2S(gteMAC2); + GTE_RTPS2(1); + + GTE_RTPS1(2); + + MAC2IR(); + +// gteSZ2 = limC(gteMAC3); + gteSZ2 = FlimC(gteMAC3); + + GTE_RTPS2(2); + gteSXYP = gteSXY2; + + GTE_RTPS3(); + + SUM_FLAG; + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(8); + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(12); + G_GD(13); + G_GD(14); + + G_GD(16); + G_GD(17); + G_GD(18); + G_GD(19); + + G_GD(24); + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +#define gte_C11 gteLR1 +#define gte_C12 gteLR2 +#define gte_C13 gteLR3 +#define gte_C21 gteLG1 +#define gte_C22 gteLG2 +#define gte_C23 gteLG3 +#define gte_C31 gteLB1 +#define gte_C32 gteLB2 +#define gte_C33 gteLB3 + +#define _MVMVA_FUNC(_v0, _v1, _v2, mx) { \ + SSX = (_v0) * mx##11 + (_v1) * mx##12 + (_v2) * mx##13; \ + SSY = (_v0) * mx##21 + (_v1) * mx##22 + (_v2) * mx##23; \ + SSZ = (_v0) * mx##31 + (_v1) * mx##32 + (_v2) * mx##33; \ +} + +void gteMVMVA() { + s64 SSX, SSY, SSZ; + +#ifdef GTE_LOG + GTE_LOG("GTE_MVMVA %lx\n", psxRegs.code & 0x1ffffff); +#endif + + switch (psxRegs.code & 0x78000) { + case 0x00000: // V0 * R + _MVMVA_FUNC(gteVX0, gteVY0, gteVZ0, gteR); break; + case 0x08000: // V1 * R + _MVMVA_FUNC(gteVX1, gteVY1, gteVZ1, gteR); break; + case 0x10000: // V2 * R + _MVMVA_FUNC(gteVX2, gteVY2, gteVZ2, gteR); break; + case 0x18000: // IR * R + _MVMVA_FUNC((short)gteIR1, (short)gteIR2, (short)gteIR3, gteR); + break; + case 0x20000: // V0 * L + _MVMVA_FUNC(gteVX0, gteVY0, gteVZ0, gteL); break; + case 0x28000: // V1 * L + _MVMVA_FUNC(gteVX1, gteVY1, gteVZ1, gteL); break; + case 0x30000: // V2 * L + _MVMVA_FUNC(gteVX2, gteVY2, gteVZ2, gteL); break; + case 0x38000: // IR * L + _MVMVA_FUNC((short)gteIR1, (short)gteIR2, (short)gteIR3, gteL); break; + case 0x40000: // V0 * C + _MVMVA_FUNC(gteVX0, gteVY0, gteVZ0, gte_C); break; + case 0x48000: // V1 * C + _MVMVA_FUNC(gteVX1, gteVY1, gteVZ1, gte_C); break; + case 0x50000: // V2 * C + _MVMVA_FUNC(gteVX2, gteVY2, gteVZ2, gte_C); break; + case 0x58000: // IR * C + _MVMVA_FUNC((short)gteIR1, (short)gteIR2, (short)gteIR3, gte_C); break; + default: + SSX = SSY = SSZ = 0; + } + + if (psxRegs.code & 0x80000) { +// SSX /= 4096.0; SSY /= 4096.0; SSZ /= 4096.0; + SSX>>= 12; SSY>>= 12; SSZ>>= 12; + } + + switch (psxRegs.code & 0x6000) { + case 0x0000: // Add TR + SSX+= gteTRX; + SSY+= gteTRY; + SSZ+= gteTRZ; + break; + case 0x2000: // Add BK + SSX+= gteRBK; + SSY+= gteGBK; + SSZ+= gteBBK; + break; + case 0x4000: // Add FC + SSX+= gteRFC; + SSY+= gteGFC; + SSZ+= gteBFC; + break; + } + + gteFLAG = 0; + //gteMAC1 = (long)SSX; + //gteMAC2 = (long)SSY; + //gteMAC3 = (long)SSZ;//okay the follow lines are correct?? +/* gteMAC1 = NC_OVERFLOW1(SSX); + gteMAC2 = NC_OVERFLOW2(SSY); + gteMAC3 = NC_OVERFLOW3(SSZ);*/ + gteMAC1 = FNC_OVERFLOW1(SSX); + gteMAC2 = FNC_OVERFLOW2(SSY); + gteMAC3 = FNC_OVERFLOW3(SSZ); + if (psxRegs.code & 0x400) + MAC2IR1() + else MAC2IR() + + SUM_FLAG; +} + +void gteNCLIP() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCLIP\n"); +#endif + + //gteLog +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCLIP", 8); + G_SD(12); + G_SD(13); + G_SD(14); + } +#endif + + gteFLAG = 0; + + + gteMAC0 = gteSX0 * (gteSY1 - gteSY2) + + gteSX1 * (gteSY2 - gteSY0) + + gteSX2 * (gteSY0 - gteSY1); + + //gteMAC0 = (gteSX0 - gteSX1) * (gteSY0 - gteSY2) - (gteSX0 - gteSX2) * (gteSY0 - gteSY1); + + SUM_FLAG; + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(24); + G_GC(31); + } +#endif +} + +void gteAVSZ3() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_AVSZ3\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("AVSZ3", 5); + G_SD(16); + G_SD(17); + G_SD(18); + G_SD(19); + G_SC(29); + G_SC(30); + } +#endif + + + gteFLAG = 0; + + gteMAC0 = ((gteSZ0 + gteSZ1 + gteSZ2) * (gteZSF3)) >> 12; + + gteOTZ = FlimC(gteMAC0); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(7); + G_GD(24); + G_GC(31); + } +#endif +} + +void gteAVSZ4() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_AVSZ4\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("AVSZ4", 6); + G_SD(16); + G_SD(17); + G_SD(18); + G_SD(19); + G_SC(29); + G_SC(30); + } +#endif + + gteFLAG = 0; + + gteMAC0 = ((gteSZx + gteSZ0 + gteSZ1 + gteSZ2) * (gteZSF4))>> 12; + + gteOTZ = FlimC(gteMAC0); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(7); + G_GD(24); + G_GC(31); + } +#endif +} + +void gteSQR() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_SQR %lx\n", psxRegs.code & 0x1ffffff); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("SQR", 5); + G_SD(9); + G_SD(10); + G_SD(11); + } +#endif + + gteFLAG = 0; + + if (psxRegs.code & 0x80000) { + gteMAC1 = FNC_OVERFLOW1((gteIR1 * gteIR1) >> 12); + gteMAC2 = FNC_OVERFLOW2((gteIR2 * gteIR2) >> 12); + gteMAC3 = FNC_OVERFLOW3((gteIR3 * gteIR3) >> 12); + } else { + gteMAC1 = FNC_OVERFLOW1(gteIR1 * gteIR1); + gteMAC2 = FNC_OVERFLOW2(gteIR2 * gteIR2); + gteMAC3 = FNC_OVERFLOW3(gteIR3 * gteIR3); + } + MAC2IR1(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + G_GD(25); + G_GD(26); + G_GD(27); + G_GC(31); + } +#endif +} + +#define GTE_NCCS(vn) \ + gte_LL1 = F12limA1U((gteL11*gteVX##vn + gteL12*gteVY##vn + gteL13*gteVZ##vn) >> 12); \ + gte_LL2 = F12limA2U((gteL21*gteVX##vn + gteL22*gteVY##vn + gteL23*gteVZ##vn) >> 12); \ + gte_LL3 = F12limA3U((gteL31*gteVX##vn + gteL32*gteVY##vn + gteL33*gteVZ##vn) >> 12); \ + gte_RRLT= F12limA1U(gteRBK + ((gteLR1*gte_LL1 + gteLR2*gte_LL2 + gteLR3*gte_LL3) >> 12)); \ + gte_GGLT= F12limA2U(gteGBK + ((gteLG1*gte_LL1 + gteLG2*gte_LL2 + gteLG3*gte_LL3) >> 12)); \ + gte_BBLT= F12limA3U(gteBBK + ((gteLB1*gte_LL1 + gteLB2*gte_LL2 + gteLB3*gte_LL3) >> 12)); \ + \ + gteMAC1 = (long)(((s64)((u32)gteR<<12)*gte_RRLT) >> 20);\ + gteMAC2 = (long)(((s64)((u32)gteG<<12)*gte_GGLT) >> 20);\ + gteMAC3 = (long)(((s64)((u32)gteB<<12)*gte_BBLT) >> 20); + + +void gteNCCS() { + s32 gte_LL1, gte_LL2, gte_LL3; + s32 gte_RRLT, gte_GGLT, gte_BBLT; + +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCCS\n"); +#endif + +/* + gteFLAG = 0; + + GTE_NCCS(0); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCCS", 17); + G_SD(0); + G_SD(1); + G_SD(6); + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + } +#endif + + gteFLAG = 0; + + GTE_NCCS(0); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteR2 = FlimB1(gteMAC1>>4); + gteG2 = FlimB2(gteMAC2>>4); + gteB2 = FlimB3(gteMAC3>>4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + //G_GD(24); Doc must be wrong. PSX does not touch it. + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteNCCT() { + s32 gte_LL1, gte_LL2, gte_LL3; + s32 gte_RRLT, gte_GGLT, gte_BBLT; + +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCCT\n"); +#endif + + + /*gteFLAG = 0; + + GTE_NCCS(0); + GTE_NCCS(1); + GTE_NCCS(2); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCCT", 39); + G_SD(0); + G_SD(1); + G_SD(2); + G_SD(3); + G_SD(4); + G_SD(5); + G_SD(6); + + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + } +#endif + + gteFLAG = 0; + + GTE_NCCS(0); + + gteR0 = FlimB1(gteMAC1>>4); + gteG0 = FlimB2(gteMAC2>>4); + gteB0 = FlimB3(gteMAC3>>4); gteCODE0 = gteCODE; + + GTE_NCCS(1); + + gteR1 = FlimB1(gteMAC1>>4); + gteG1 = FlimB2(gteMAC2>>4); + gteB1 = FlimB3(gteMAC3>>4); gteCODE1 = gteCODE; + + GTE_NCCS(2); + + gteR2 = FlimB1(gteMAC1>>4); + gteG2 = FlimB2(gteMAC2>>4); + gteB2 = FlimB3(gteMAC3>>4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(20); + G_GD(21); + G_GD(22); + + //G_GD(24); Doc must be wrong. PSX does not touch it. + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} +/* +#define GTE_NCDS(vn) \ +gte_LL1 = limA1U((gteL11*gteVX##vn + gteL12*gteVY##vn + gteL13*gteVZ##vn)/16777216.0f);\ +gte_LL2 = limA2U((gteL21*gteVX##vn + gteL22*gteVY##vn + gteL23*gteVZ##vn)/16777216.0f);\ +gte_LL3 = limA3U((gteL31*gteVX##vn + gteL32*gteVY##vn + gteL33*gteVZ##vn)/16777216.0f);\ +gte_RRLT= limA1U(gteRBK/4096.0f + (gteLR1/4096.0f*gte_LL1 + gteLR2/4096.0f*gte_LL2 + gteLR3/4096.0f*gte_LL3));\ +gte_GGLT= limA2U(gteGBK/4096.0f + (gteLG1/4096.0f*gte_LL1 + gteLG2/4096.0f*gte_LL2 + gteLG3/4096.0f*gte_LL3));\ +gte_BBLT= limA3U(gteBBK/4096.0f + (gteLB1/4096.0f*gte_LL1 + gteLB2/4096.0f*gte_LL2 + gteLB3/4096.0f*gte_LL3));\ +gte_RR0 = (gteR*gte_RRLT) + (gteIR0/4096.0f * limA1S(gteRFC/16.0f - (gteR*gte_RRLT)));\ +gte_GG0 = (gteG*gte_GGLT) + (gteIR0/4096.0f * limA2S(gteGFC/16.0f - (gteG*gte_GGLT)));\ +gte_BB0 = (gteB*gte_BBLT) + (gteIR0/4096.0f * limA3S(gteBFC/16.0f - (gteB*gte_BBLT)));\ +gteMAC1= (long)(gte_RR0 * 16.0f); gteIR1 = (long)limA1U(gte_RR0*16.0f);\ +gteMAC2= (long)(gte_GG0 * 16.0f); gteIR2 = (long)limA2U(gte_GG0*16.0f);\ +gteMAC3= (long)(gte_BB0 * 16.0f); gteIR3 = (long)limA3U(gte_BB0*16.0f);\ +gteRGB0 = gteRGB1; \ +gteRGB1 = gteRGB2; \ +gteR2 = limB1(gte_RR0); \ +gteG2 = limB2(gte_GG0); \ +gteB2 = limB3(gte_BB0); gteCODE2 = gteCODE; +*/ +/* +#define GTE_NCDS(vn) \ +gte_LL1 = limA1U((gteL11*gteVX##vn + gteL12*gteVY##vn + gteL13*gteVZ##vn)/16777216.0f);\ +gte_LL2 = limA2U((gteL21*gteVX##vn + gteL22*gteVY##vn + gteL23*gteVZ##vn)/16777216.0f);\ +gte_LL3 = limA3U((gteL31*gteVX##vn + gteL32*gteVY##vn + gteL33*gteVZ##vn)/16777216.0f);\ +gte_RRLT= limA1U(gteRBK/4096.0f + (gteLR1/4096.0f*gte_LL1 + gteLR2/4096.0f*gte_LL2 + gteLR3/4096.0f*gte_LL3));\ +gte_GGLT= limA2U(gteGBK/4096.0f + (gteLG1/4096.0f*gte_LL1 + gteLG2/4096.0f*gte_LL2 + gteLG3/4096.0f*gte_LL3));\ +gte_BBLT= limA3U(gteBBK/4096.0f + (gteLB1/4096.0f*gte_LL1 + gteLB2/4096.0f*gte_LL2 + gteLB3/4096.0f*gte_LL3));\ + \ + gte_RR0 = (gteR*gte_RRLT) + (gteIR0/4096.0f * limA1S(gteRFC/16.0f - (gteR*gte_RRLT)));\ + gte_GG0 = (gteG*gte_GGLT) + (gteIR0/4096.0f * limA2S(gteGFC/16.0f - (gteG*gte_GGLT)));\ + gte_BB0 = (gteB*gte_BBLT) + (gteIR0/4096.0f * limA3S(gteBFC/16.0f - (gteB*gte_BBLT)));\ + gteMAC1 = (long)(gte_RR0 << 4); \ + gteMAC2 = (long)(gte_GG0 << 4); \ + gteMAC3 = (long)(gte_BB0 << 4); +*/ +#define GTE_NCDS(vn) \ + gte_LL1 = F12limA1U((gteL11*gteVX##vn + gteL12*gteVY##vn + gteL13*gteVZ##vn) >> 12); \ + gte_LL2 = F12limA2U((gteL21*gteVX##vn + gteL22*gteVY##vn + gteL23*gteVZ##vn) >> 12); \ + gte_LL3 = F12limA3U((gteL31*gteVX##vn + gteL32*gteVY##vn + gteL33*gteVZ##vn) >> 12); \ + gte_RRLT= F12limA1U(gteRBK + ((gteLR1*gte_LL1 + gteLR2*gte_LL2 + gteLR3*gte_LL3) >> 12)); \ + gte_GGLT= F12limA2U(gteGBK + ((gteLG1*gte_LL1 + gteLG2*gte_LL2 + gteLG3*gte_LL3) >> 12)); \ + gte_BBLT= F12limA3U(gteBBK + ((gteLB1*gte_LL1 + gteLB2*gte_LL2 + gteLB3*gte_LL3) >> 12)); \ + \ + gte_RR0 = (long)(((s64)((u32)gteR<<12)*gte_RRLT) >> 12);\ + gte_GG0 = (long)(((s64)((u32)gteG<<12)*gte_GGLT) >> 12);\ + gte_BB0 = (long)(((s64)((u32)gteB<<12)*gte_BBLT) >> 12);\ + gteMAC1 = (long)((gte_RR0 + (((s64)gteIR0 * F12limA1S((s64)(gteRFC << 8) - gte_RR0)) >> 12)) >> 8);\ + gteMAC2 = (long)((gte_GG0 + (((s64)gteIR0 * F12limA2S((s64)(gteGFC << 8) - gte_GG0)) >> 12)) >> 8);\ + gteMAC3 = (long)((gte_BB0 + (((s64)gteIR0 * F12limA3S((s64)(gteBFC << 8) - gte_BB0)) >> 12)) >> 8); + +void gteNCDS() { + s32 gte_LL1, gte_LL2, gte_LL3; + s32 gte_RRLT, gte_GGLT, gte_BBLT; + s32 gte_RR0, gte_GG0, gte_BB0; + +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCDS\n"); +#endif + +/* gteFLAG = 0; + + R = ((gteRGB)&0xff); + G = ((gteRGB>> 8)&0xff); + B = ((gteRGB>>16)&0xff); + C = ((gteRGB>>24)&0xff); + + tLL1 = (gteL11/4096.0 * gteVX0/4096.0) + (gteL12/4096.0 * gteVY0/4096.0) + (gteL13/4096.0 * gteVZ0/4096.0); + tLL2 = (gteL21/4096.0 * gteVX0/4096.0) + (gteL22/4096.0 * gteVY0/4096.0) + (gteL23/4096.0 * gteVZ0/4096.0); + tLL3 = (gteL31/4096.0 * gteVX0/4096.0) + (gteL32/4096.0 * gteVY0/4096.0) + (gteL33/4096.0 * gteVZ0/4096.0); + + tL1 = LimitAU(tLL1,24); + tL2 = LimitAU(tLL2,23); + tL3 = LimitAU(tLL3,22); + + tRRLT = gteRBK/4096.0 + (gteLR1/4096.0 * tL1) + (gteLR2/4096.0 * tL2) + (gteLR3/4096.0 * tL3); + tGGLT = gteGBK/4096.0 + (gteLG1/4096.0 * tL1) + (gteLG2/4096.0 * tL2) + (gteLG3/4096.0 * tL3); + tBBLT = gteBBK/4096.0 + (gteLB1/4096.0 * tL1) + (gteLB2/4096.0 * tL2) + (gteLB3/4096.0 * tL3); + + tRLT = LimitAU(tRRLT,24); + tGLT = LimitAU(tGGLT,23); + tBLT = LimitAU(tBBLT,22); + + tRR0 = (R * tRLT) + (gteIR0/4096.0 * LimitAS(gteRFC/16.0 - (R * tRLT),24)); + tGG0 = (G * tGLT) + (gteIR0/4096.0 * LimitAS(gteGFC/16.0 - (G * tGLT),23)); + tBB0 = (B * tBLT) + (gteIR0/4096.0 * LimitAS(gteBFC/16.0 - (B * tBLT),22)); + + gteMAC1 = (long)(tRR0 * 16.0); gteIR1 = (long)LimitAU((tRR0*16.0),24); + gteMAC2 = (long)(tGG0 * 16.0); gteIR2 = (long)LimitAU((tGG0*16.0),23); + gteMAC3 = (long)(tBB0 * 16.0); gteIR3 = (long)LimitAU((tBB0*16.0),22); + + R = (unsigned long)LimitB(tRR0,21); if (R>255) R=255; else if (R<0) R=0; + G = (unsigned long)LimitB(tGG0,20); if (G>255) G=255; else if (G<0) G=0; + B = (unsigned long)LimitB(tBB0,19); if (B>255) B=255; else if (B<0) B=0; + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteRGB2 = R|(G<<8)|(B<<16)|(C<<24); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCDS", 19); + G_SD(0); + G_SD(1); + G_SD(6); + G_SD(8); + + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + + gteFLAG = 0; + GTE_NCDS(0); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG; + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteNCDT() { + s32 gte_LL1, gte_LL2, gte_LL3; + s32 gte_RRLT, gte_GGLT, gte_BBLT; + s32 gte_RR0, gte_GG0, gte_BB0; + +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCDT\n"); +#endif + +/* gteFLAG = 0; + + R = ((gteRGB)&0xff); + G = ((gteRGB>> 8)&0xff); + B = ((gteRGB>>16)&0xff); + C = ((gteRGB>>24)&0xff); + + tLL1 = (gteL11/4096.0 * gteVX0/4096.0) + (gteL12/4096.0 * gteVY0/4096.0) + (gteL13/4096.0 * gteVZ0/4096.0); + tLL2 = (gteL21/4096.0 * gteVX0/4096.0) + (gteL22/4096.0 * gteVY0/4096.0) + (gteL23/4096.0 * gteVZ0/4096.0); + tLL3 = (gteL31/4096.0 * gteVX0/4096.0) + (gteL32/4096.0 * gteVY0/4096.0) + (gteL33/4096.0 * gteVZ0/4096.0); + + tL1 = LimitAU(tLL1,24); + tL2 = LimitAU(tLL2,23); + tL3 = LimitAU(tLL3,22); + + tRRLT = gteRBK/4096.0 + (gteLR1/4096.0 * tL1) + (gteLR2/4096.0 * tL2) + (gteLR3/4096.0 * tL3); + tGGLT = gteGBK/4096.0 + (gteLG1/4096.0 * tL1) + (gteLG2/4096.0 * tL2) + (gteLG3/4096.0 * tL3); + tBBLT = gteBBK/4096.0 + (gteLB1/4096.0 * tL1) + (gteLB2/4096.0 * tL2) + (gteLB3/4096.0 * tL3); + + tRLT = LimitAU(tRRLT,24); + tGLT = LimitAU(tGGLT,23); + tBLT = LimitAU(tBBLT,22); + + tRR0 = (R * tRLT) + (gteIR0/4096.0 * LimitAS(gteRFC/16.0 - (R * tRLT),24)); + tGG0 = (G * tGLT) + (gteIR0/4096.0 * LimitAS(gteGFC/16.0 - (G * tGLT),23)); + tBB0 = (B * tBLT) + (gteIR0/4096.0 * LimitAS(gteBFC/16.0 - (B * tBLT),22)); + + gteMAC1 = (long)(tRR0 * 16.0); gteIR1 = (long)LimitAU((tRR0*16.0),24); + gteMAC2 = (long)(tGG0 * 16.0); gteIR2 = (long)LimitAU((tGG0*16.0),23); + gteMAC3 = (long)(tBB0 * 16.0); gteIR3 = (long)LimitAU((tBB0*16.0),22); + + R = (unsigned long)LimitB(tRR0,21); if (R>255) R=255; else if (R<0) R=0; + G = (unsigned long)LimitB(tGG0,20); if (G>255) G=255; else if (G<0) G=0; + B = (unsigned long)LimitB(tBB0,19); if (B>255) B=255; else if (B<0) B=0; + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteRGB2 = R|(G<<8)|(B<<16)|(C<<24); + + R = ((gteRGB)&0xff); + G = ((gteRGB>> 8)&0xff); + B = ((gteRGB>>16)&0xff); + C = ((gteRGB>>24)&0xff); + + tLL1 = (gteL11/4096.0 * gteVX1/4096.0) + (gteL12/4096.0 * gteVY1/4096.0) + (gteL13/4096.0 * gteVZ1/4096.0); + tLL2 = (gteL21/4096.0 * gteVX1/4096.0) + (gteL22/4096.0 * gteVY1/4096.0) + (gteL23/4096.0 * gteVZ1/4096.0); + tLL3 = (gteL31/4096.0 * gteVX1/4096.0) + (gteL32/4096.0 * gteVY1/4096.0) + (gteL33/4096.0 * gteVZ1/4096.0); + + tL1 = LimitAU(tLL1,24); + tL2 = LimitAU(tLL2,23); + tL3 = LimitAU(tLL3,22); + + tRRLT = gteRBK/4096.0 + (gteLR1/4096.0 * tL1) + (gteLR2/4096.0 * tL2) + (gteLR3/4096.0 * tL3); + tGGLT = gteGBK/4096.0 + (gteLG1/4096.0 * tL1) + (gteLG2/4096.0 * tL2) + (gteLG3/4096.0 * tL3); + tBBLT = gteBBK/4096.0 + (gteLB1/4096.0 * tL1) + (gteLB2/4096.0 * tL2) + (gteLB3/4096.0 * tL3); + + tRLT = LimitAU(tRRLT,24); + tGLT = LimitAU(tGGLT,23); + tBLT = LimitAU(tBBLT,22); + + tRR0 = (R * tRLT) + (gteIR0/4096.0 * LimitAS(gteRFC/16.0 - (R * tRLT),24)); + tGG0 = (G * tGLT) + (gteIR0/4096.0 * LimitAS(gteGFC/16.0 - (G * tGLT),23)); + tBB0 = (B * tBLT) + (gteIR0/4096.0 * LimitAS(gteBFC/16.0 - (B * tBLT),22)); + + gteMAC1 = (long)(tRR0 * 16.0); gteIR1 = (long)LimitAU((tRR0*16.0),24); + gteMAC2 = (long)(tGG0 * 16.0); gteIR2 = (long)LimitAU((tGG0*16.0),23); + gteMAC3 = (long)(tBB0 * 16.0); gteIR3 = (long)LimitAU((tBB0*16.0),22); + + R = (unsigned long)LimitB(tRR0,21); if (R>255) R=255; else if (R<0) R=0; + G = (unsigned long)LimitB(tGG0,20); if (G>255) G=255; else if (G<0) G=0; + B = (unsigned long)LimitB(tBB0,19); if (B>255) B=255; else if (B<0) B=0; + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteRGB2 = R|(G<<8)|(B<<16)|(C<<24); + + R = ((gteRGB)&0xff); + G = ((gteRGB>> 8)&0xff); + B = ((gteRGB>>16)&0xff); + C = ((gteRGB>>24)&0xff); + + tLL1 = (gteL11/4096.0 * gteVX2/4096.0) + (gteL12/4096.0 * gteVY2/4096.0) + (gteL13/4096.0 * gteVZ2/4096.0); + tLL2 = (gteL21/4096.0 * gteVX2/4096.0) + (gteL22/4096.0 * gteVY2/4096.0) + (gteL23/4096.0 * gteVZ2/4096.0); + tLL3 = (gteL31/4096.0 * gteVX2/4096.0) + (gteL32/4096.0 * gteVY2/4096.0) + (gteL33/4096.0 * gteVZ2/4096.0); + + tL1 = LimitAU(tLL1,24); + tL2 = LimitAU(tLL2,23); + tL3 = LimitAU(tLL3,22); + + tRRLT = gteRBK/4096.0 + (gteLR1/4096.0 * tL1) + (gteLR2/4096.0 * tL2) + (gteLR3/4096.0 * tL3); + tGGLT = gteGBK/4096.0 + (gteLG1/4096.0 * tL1) + (gteLG2/4096.0 * tL2) + (gteLG3/4096.0 * tL3); + tBBLT = gteBBK/4096.0 + (gteLB1/4096.0 * tL1) + (gteLB2/4096.0 * tL2) + (gteLB3/4096.0 * tL3); + + tRLT = LimitAU(tRRLT,24); + tGLT = LimitAU(tGGLT,23); + tBLT = LimitAU(tBBLT,22); + + tRR0 = (R * tRLT) + (gteIR0/4096.0 * LimitAS(gteRFC/16.0 - (R * tRLT),24)); + tGG0 = (G * tGLT) + (gteIR0/4096.0 * LimitAS(gteGFC/16.0 - (G * tGLT),23)); + tBB0 = (B * tBLT) + (gteIR0/4096.0 * LimitAS(gteBFC/16.0 - (B * tBLT),22)); + + gteMAC1 = (long)(tRR0 * 16.0); gteIR1 = (long)LimitAU((tRR0*16.0),24); + gteMAC2 = (long)(tGG0 * 16.0); gteIR2 = (long)LimitAU((tGG0*16.0),23); + gteMAC3 = (long)(tBB0 * 16.0); gteIR3 = (long)LimitAU((tBB0*16.0),22); + + R = (unsigned long)LimitB(tRR0,21); if (R>255) R=255; else if (R<0) R=0; + G = (unsigned long)LimitB(tGG0,20); if (G>255) G=255; else if (G<0) G=0; + B = (unsigned long)LimitB(tBB0,19); if (B>255) B=255; else if (B<0) B=0; + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteRGB2 = R|(G<<8)|(B<<16)|(C<<24); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCDT", 44); + G_SD(0); + G_SD(1); + G_SD(2); + G_SD(3); + G_SD(4); + G_SD(5); + G_SD(6); + G_SD(8); + + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + + gteFLAG = 0; + GTE_NCDS(0); + + gteR0 = FlimB1(gteMAC1 >> 4); + gteG0 = FlimB2(gteMAC2 >> 4); + gteB0 = FlimB3(gteMAC3 >> 4); gteCODE0 = gteCODE; + + GTE_NCDS(1); + + gteR1 = FlimB1(gteMAC1 >> 4); + gteG1 = FlimB2(gteMAC2 >> 4); + gteB1 = FlimB3(gteMAC3 >> 4); gteCODE1 = gteCODE; + + GTE_NCDS(2); + + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG; + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(20); + G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +#define gteD1 (*(short *)>eR11) +#define gteD2 (*(short *)>eR22) +#define gteD3 (*(short *)>eR33) + +void gteOP() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_OP %lx\n", psxRegs.code & 0x1ffffff); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("OP", 6); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SC(0); + G_SC(2); + G_SC(4); + } +#endif + + gteFLAG = 0; + + if (psxRegs.code & 0x80000) { + gteMAC1 = FNC_OVERFLOW1((gteD2 * gteIR3 - gteD3 * gteIR2) >> 12); + gteMAC2 = FNC_OVERFLOW2((gteD3 * gteIR1 - gteD1 * gteIR3) >> 12); + gteMAC3 = FNC_OVERFLOW3((gteD1 * gteIR2 - gteD2 * gteIR1) >> 12); + } else { + gteMAC1 = FNC_OVERFLOW1(gteD2 * gteIR3 - gteD3 * gteIR2); + gteMAC2 = FNC_OVERFLOW2(gteD3 * gteIR1 - gteD1 * gteIR3); + gteMAC3 = FNC_OVERFLOW3(gteD1 * gteIR2 - gteD2 * gteIR1); + } + + /* NC: old + MAC2IR1(); + */ + MAC2IR(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteDCPL() { +// unsigned long C,R,G,B; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_DCPL\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("DCPL", 8); + G_SD(6); + G_SD(8); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + + gteMAC1 = ( (signed long)(gteR)*gteIR1 + (gteIR0*(signed short)FlimA1S(gteRFC - ((gteR*gteIR1)>>12) )) ) >>8; + gteMAC2 = ( (signed long)(gteG)*gteIR2 + (gteIR0*(signed short)FlimA2S(gteGFC - ((gteG*gteIR2)>>12) )) ) >>8; + gteMAC3 = ( (signed long)(gteB)*gteIR3 + (gteIR0*(signed short)FlimA3S(gteBFC - ((gteB*gteIR3)>>12) )) ) >>8; + + gteFLAG=0; + MAC2IR(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteGPF() { + +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_GPF %lx\n", psxRegs.code & 0x1ffffff); +#endif +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("GPF", 5); + G_SD(6); + G_SD(8); + G_SD(9); + G_SD(10); + G_SD(11); + } +#endif + + gteFLAG = 0; + + if (psxRegs.code & 0x80000) { + gteMAC1 = FNC_OVERFLOW1((gteIR0 * gteIR1) >> 12); + gteMAC2 = FNC_OVERFLOW2((gteIR0 * gteIR2) >> 12); + gteMAC3 = FNC_OVERFLOW3((gteIR0 * gteIR3) >> 12); + } else { + gteMAC1 = FNC_OVERFLOW1(gteIR0 * gteIR1); + gteMAC2 = FNC_OVERFLOW2(gteIR0 * gteIR2); + gteMAC3 = FNC_OVERFLOW3(gteIR0 * gteIR3); + } + MAC2IR(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteGPL() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_GPL %lx\n", psxRegs.code & 0x1ffffff); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("GPL", 5); + G_SD(6); + G_SD(8); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SD(25); + G_SD(26); + G_SD(27); + } +#endif + + gteFLAG = 0; + + if (psxRegs.code & 0x80000) { + gteMAC1 = FNC_OVERFLOW1(gteMAC1 + ((gteIR0 * gteIR1) >> 12)); + gteMAC2 = FNC_OVERFLOW2(gteMAC2 + ((gteIR0 * gteIR2) >> 12)); + gteMAC3 = FNC_OVERFLOW3(gteMAC3 + ((gteIR0 * gteIR3) >> 12)); + } else { + gteMAC1 = FNC_OVERFLOW1(gteMAC1 + (gteIR0 * gteIR1)); + gteMAC2 = FNC_OVERFLOW2(gteMAC2 + (gteIR0 * gteIR2)); + gteMAC3 = FNC_OVERFLOW3(gteMAC3 + (gteIR0 * gteIR3)); + } + MAC2IR(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteDPCS() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_DPCS\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("DPCS", 8); + G_SD(6); + G_SD(8); + + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + +/* gteFLAG = 0; + + C = gteCODE; + R = gteR * 16.0; + G = gteG * 16.0; + B = gteB * 16.0; + + GTE_DPCS(); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ +/* gteFLAG = 0; + + gteMAC1 = NC_OVERFLOW1((gteR * 16.0f) + (gteIR0 * limA1S(gteRFC - (gteR * 16.0f))) / 4096.0f); + gteMAC2 = NC_OVERFLOW2((gteG * 16.0f) + (gteIR0 * limA2S(gteGFC - (gteG * 16.0f))) / 4096.0f); + gteMAC3 = NC_OVERFLOW3((gteB * 16.0f) + (gteIR0 * limA3S(gteBFC - (gteB * 16.0f))) / 4096.0f); + */ +/* gteMAC1 = (gteR<<4) + ( (gteIR0*(signed short)limA1S(gteRFC-(gteR<<4)) ) >>12); + gteMAC2 = (gteG<<4) + ( (gteIR0*(signed short)limA2S(gteGFC-(gteG<<4)) ) >>12); + gteMAC3 = (gteB<<4) + ( (gteIR0*(signed short)limA3S(gteBFC-(gteB<<4)) ) >>12);*/ + gteMAC1 = (gteR<<4) + ( (gteIR0*(signed short)FlimA1S(gteRFC-(gteR<<4)) ) >>12); + gteMAC2 = (gteG<<4) + ( (gteIR0*(signed short)FlimA2S(gteGFC-(gteG<<4)) ) >>12); + gteMAC3 = (gteB<<4) + ( (gteIR0*(signed short)FlimA3S(gteBFC-(gteB<<4)) ) >>12); + + gteFLAG = 0; + MAC2IR(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteDPCT() { +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_DPCT\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("DPCT", 17); + G_SD(8); + + G_SD(20); + G_SD(21); + G_SD(22); + + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif +/* gteFLAG = 0; + + C = gteCODE0; + R = gteR0 * 16.0; + G = gteG0 * 16.0; + B = gteB0 * 16.0; + + GTE_DPCS(); + + C = gteCODE0; + R = gteR0 * 16.0; + G = gteG0 * 16.0; + B = gteB0 * 16.0; + + GTE_DPCS(); + + C = gteCODE0; + R = gteR0 * 16.0; + G = gteG0 * 16.0; + B = gteB0 * 16.0; + + GTE_DPCS(); + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ +/* gteFLAG = 0; + + gteMAC1 = NC_OVERFLOW1((gteR0 * 16.0f) + gteIR0 * limA1S(gteRFC - (gteR0 * 16.0f))); + gteMAC2 = NC_OVERFLOW2((gteG0 * 16.0f) + gteIR0 * limA2S(gteGFC - (gteG0 * 16.0f))); + gteMAC3 = NC_OVERFLOW3((gteB0 * 16.0f) + gteIR0 * limA3S(gteBFC - (gteB0 * 16.0f))); + */ +/* gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)limA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)limA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)limA3S(gteBFC-(gteB0<<4)) ) >>12);*/ + gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)FlimA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)FlimA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)FlimA3S(gteBFC-(gteB0<<4)) ) >>12); +// MAC2IR(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + +/* gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)limA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)limA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)limA3S(gteBFC-(gteB0<<4)) ) >>12);*/ + gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)FlimA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)FlimA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)FlimA3S(gteBFC-(gteB0<<4)) ) >>12); +// MAC2IR(); + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + +/* gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)limA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)limA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)limA3S(gteBFC-(gteB0<<4)) ) >>12);*/ + gteMAC1 = (gteR0<<4) + ( (gteIR0*(signed short)FlimA1S(gteRFC-(gteR0<<4)) ) >>12); + gteMAC2 = (gteG0<<4) + ( (gteIR0*(signed short)FlimA2S(gteGFC-(gteG0<<4)) ) >>12); + gteMAC3 = (gteB0<<4) + ( (gteIR0*(signed short)FlimA3S(gteBFC-(gteB0<<4)) ) >>12); + gteFLAG = 0; + MAC2IR(); + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(20); + G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +#define LOW(a) (((a) < 0) ? 0 : (a)) + +#define GTE_NCS(vn) \ + gte_LL1 = F12limA1U((gteL11*gteVX##vn + gteL12*gteVY##vn + gteL13*gteVZ##vn) >> 12); \ + gte_LL2 = F12limA2U((gteL21*gteVX##vn + gteL22*gteVY##vn + gteL23*gteVZ##vn) >> 12); \ + gte_LL3 = F12limA3U((gteL31*gteVX##vn + gteL32*gteVY##vn + gteL33*gteVZ##vn) >> 12); \ + gteMAC1 = F12limA1U(gteRBK + ((gteLR1*gte_LL1 + gteLR2*gte_LL2 + gteLR3*gte_LL3) >> 12)); \ + gteMAC2 = F12limA2U(gteGBK + ((gteLG1*gte_LL1 + gteLG2*gte_LL2 + gteLG3*gte_LL3) >> 12)); \ + gteMAC3 = F12limA3U(gteBBK + ((gteLB1*gte_LL1 + gteLB2*gte_LL2 + gteLB3*gte_LL3) >> 12)); + +void gteNCS() { + s32 gte_LL1,gte_LL2,gte_LL3; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCS\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCS", 14); + G_SD(0); + G_SD(1); + G_SD(6); + + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + } +#endif +/* gteFLAG = 0; + + GTE_NCS(0); + + gteMAC1=(long)RR0; + gteMAC2=(long)GG0; + gteMAC3=(long)BB0; + + gteIR1=(long)t1; + gteIR2=(long)t2; + gteIR3=(long)t3; + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + gteFLAG = 0; + + GTE_NCS(0); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteNCT() { + s32 gte_LL1,gte_LL2,gte_LL3; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_NCT\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("NCT", 30); + G_SD(0); + G_SD(1); + G_SD(2); + G_SD(3); + G_SD(4); + G_SD(5); + G_SD(6); + + G_SC(8); + G_SC(9); + G_SC(10); + G_SC(11); + G_SC(12); + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + } +#endif +/* + gteFLAG = 0; + +//V0 + GTE_NCS(0); +//V1 + GTE_NCS(1); +//V2 + GTE_NCS(2); + + gteMAC1=(long)RR0; + gteMAC2=(long)GG0; + gteMAC3=(long)BB0; + + gteIR1=(long)t1; + gteIR2=(long)t2; + gteIR3=(long)t3; + + if (gteFLAG & 0x7f87e000) gteFLAG|=0x80000000;*/ + gteFLAG = 0; + + GTE_NCS(0); + + gteR0 = FlimB1(gteMAC1 >> 4); + gteG0 = FlimB2(gteMAC2 >> 4); + gteB0 = FlimB3(gteMAC3 >> 4); gteCODE0 = gteCODE; + + GTE_NCS(1); + gteR1 = FlimB1(gteMAC1 >> 4); + gteG1 = FlimB2(gteMAC2 >> 4); + gteB1 = FlimB3(gteMAC3 >> 4); gteCODE1 = gteCODE; + + GTE_NCS(2); + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + MAC2IR1(); + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + G_GD(20); + G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteCC() { + s32 RR0,GG0,BB0; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_CC\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("CC", 11); + G_SD(6); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + } +#endif + + gteFLAG = 0; + + RR0 = FNC_OVERFLOW1(gteRBK + ((gteLR1*gteIR1 + gteLR2*gteIR2 + gteLR3*gteIR3) >> 12)); + GG0 = FNC_OVERFLOW2(gteGBK + ((gteLG1*gteIR1 + gteLG2*gteIR2 + gteLG3*gteIR3) >> 12)); + BB0 = FNC_OVERFLOW3(gteBBK + ((gteLB1*gteIR1 + gteLB2*gteIR2 + gteLB3*gteIR3) >> 12)); + + gteMAC1 = (gteR * RR0) >> 8; + gteMAC2 = (gteG * GG0) >> 8; + gteMAC3 = (gteB * BB0) >> 8; + + MAC2IR1(); + + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteINTPL() { //test opcode +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif +#ifdef GTE_LOG + GTE_LOG("GTE_INTP\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("INTPL", 8); + G_SD(6); + G_SD(8); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + /* NC: old + gteFLAG=0; + gteMAC1 = gteIR1 + gteIR0*limA1S(gteRFC-gteIR1); + gteMAC2 = gteIR2 + gteIR0*limA2S(gteGFC-gteIR2); + gteMAC3 = gteIR3 + gteIR0*limA3S(gteBFC-gteIR3); + //gteFLAG = 0; + MAC2IR(); + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + + gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE; + */ + +/* gteFLAG=0; + gteMAC1 = gteIR1 + gteIR0*(gteRFC-gteIR1)/4096.0; + gteMAC2 = gteIR2 + gteIR0*(gteGFC-gteIR2)/4096.0; + gteMAC3 = gteIR3 + gteIR0*(gteBFC-gteIR3)/4096.0; + + //gteMAC3 = (int)((((psxRegs).CP2D).n).ir3+(((psxRegs).CP2D).n).ir0 * ((((psxRegs).CP2C).n).bfc-(((psxRegs).CP2D).n).ir3)/4096.0); + + if(gteMAC3 > gteIR1 && gteMAC3 > gteBFC) + { + gteMAC3 = gteMAC3; + } + //gteFLAG = 0;*/ + //NEW CODE +/* gteMAC1 = gteIR1 + ((gteIR0*(signed short)limA1S(gteRFC-gteIR1))>>12); + gteMAC2 = gteIR2 + ((gteIR0*(signed short)limA2S(gteGFC-gteIR2))>>12); + gteMAC3 = gteIR3 + ((gteIR0*(signed short)limA3S(gteBFC-gteIR3))>>12);*/ + gteMAC1 = gteIR1 + ((gteIR0*(signed short)FlimA1S(gteRFC-gteIR1))>>12); + gteMAC2 = gteIR2 + ((gteIR0*(signed short)FlimA2S(gteGFC-gteIR2))>>12); + gteMAC3 = gteIR3 + ((gteIR0*(signed short)FlimA3S(gteBFC-gteIR3))>>12); + gteFLAG = 0; + + MAC2IR(); + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} + +void gteCDP() { //test opcode + float RR0,GG0,BB0; +// s32 RR0,GG0,BB0; +#ifdef GTE_DUMP + static int sample = 0; sample++; +#endif + +#ifdef GTE_LOG + GTE_LOG("GTE_CDP\n"); +#endif + +#ifdef GTE_DUMP + if(sample < 100) + { + G_OP("CDP", 13); + G_SD(6); + G_SD(8); + G_SD(9); + G_SD(10); + G_SD(11); + + G_SC(13); + G_SC(14); + G_SC(15); + G_SC(16); + G_SC(17); + G_SC(18); + G_SC(19); + G_SC(20); + G_SC(21); + G_SC(22); + G_SC(23); + } +#endif + + gteFLAG = 0; + + RR0 = NC_OVERFLOW1(gteRBK + (gteLR1*gteIR1 +gteLR2*gteIR2 + gteLR3*gteIR3)); + GG0 = NC_OVERFLOW2(gteGBK + (gteLG1*gteIR1 +gteLG2*gteIR2 + gteLG3*gteIR3)); + BB0 = NC_OVERFLOW3(gteBBK + (gteLB1*gteIR1 +gteLB2*gteIR2 + gteLB3*gteIR3)); + gteMAC1 = gteR*RR0 + gteIR0*limA1S(gteRFC-gteR*RR0); + gteMAC2 = gteG*GG0 + gteIR0*limA2S(gteGFC-gteG*GG0); + gteMAC3 = gteB*BB0 + gteIR0*limA3S(gteBFC-gteB*BB0); + +/* RR0 = FNC_OVERFLOW1(gteRBK + (gteLR1*gteIR1 +gteLR2*gteIR2 + gteLR3*gteIR3)); + GG0 = FNC_OVERFLOW2(gteGBK + (gteLG1*gteIR1 +gteLG2*gteIR2 + gteLG3*gteIR3)); + BB0 = FNC_OVERFLOW3(gteBBK + (gteLB1*gteIR1 +gteLB2*gteIR2 + gteLB3*gteIR3)); + gteMAC1 = gteR*RR0 + gteIR0*FlimA1S(gteRFC-gteR*RR0); + gteMAC2 = gteG*GG0 + gteIR0*FlimA2S(gteGFC-gteG*GG0); + gteMAC3 = gteB*BB0 + gteIR0*FlimA3S(gteBFC-gteB*BB0);*/ + + MAC2IR1(); + gteRGB0 = gteRGB1; + gteRGB1 = gteRGB2; + +/* gteR2 = limB1(gteMAC1 / 16.0f); + gteG2 = limB2(gteMAC2 / 16.0f); + gteB2 = limB3(gteMAC3 / 16.0f); gteCODE2 = gteCODE;*/ + gteR2 = FlimB1(gteMAC1 >> 4); + gteG2 = FlimB2(gteMAC2 >> 4); + gteB2 = FlimB3(gteMAC3 >> 4); gteCODE2 = gteCODE; + + SUM_FLAG + +#ifdef GTE_DUMP + if(sample < 100) + { + G_GD(9); + G_GD(10); + G_GD(11); + + //G_GD(20); + //G_GD(21); + G_GD(22); + + G_GD(25); + G_GD(26); + G_GD(27); + + G_GC(31); + } +#endif +} diff --git a/gte.h b/gte.h new file mode 100644 index 0000000..b1036a6 --- /dev/null +++ b/gte.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __GTE_H__ +#define __GTE_H__ + +#include "psxcommon.h" +#include "r3000a.h" + +void gteMFC2(); +void gteCFC2(); +void gteMTC2(); +void gteCTC2(); +void gteLWC2(); +void gteSWC2(); + +void gteRTPS(); +void gteOP(); +void gteNCLIP(); +void gteDPCS(); +void gteINTPL(); +void gteMVMVA(); +void gteNCDS(); +void gteNCDT(); +void gteCDP(); +void gteNCCS(); +void gteCC(); +void gteNCS(); +void gteNCT(); +void gteSQR(); +void gteDCPL(); +void gteDPCT(); +void gteAVSZ3(); +void gteAVSZ4(); +void gteRTPT(); +void gteGPF(); +void gteGPL(); +void gteNCCT(); + +#endif /* __GTE_H__ */ diff --git a/mdec.c b/mdec.c new file mode 100644 index 0000000..a98c52e --- /dev/null +++ b/mdec.c @@ -0,0 +1,538 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Movie decoder. Based on the FPSE v0.08 Mdec decoder. +*/ + +#include "mdec.h" + +#define _FIXED + +#define CONST_BITS 8 +#define PASS1_BITS 2 + +#define FIX_1_082392200 (277) +#define FIX_1_414213562 (362) +#define FIX_1_847759065 (473) +#define FIX_2_613125930 (669) + +#define MULTIPLY(var,const) (DESCALE((var) * (const), CONST_BITS)) + +#define DEQUANTIZE(coef,quantval) (coef) + +#define DESCALE(x,n) ((x)>>(n)) +#define RANGE(n) (n) + +#define DCTSIZE 8 +#define DCTSIZE2 64 + +static void idct1(int *block) +{ + int val = RANGE(DESCALE(block[0], PASS1_BITS+3)); + int i; + for(i=0;i>16)*(bcr&0xffff); + + if (cmd==0x60000000) { + } else + if (cmd==0x40000001) { + u8 *p = (u8*)PSXM(adr); + iqtab_init(iq_y,p); + iqtab_init(iq_uv,p+64); + } else + if ((cmd&0xf5ff0000)==0x30000000) { + mdec.rl = (u16*)PSXM(adr); + } + else { + } + + HW_DMA0_CHCR &= SWAP32(~0x01000000); + DMA_INTERRUPT(0); +} + +void psxDma1(u32 adr, u32 bcr, u32 chcr) { + int blk[DCTSIZE2*6]; + unsigned short *image; + int size; + +#ifdef CDR_LOG + CDR_LOG("DMA1 %lx %lx %lx (cmd = %lx)\n", adr, bcr, chcr, mdec.command); +#endif + + if (chcr!=0x01000200) return; + + size = (bcr>>16)*(bcr&0xffff); + + image = (u16*)PSXM(adr); + if (mdec.command&0x08000000) { +// MDECOUTDMA_INT(((size * (1000000 / 9000)) / 4) /** 4*/ / BIAS); + MDECOUTDMA_INT((size / 4) / BIAS); + size = size / ((16*16)/2); + for (;size>0;size--,image+=(16*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb15(blk,image); + } + } else { +// MDECOUTDMA_INT(((size * (1000000 / 9000)) / 4) /** 4*/ / BIAS); + MDECOUTDMA_INT((size / 4) / BIAS); + size = size / ((24*16)/2); + for (;size>0;size--,image+=(24*16)) { + mdec.rl = rl2blk(blk,mdec.rl); + yuv2rgb24(blk,(u8 *)image); + } + } + mdec.status|= MDEC_BUSY; +} + +void mdec1Interrupt() { +#ifdef CDR_LOG + CDR_LOG("mdec1Interrupt\n"); +#endif + if (HW_DMA1_CHCR & SWAP32(0x01000000)) { + // Set a fixed value totaly arbitrarie + // another sound value is PSXCLK / 60 or + // PSXCLK / 50 since the bug happend + // at end of frame. PSXCLK / 1000 seems + // good for FF9. + // (for FF9 need < ~28000) + // CAUTION: commented interrupt-handling may lead to problems, keep an eye ;-) + MDECOUTDMA_INT(PSXCLK / 1000); + //psxRegs.interrupt|= 0x02000000; + //psxRegs.intCycle[5+24+1] *= 8; + //psxRegs.intCycle[5+24] = psxRegs.cycle; + HW_DMA1_CHCR&= SWAP32(~0x01000000); + DMA_INTERRUPT(1); + } else { + mdec.status&= ~MDEC_BUSY; + } +} + +#define RUNOF(a) ((a)>>10) +#define VALOF(a) (((int)(a)<<(32-10))>>(32-10)) + +static int zscan[DCTSIZE2] = { + 0 ,1 ,8 ,16,9 ,2 ,3 ,10, + 17,24,32,25,18,11,4 ,5 , + 12,19,26,33,40,48,41,34, + 27,20,13,6 ,7 ,14,21,28, + 35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51, + 58,59,52,45,38,31,39,46, + 53,60,61,54,47,55,62,63 +}; + +static int aanscales[DCTSIZE2] = { + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +void iqtab_init(int *iqtab,unsigned char *iq_y) { +#define CONST_BITS14 14 +#define IFAST_SCALE_BITS 2 + int i; + + for(i=0;i>(CONST_BITS14-IFAST_SCALE_BITS); + } +} + +#define NOP 0xfe00 +unsigned short* rl2blk(int *blk,unsigned short *mdec_rl) { + int i,k; + int *iqtab; + + memset (blk, 0, 6*DCTSIZE2*4); + iqtab = iq_uv; + for(i=0;i<6;i++) { // decode blocks (Cr,Cb,Y1,Y2,Y3,Y4) + if (i>1) iqtab = iq_y; + + // zigzag transformation + int rl = SWAP16(*mdec_rl); mdec_rl++; + int q_scale = RUNOF(rl); + blk[0] = iqtab[0]*VALOF(rl); + for(k = 0;;) { + rl = SWAP16(*mdec_rl); mdec_rl++; + if (rl==NOP) break; + k += RUNOF(rl)+1; // skip level zero-coefficients + if (k > 63) break; + blk[zscan[k]] = (VALOF(rl) * iqtab[k] * q_scale) / 8; // / 16; + } +// blk[0] = (blk[0] * iq_t[0] * 8) / 16; +// for(int j=1;j<64;j++) +// blk[j] = blk[j] * iq_t[j] * q_scale; + + // idct + idct(blk,k+1); + + blk+=DCTSIZE2; + } + return mdec_rl; +} + +#ifdef _FIXED +#define MULR(a) ((((int)0x0000059B) * (a)) >> 10) +#define MULG(a) ((((int)0xFFFFFEA1) * (a)) >> 10) +#define MULG2(a) ((((int)0xFFFFFD25) * (a)) >> 10) +#define MULB(a) ((((int)0x00000716) * (a)) >> 10) +#else +#define MULR(a) ((int)((float)1.40200 * (a))) +#define MULG(a) ((int)((float)-0.3437 * (a))) +#define MULG2(a) ((int)((float)-0.7143 * (a))) +#define MULB(a) ((int)((float)1.77200 * (a))) +#endif + +#define MAKERGB15(r,g,b) ( SWAP16((((r)>>3)<<10)|(((g)>>3)<<5)|((b)>>3)) ) +#define ROUND(c) roundtbl[((c)+128+256)]//&0x3ff] +/*#define ROUND(c) round(c+128) +int round(int r) { + if (r<0) return 0; + if (r>255) return 255; + return r; +}*/ + +#define RGB15(n, Y) \ + image[n] = MAKERGB15(ROUND(Y + R),ROUND(Y + G),ROUND(Y + B)); + +#define RGB15BW(n, Y) \ + image[n] = MAKERGB15(ROUND(Y),ROUND(Y),ROUND(Y)); + +#define RGB24(n, Y) \ + image[n+2] = ROUND(Y + R); \ + image[n+1] = ROUND(Y + G); \ + image[n+0] = ROUND(Y + B); + +#define RGB24BW(n, Y) \ + image[n+2] = ROUND(Y); \ + image[n+1] = ROUND(Y); \ + image[n+0] = ROUND(Y); + +unsigned char roundtbl[256*3]; + +void round_init(void) { + int i; + for(i=0;i<256;i++) { + roundtbl[i]=0; + roundtbl[i+256]=i; + roundtbl[i+512]=255; + } +} + +void yuv2rgb15(int *blk,unsigned short *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!Config.Mdec) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Crblk++,Cbblk++,Yblk+=2) { + int Cr = *Crblk; + int Cb = *Cbblk; + int R = MULR(Cr); + int G = MULG(Cb) + MULG2(Cr); + int B = MULB(Cb); + + RGB15(0, Yblk[0]); + RGB15(1, Yblk[1]); + RGB15(16, Yblk[8]); + RGB15(17, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB15(8, Yblk[DCTSIZE2+0]); + RGB15(9, Yblk[DCTSIZE2+1]); + RGB15(24, Yblk[DCTSIZE2+8]); + RGB15(25, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=2,Yblk+=2) { + RGB15BW(0, Yblk[0]); + RGB15BW(1, Yblk[1]); + RGB15BW(16, Yblk[8]); + RGB15BW(17, Yblk[9]); + + RGB15BW(8, Yblk[DCTSIZE2+0]); + RGB15BW(9, Yblk[DCTSIZE2+1]); + RGB15BW(24, Yblk[DCTSIZE2+8]); + RGB15BW(25, Yblk[DCTSIZE2+9]); + } + } +} + +void yuv2rgb24(int *blk,unsigned char *image) { + int x,y; + int *Yblk = blk+DCTSIZE2*2; + int *Cbblk = blk; + int *Crblk = blk+DCTSIZE2; + + if (!Config.Mdec) + for (y=0;y<16;y+=2,Crblk+=4,Cbblk+=4,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Crblk++,Cbblk++,Yblk+=2) { + int Cr = *Crblk; + int Cb = *Cbblk; + int R = MULR(Cr); + int G = MULG(Cb) + MULG2(Cr); + int B = MULB(Cb); + + RGB24(0, Yblk[0]); + RGB24(1*3, Yblk[1]); + RGB24(16*3, Yblk[8]); + RGB24(17*3, Yblk[9]); + + Cr = *(Crblk+4); + Cb = *(Cbblk+4); + R = MULR(Cr); + G = MULG(Cb) + MULG2(Cr); + B = MULB(Cb); + + RGB24(8*3, Yblk[DCTSIZE2+0]); + RGB24(9*3, Yblk[DCTSIZE2+1]); + RGB24(24*3, Yblk[DCTSIZE2+8]); + RGB24(25*3, Yblk[DCTSIZE2+9]); + } + } else + for (y=0;y<16;y+=2,Yblk+=8,image+=24*3) { + if (y==8) Yblk+=DCTSIZE2; + for (x=0;x<4;x++,image+=6,Yblk+=2) { + RGB24BW(0, Yblk[0]); + RGB24BW(1*3, Yblk[1]); + RGB24BW(16*3, Yblk[8]); + RGB24BW(17*3, Yblk[9]); + + RGB24BW(8*3, Yblk[DCTSIZE2+0]); + RGB24BW(9*3, Yblk[DCTSIZE2+1]); + RGB24BW(24*3, Yblk[DCTSIZE2+8]); + RGB24BW(25*3, Yblk[DCTSIZE2+9]); + } + } +} + +int mdecFreeze(gzFile f, int Mode) { + char Unused[4096]; + + gzfreeze(&mdec, sizeof(mdec)); + gzfreezel(iq_y); + gzfreezel(iq_uv); + gzfreezel(Unused); + + return 0; +} + diff --git a/mdec.h b/mdec.h new file mode 100644 index 0000000..3fa5353 --- /dev/null +++ b/mdec.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __MDEC_H__ +#define __MDEC_H__ + +#include "psxcommon.h" +#include "r3000a.h" +#include "psxhw.h" +#include "psxdma.h" + +void mdecInit(); +void mdecWrite0(u32 data); +void mdecWrite1(u32 data); +u32 mdecRead0(); +u32 mdecRead1(); +void psxDma0(u32 madr, u32 bcr, u32 chcr); +void psxDma1(u32 madr, u32 bcr, u32 chcr); +void mdec1Interrupt(); +int mdecFreeze(gzFile f, int Mode); + +#endif /* __MDEC_H__ */ diff --git a/misc.c b/misc.c new file mode 100644 index 0000000..1a3e83e --- /dev/null +++ b/misc.c @@ -0,0 +1,690 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Miscellaneous functions, including savesates and CD-ROM loading. +*/ + +#include "misc.h" +#include "cdrom.h" +#include "psxhw.h" +#include "mdec.h" +#include "Gamecube/wiiSXconfig.h" +#include "Gamecube/fileBrowser/fileBrowser-libfat.h" + +int Log = 0; + +/* PSX Executable types */ +#define PSX_EXE 1 +#define CPE_EXE 2 +#define COFF_EXE 3 +#define INVALID_EXE 4 + +#define ISODCL(from, to) (to - from + 1) + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + char name [1]; +}; + +#define btoi(b) ((b)/16*10 + (b)%16) /* BCD to u_char */ +#define itob(i) ((i)/10*16 + (i)%10) /* u_char to BCD */ + +void mmssdd( char *b, char *p ) + { + int m, s, d; +#if defined(HW_RVL) || defined(HW_DOL) || defined(BIG_ENDIAN) + int block = (b[0]&0xff) | ((b[1]&0xff)<<8) | ((b[2]&0xff)<<16) | (b[3]<<24); +#else + int block = *((int*)b); +#endif + + block += 150; + m = block / 4500; // minuten + block = block - m * 4500; // minuten rest + s = block / 75; // sekunden + d = block - s * 75; // sekunden rest + + m = ( ( m / 10 ) << 4 ) | m % 10; + s = ( ( s / 10 ) << 4 ) | s % 10; + d = ( ( d / 10 ) << 4 ) | d % 10; + + p[0] = m; + p[1] = s; + p[2] = d; +} + +#define incTime() \ + time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \ + time[2]++; \ + if(time[2] == 75) { \ + time[2] = 0; \ + time[1]++; \ + if (time[1] == 60) { \ + time[1] = 0; \ + time[0]++; \ + } \ + } \ + time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]); + +#define READTRACK() \ + if (CDR_readTrack(time) == -1) return -1; \ + buf = CDR_getBuffer(); if (buf == NULL) return -1; + +#define READDIR(_dir) \ + READTRACK(); \ + memcpy(_dir, buf+12, 2048); \ + \ + incTime(); \ + READTRACK(); \ + memcpy(_dir+2048, buf+12, 2048); + +int GetCdromFile(u8 *mdir, u8 *time, char *filename) { + struct iso_directory_record *dir; + char ddir[4096]; + u8 *buf; + int i; + + // only try to scan if a filename is given + if(!strlen((char*)filename)) return -1; + + i = 0; + while (i < 4096) { + dir = (struct iso_directory_record*) &mdir[i]; + if (dir->length[0] == 0) { + return -1; + } + i += dir->length[0]; + + if (dir->flags[0] & 0x2) { // it's a dir + if (!strnicmp((char*)&dir->name[0], (char*)filename, dir->name_len[0])) { + if (filename[dir->name_len[0]] != '\\') continue; + + filename+= dir->name_len[0] + 1; + + mmssdd(dir->extent, (char*)time); + READDIR(ddir); + i = 0; + } + } else { + if (!strnicmp((char*)&dir->name[0], (char*)filename, strlen((char*)filename))) { + mmssdd(dir->extent, (char*)time); + break; + } + } + } + return 0; +} + +int LoadCdrom() { + EXE_HEADER tmpHead; + struct iso_directory_record *dir; + u8 time[4],*buf; + u8 mdir[4096]; + + + if (!Config.HLE) { + if(!LoadCdBios) + psxRegs.pc = psxRegs.GPR.n.ra; + return 0; + } + + time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + + READTRACK(); + + // skip head and sub, and go to the root directory record + dir = (struct iso_directory_record*) &buf[12+156]; + + mmssdd(dir->extent, (char*)time); + + READDIR(mdir); + + // Load SYSTEM.CNF and scan for the main executable + if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) { + // if SYSTEM.CNF is missing, start an existing PSX.EXE + if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1; + + READTRACK(); + } + else { + // read the SYSTEM.CNF + READTRACK(); + char exename[256]; + + sscanf((char*)buf+12, "BOOT = cdrom:\\%255s", exename); + if (GetCdromFile(mdir, time, exename) == -1) { + sscanf((char*)buf+12, "BOOT = cdrom:%255s", exename); + if (GetCdromFile(mdir, time, exename) == -1) { + char *ptr = strstr((char*)buf+12, "cdrom:"); + if(ptr) { + strncpy(exename, ptr, 256); + if (GetCdromFile(mdir, time, exename) == -1) + return -1; + } + } + } + + // Read the EXE-Header + READTRACK(); + } + + + memcpy(&tmpHead, buf+12, sizeof(EXE_HEADER)); + + psxRegs.pc = SWAP32(tmpHead.pc0); + psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0); + psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); + if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00; + + tmpHead.t_size = SWAP32(tmpHead.t_size); + tmpHead.t_addr = SWAP32(tmpHead.t_addr); + + // Read the rest of the main executable + while (tmpHead.t_size) { + void *ptr = (void *)PSXM(tmpHead.t_addr); + + incTime(); + READTRACK(); + + if (ptr != NULL) memcpy(ptr, buf+12, 2048); + + tmpHead.t_size -= 2048; + tmpHead.t_addr += 2048; + } + + return 0; +} + +int LoadCdromFile(char *filename, EXE_HEADER *head) { + struct iso_directory_record *dir; + u8 time[4],*buf; + u8 mdir[4096], exename[256]; + u32 size, addr; + + sscanf(filename, "cdrom:\\%256s", exename); + + time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + + READTRACK(); + + // skip head and sub, and go to the root directory record + dir = (struct iso_directory_record*) &buf[12+156]; + + mmssdd(dir->extent, (char*)time); + + READDIR(mdir); + + if (GetCdromFile(mdir, time, (char*)exename) == -1) return -1; + + READTRACK(); + + memcpy(head, buf+12, sizeof(EXE_HEADER)); + size = head->t_size; + addr = head->t_addr; + + while (size) { + incTime(); + READTRACK(); + + memcpy((u8*)(psxMemRLUT[(addr) >> 16] + ((addr) & 0xffff)), (char*)buf+12, 2048); + + size -= 2048; + addr += 2048; + } + + return 0; +} + +int CheckCdrom() { + struct iso_directory_record *dir; + unsigned char time[4],*buf; + unsigned char mdir[4096]; + char exename[256]; + int i; + + time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10); + + READTRACK(); + + CdromLabel[32]=0; + CdromId[9]=0; + + strncpy(CdromLabel, (char*)buf+52, 32); + + // skip head and sub, and go to the root directory record + dir = (struct iso_directory_record*) &buf[12+156]; + + mmssdd(dir->extent, (char*)time); + + READDIR(mdir); + + if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) { + READTRACK(); + + sscanf((char*)buf+12, "BOOT = cdrom:\\%255s", exename); + if (GetCdromFile(mdir, time, exename) == -1) { + sscanf((char*)buf+12, "BOOT = cdrom:%255s", exename); + if (GetCdromFile(mdir, time, exename) == -1) { + char *ptr = strstr((char*)buf+12, "cdrom:"); // possibly the executable is in some subdir + for (i=0; i<32; i++) { + if (ptr[i] == ' ') continue; + if (ptr[i] == '\\') continue; + } + if(ptr) { + strncpy(exename, ptr, 256); + if (GetCdromFile(mdir, time, exename) == -1) + return -1; // main executable not found + } + } + } + } else + return -1; // SYSTEM.CNF not found + + i = strlen(exename); + if (i >= 2) { + if (exename[i - 2] == ';') i-= 2; + int c = 8; i--; + while (i >= 0 && c >= 0) { + if (isalnum((int) exename[i])) CdromId[c--] = exename[i]; + i--; + } + } + + if (Config.PsxAuto) { // autodetect system (pal or ntsc) + if (strstr(exename, "ES") != NULL) + Config.PsxType = 1; // pal + else Config.PsxType = 0; // ntsc + } + psxUpdateVSyncRate(); + if (CdromLabel[0] == ' ') { + strncpy(CdromLabel, CdromId, 9); + } + SysPrintf("CD-ROM Label: %.32s\n", CdromLabel); + SysPrintf("CD-ROM ID: %.9s\n", CdromId); + for(i = 32; i>0; i--) { + if(CdromLabel[i]==' ') { + CdromLabel[i]=0; + } + } + for(i = 9; i>0; i--) { + if(CdromId[i]==' ') { + CdromId[i]=0; + } + } + return 0; +} + +static int PSXGetFileType(fileBrowser_file *f) { + unsigned long current; + u32 mybuf[2048]; + EXE_HEADER *exe_hdr; + FILHDR *coff_hdr; + + current = f->offset; + isoFile_seekFile(f, 0, FILE_BROWSER_SEEK_SET); + isoFile_readFile(f, mybuf, 2048); + isoFile_seekFile(f, current, FILE_BROWSER_SEEK_SET); + + exe_hdr = (EXE_HEADER *)mybuf; + if (memcmp(exe_hdr->id,"PS-X EXE",8)==0) + return PSX_EXE; + + if (mybuf[0]=='C' && mybuf[1]=='P' && mybuf[2]=='E') + return CPE_EXE; + + coff_hdr = (FILHDR*)mybuf; + if (coff_hdr->f_magic == 0x0162) + return COFF_EXE; + + return INVALID_EXE; +} + +/* TODO Error handling - return integer for each error case below, defined in an enum. Pass variable on return */ +int Load(fileBrowser_file *exe) { + + EXE_HEADER tmpHead; + int temp; + int retval = 0; + + strncpy(CdromId, "Homebrew\0", 9); + strncpy(CdromLabel, "Demo\0", 5); + + if (isoFile_readFile(exe, &temp, 4) != 4) { + SysMessage(_("Error opening file: %s"), exe->name); + retval = 0; + } else { + exe->offset = 0; //reset the offset back to 0 + int type = PSXGetFileType(exe); + switch (type) { + case PSX_EXE: + isoFile_readFile(exe, &tmpHead, sizeof(EXE_HEADER)); + isoFile_seekFile(exe, 0x800, FILE_BROWSER_SEEK_SET); + isoFile_readFile(exe, (void *)PSXM(SWAP32(tmpHead.t_addr)), SWAP32(tmpHead.t_size)); + psxRegs.pc = SWAP32(tmpHead.pc0); + psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0); + psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); + if (psxRegs.GPR.n.sp == 0) + psxRegs.GPR.n.sp = 0x801fff00; + retval = 0; + break; + case CPE_EXE: + SysMessage(_("CPE files not supported.")); + retval = -1; + break; + case COFF_EXE: + SysMessage(_("COFF files not supported.")); + retval = -1; + break; + case INVALID_EXE: + SysMessage(_("This file does not appear to be a valid PSX file.")); + retval = -1; + break; + } + } + return retval; +} + +// STATES +void LoadingBar_showBar(float percent, const char* string); +const char PcsxHeader[32] = "STv3 PCSX v"; +char* statespath = "/wiisxrx/saves/"; +static unsigned int savestates_slot = 0; +extern unsigned char *psxVub; +extern unsigned short spuMem[256*1024]; +#define iGPUHeight 512 +#define SAVE_STATE_MSG "Saving State .." +#define LOAD_STATE_MSG "Loading State .." + +void savestates_select_slot(unsigned int s) +{ + if (s > 9) { + return; + } + savestates_slot = s; +} + +int SaveState() { + + gzFile f; + GPUFreeze_t *gpufP; + SPUFreeze_t *spufP; + int Size; + unsigned char *pMem; + char *filename; + + /* fix the filename to %s.st%u format */ + filename = malloc(1024); + +#ifdef HW_RVL + sprintf(filename, "%s%s%s.st%u",(saveStateDevice==SAVESTATEDEVICE_USB)?"usb:":"sd:", + statespath, CdromId, savestates_slot); +#else + sprintf(filename, "sd:%s%s.st%u", statespath, CdromId, savestates_slot); +#endif + + f = gzopen(filename, "wb"); + free(filename); + + if(!f) { + return 0; + } + + LoadingBar_showBar(0.0f, SAVE_STATE_MSG); + pauseRemovalThread(); + GPU_updateLace(); + + gzwrite(f, (void*)PcsxHeader, 32); + + pMem = (unsigned char *) malloc(128*96*3); + if (pMem == NULL) return -1; + GPU_getScreenPic(pMem); + gzwrite(f, pMem, 128*96*3); + free(pMem); + + if (Config.HLE) { + psxBiosFreeze(1); + } + LoadingBar_showBar(0.10f, SAVE_STATE_MSG); + gzwrite(f, psxM, 0x00200000); + LoadingBar_showBar(0.40f, SAVE_STATE_MSG); + gzwrite(f, psxR, 0x00080000); + LoadingBar_showBar(0.60f, SAVE_STATE_MSG); + gzwrite(f, psxH, 0x00010000); + gzwrite(f, (void*)&psxRegs, sizeof(psxRegs)); + LoadingBar_showBar(0.70f, SAVE_STATE_MSG); + // gpu + gpufP = (GPUFreeze_t *) malloc(sizeof(GPUFreeze_t)); + gpufP->ulFreezeVersion = 1; + GPU_freeze(1, gpufP); + gzwrite(f, gpufP, sizeof(GPUFreeze_t)); + free(gpufP); + // gpu VRAM save (save directly to save memory) + gzwrite(f, &psxVub[0], 1024*iGPUHeight*2); + LoadingBar_showBar(0.80f, SAVE_STATE_MSG); + // spu + spufP = (SPUFreeze_t *) malloc(16); + SPU_freeze(2, spufP); + Size = spufP->ulFreezeSize; gzwrite(f, &Size, 4); + free(spufP); + spufP = (SPUFreeze_t *) malloc(Size); + SPU_freeze(1, spufP); + gzwrite(f, spufP, Size); + free(spufP); + // spu spuMem save (save directly to save memory) + gzwrite(f, &spuMem[0], 0x80000); + LoadingBar_showBar(0.90f, SAVE_STATE_MSG); + + sioFreeze(f, 1); + cdrFreeze(f, 1); + psxHwFreeze(f, 1); + psxRcntFreeze(f, 1); + mdecFreeze(f, 1); + LoadingBar_showBar(0.99f, SAVE_STATE_MSG); + gzclose(f); + + continueRemovalThread(); + LoadingBar_showBar(1.0f, SAVE_STATE_MSG); + return 1; //ok +} + +int LoadState() { + gzFile f; + GPUFreeze_t *gpufP; + SPUFreeze_t *spufP; + int Size; + char header[32]; + char *filename; + + /* fix the filename to %s.st%u format */ + filename = malloc(1024); +#ifdef HW_RVL + sprintf(filename, "%s%s%s.st%u",(saveStateDevice==SAVESTATEDEVICE_USB)?"usb:":"sd:", + statespath, CdromId, savestates_slot); +#else + sprintf(filename, "sd:%s%s.st%u", statespath, CdromId, savestates_slot); +#endif + + f = gzopen(filename, "rb"); + free(filename); + + if(!f) { + return 0; + } + + pauseRemovalThread(); + LoadingBar_showBar(0.0f, LOAD_STATE_MSG); + //SysReset(); + + psxCpu->Reset(); + LoadingBar_showBar(0.10f, LOAD_STATE_MSG); + gzread(f, header, 32); + + if (strncmp("STv3 PCSX", header, 9)) { gzclose(f); return -1; } + + gzseek(f, 128*96*3, SEEK_CUR); + + gzread(f, psxM, 0x00200000); + LoadingBar_showBar(0.40f, LOAD_STATE_MSG); + gzread(f, psxR, 0x00080000); + LoadingBar_showBar(0.60f, LOAD_STATE_MSG); + gzread(f, psxH, 0x00010000); + gzread(f, (void*)&psxRegs, sizeof(psxRegs)); + LoadingBar_showBar(0.70f, LOAD_STATE_MSG); + if (Config.HLE) + psxBiosFreeze(0); + + // gpu + gpufP = (GPUFreeze_t *) malloc (sizeof(GPUFreeze_t)); + gzread(f, gpufP, sizeof(GPUFreeze_t)); + GPU_freeze(0, gpufP); + free(gpufP); + // gpu VRAM load (load directly to save memory) + gzread(f, &psxVub[0], 1024*iGPUHeight*2); + LoadingBar_showBar(0.80f, LOAD_STATE_MSG); + + // spu + gzread(f, &Size, 4); + spufP = (SPUFreeze_t *) malloc (Size); + gzread(f, spufP, Size); + SPU_freeze(0, spufP); + free(spufP); + // spu spuMem save (save directly to save memory) + gzread(f, &spuMem[0], 0x80000); + LoadingBar_showBar(0.99f, LOAD_STATE_MSG); + + sioFreeze(f, 0); + cdrFreeze(f, 0); + psxHwFreeze(f, 0); + psxRcntFreeze(f, 0); + mdecFreeze(f, 0); + + gzclose(f); + continueRemovalThread(); + LoadingBar_showBar(1.0f, LOAD_STATE_MSG); + + return 1; +} + +int CheckState(char *file) { + gzFile f; + char header[32]; + + f = gzopen(file, "rb"); + if (f == NULL) return -1; + + psxCpu->Reset(); + + gzread(f, header, 32); + + gzclose(f); + + if (strncmp("STv3 PCSX", header, 9)) return -1; + + return 0; +} + +// NET Function Helpers + +int SendPcsxInfo() { + if (NET_recvData == NULL || NET_sendData == NULL) + return 0; + +// SysPrintf("SendPcsxInfo\n"); + + NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING); + NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING); + NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING); + NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING); + NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING); + NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING); + +// SysPrintf("Send OK\n"); + + return 0; +} + +int RecvPcsxInfo() { + int tmp; + + if (NET_recvData == NULL || NET_sendData == NULL) + return 0; + +// SysPrintf("RecvPcsxInfo\n"); + + NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING); + NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING); + NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING); + NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING); + NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING); + psxUpdateVSyncRate(); + + SysUpdate(); + + tmp = Config.Cpu; + NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING); + if (tmp != Config.Cpu) { + psxCpu->Shutdown(); +#ifdef PSXREC + if (Config.Cpu) + psxCpu = &psxInt; + else psxCpu = &psxRec; +#else + psxCpu = &psxInt; +#endif + if (psxCpu->Init() == -1) { + SysClose(); return -1; + } + psxCpu->Reset(); + } + +// SysPrintf("Recv OK\n"); + + return 0; +} + + +void __Log(char *fmt, ...) { + va_list list; +#ifdef LOG_STDOUT + char tmp[1024]; +#endif + + va_start(list, fmt); +#ifndef LOG_STDOUT +#if defined (CPU_LOG) || defined(DMA_LOG) || defined(CDR_LOG) || defined(HW_LOG) || \ + defined(BIOS_LOG) || defined(GTE_LOG) || defined(PAD_LOG) + vfprintf(emuLog, fmt, list); +#endif +#else + vsprintf(tmp, fmt, list); + SysPrintf(tmp); +#endif + va_end(list); +} + diff --git a/misc.h b/misc.h new file mode 100644 index 0000000..dee6819 --- /dev/null +++ b/misc.h @@ -0,0 +1,71 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __MISC_H__ +#define __MISC_H__ + +#include "psxcommon.h" +#include "coff.h" +#include "plugins.h" +#include "r3000a.h" +#include "psxmem.h" +#include "Gamecube/fileBrowser/fileBrowser.h" + +#undef s_addr + +typedef struct { + unsigned char id[8]; + u32 text; + u32 data; + u32 pc0; + u32 gp0; + u32 t_addr; + u32 t_size; + u32 d_addr; + u32 d_size; + u32 b_addr; + u32 b_size; + u32 s_addr; + u32 s_size; + u32 SavedSP; + u32 SavedFP; + u32 SavedGP; + u32 SavedRA; + u32 SavedS0; +} EXE_HEADER; + +char CdromId[10]; +char CdromLabel[33]; + +int LoadCdrom(); +int LoadCdromFile(char *filename, EXE_HEADER *head); +int CheckCdrom(); +int Load(fileBrowser_file *exe); + +int SaveState(); +int LoadState(); +int CheckState(); + +int SendPcsxInfo(); +int RecvPcsxInfo(); + +extern char *LabelAuthors; +extern char *LabelGreets; + +#endif /* __MISC_H__ */ diff --git a/nopic.h b/nopic.h new file mode 100644 index 0000000..553cede --- /dev/null +++ b/nopic.h @@ -0,0 +1,1345 @@ +//////////////////////////////////////////////////////////////////////// +// following code taken from the gpuPeopsSoft +//////////////////////////////////////////////////////////////////////// + +// font 0-9, 24x20 pixels, 1 byte = 4 dots +// 00 = black +// 01 = white +// 10 = red +// 11 = transparent + +unsigned char cFont[10][120]= +{ +// 0 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 1 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 2 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 3 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 4 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x14,0x00,0x00, + 0x80,0x00,0x14,0x14,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x55,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 5 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 6 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x01,0x54,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x14,0x00,0x00,0x00, + 0x80,0x00,0x15,0x54,0x00,0x00, + 0x80,0x00,0x15,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 7 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x15,0x55,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x00,0x50,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x01,0x40,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x05,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 8 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +}, +// 9 +{0xaa,0xaa,0xaa,0xaa,0xaa,0xaa, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x05,0x54,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x05,0x00,0x00, + 0x80,0x00,0x14,0x15,0x00,0x00, + 0x80,0x00,0x05,0x55,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x05,0x00,0x00, + 0x80,0x00,0x00,0x14,0x00,0x00, + 0x80,0x00,0x05,0x50,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0x80,0x00,0x00,0x00,0x00,0x00, + 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa +} +}; + +//////////////////////////////////////////////////////////////////////// + +void PaintPicDot(unsigned char * p,unsigned char c) +{ + + if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black + if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white + if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red + // transparent +} + + ///////////////////////////////////////////////////////////////////// + // generic number/border painter + +void DrawNumBorPic(unsigned char *pMem, int lSelectedSlot) +{ + unsigned char *pf; + int x,y; + int c,v; + + pf=pMem+(103*3); // offset to number rect + + for(y=0;y<20;y++) // loop the number rect pixel + { + for(x=0;x<6;x++) + { + c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot) + v=(c&0xc0)>>6; + PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect + v=(c&0x30)>>4; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=(c&0x0c)>>2; + PaintPicDot(pf,(unsigned char)v);pf+=3; + v=c&0x03; + PaintPicDot(pf,(unsigned char)v);pf+=3; + } + pf+=104*3; // next rect y line + } + + pf=pMem; // ptr to first pos in 128x96 pic + for(x=0;x<128;x++) // loop top/bottom line + { + *(pf+(95*128*3))=0x00;*pf++=0x00; + *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red + *(pf+(95*128*3))=0xff;*pf++=0xff; + } + pf=pMem; // ptr to first pos + for(y=0;y<96;y++) // loop left/right line + { + *(pf+(127*3))=0x00;*pf++=0x00; + *(pf+(127*3))=0x00;*pf++=0x00; // paint it red + *(pf+(127*3))=0xff;*pf++=0xff; + pf+=127*3; // offset to next line + } +} + +//////////////////////////////////////////////////////////////////////// + + +/* GIMP RGB C-Source image dump (NoPic.h) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 96 * 3 + 1]; +} NoPic_Image = { + 128, 96, 3, + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0U\0\0" + "U\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8" + "\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251" + "\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0" + "\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\305" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0\214\0\0\34\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\305\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\305\0\0\34\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0""8\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\305\0\0q\0\0U\0\0U\0" + "\0U\0\0\214\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\251\0\0\251\0\0\251\0\0\251\0\0\251" + "\0\0\251\0\0\251\0\0\341\0\0\376\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\376\0\0\251\0\0U\0\0U\0\0" + "U\0\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0" + "\0\376\0\0\376\0\0\341\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\341\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\341\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\305" + "\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\341\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214" + "\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34" + "\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\0\0\0\251\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0" + "\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376" + "\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0\214\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0" + "\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0U\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0""8\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0" + "\0\0\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\214\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0" + "\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0" + "\0\376\0\0\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\214\0\0\341\0\0\376" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\34" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0" + "\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0q\0\0\0\0\0" + "\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0" + "\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0" + "\305\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\341\0\0\34\0\0\0" + "\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\341\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0" + "\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\376\0\0\376\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\305\0\0\376\0\0\376" + "\0\0q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\305\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\341\0\0\34\0\0\376\0\0\376\0\0U\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0" + "\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0\0\251" + "\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0" + "\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\34\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\305" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376" + "\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0" + "\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\214\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\376\0\0\214\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0" + "\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376" + "\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376" + "\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\376\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\214\0\0\376\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\251\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\305\0\0\376\0\0\376\0\0\376\0\0\214\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\305\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\341\0\0\376\0\0\376\0" + "\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\251\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\305\0\0\251\0\0\251\0\0\251\0\0\341\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376" + "\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0" + "U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0\341\0\0\376\0\0\376\0\0" + "\376\0\0\376\0\0\251\0\0\251\0\0\251\0\0\251\0\0\376\0\0\376\0\0\376\0\0" + "\376\0\0\341\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\376\0\0\376\0\0\376\0\0U\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0q\0\0\376\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\341\0\0q\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0U\0\0\376\0\0\376\0\0\251\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\251\0\0\376\0\0\376\0\0U\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\34\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0" + "\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\0\0U\0" + "\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0q\0\0\251\0\0\376\0\0\376\0\0\376\0\0\376\0\0\376\0\0\251\0\0q\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\34\0\0U\0\0U\0\0""8\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0U\0\0U\0\0\34\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""8\0\0\214\0\0\305\0\0\376\0\0\376\0\0\376" + "\0\0\376\0\0\341\0\0\214\0\0""8\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0", +}; + diff --git a/plugins.h b/plugins.h new file mode 100644 index 0000000..f4d3e78 --- /dev/null +++ b/plugins.h @@ -0,0 +1,340 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PLUGINS_H__ +#define __PLUGINS_H__ + +#include "psxcommon.h" +#include "spu.h" + +typedef void* HWND; +#define CALLBACK +typedef long (* GPUopen)(unsigned long *, char *, char *); +long GPU__open(void); +typedef long (* SPUopen)(void); +long SPU__open(void); +typedef long (* PADopen)(unsigned long *); +long PAD1__open(void); +long PAD2__open(void); +typedef long (* NETopen)(unsigned long *); + +#include "psemu_plugin_defs.h" +#include "decode_xa.h" + +int LoadPlugins(); +void ReleasePlugins(); +int OpenPlugins(); +void ClosePlugins(); + + +typedef unsigned long (CALLBACK* PSEgetLibType)(void); +typedef unsigned long (CALLBACK* PSEgetLibVersion)(void); +typedef char *(CALLBACK* PSEgetLibName)(void); + +///GPU PLUGIN STUFF +typedef long (CALLBACK* GPUinit)(void); +typedef long (CALLBACK* GPUshutdown)(void); +typedef long (CALLBACK* GPUclose)(void); +typedef void (CALLBACK* GPUwriteStatus)(uint32_t); +typedef void (CALLBACK* GPUwriteData)(uint32_t); +typedef void (CALLBACK* GPUwriteDataMem)(unsigned long *, int); +typedef uint32_t (CALLBACK* GPUreadStatus)(void); +typedef uint32_t (CALLBACK* GPUreadData)(void); +typedef void (CALLBACK* GPUreadDataMem)(unsigned long *, int); +typedef long (CALLBACK* GPUdmaChain)(uint32_t *,uint32_t); +typedef void (CALLBACK* GPUupdateLace)(void); +typedef long (CALLBACK* GPUconfigure)(void); +typedef long (CALLBACK* GPUtest)(void); +typedef void (CALLBACK* GPUabout)(void); +typedef void (CALLBACK* GPUmakeSnapshot)(void); +typedef void (CALLBACK* GPUkeypressed)(int); +typedef void (CALLBACK* GPUdisplayText)(char *); +typedef struct GPUFREEZETAG +{ + unsigned long ulFreezeVersion; // should be always 1 for now (set by main emu) + unsigned long ulStatus; // current gpu status + unsigned long ulControl[256]; // latest control register values + //unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN) +} GPUFreeze_t; +typedef long (CALLBACK* GPUfreeze)(uint32_t, GPUFreeze_t *); +typedef long (CALLBACK* GPUgetScreenPic)(unsigned char *); +typedef long (CALLBACK* GPUshowScreenPic)(unsigned char *); +typedef void (CALLBACK* GPUclearDynarec)(void (CALLBACK *callback)(void)); + +//plugin stuff From Shadow +// *** walking in the valley of your darking soul i realize that i was alone +//Gpu function pointers +GPUupdateLace GPU_updateLace; +GPUinit GPU_init; +GPUshutdown GPU_shutdown; +GPUconfigure GPU_configure; +GPUtest GPU_test; +GPUabout GPU_about; +GPUopen GPU_open; +GPUclose GPU_close; +GPUreadStatus GPU_readStatus; +GPUreadData GPU_readData; +GPUreadDataMem GPU_readDataMem; +GPUwriteStatus GPU_writeStatus; +GPUwriteData GPU_writeData; +GPUwriteDataMem GPU_writeDataMem; +GPUdmaChain GPU_dmaChain; +GPUkeypressed GPU_keypressed; +GPUdisplayText GPU_displayText; +GPUmakeSnapshot GPU_makeSnapshot; +GPUfreeze GPU_freeze; +GPUgetScreenPic GPU_getScreenPic; +GPUshowScreenPic GPU_showScreenPic; +GPUclearDynarec GPU_clearDynarec; + +//cd rom plugin ;) +typedef long (CALLBACK* CDRinit)(void); +typedef long (CALLBACK* CDRshutdown)(void); +typedef long (CALLBACK* CDRopen)(void); +typedef long (CALLBACK* CDRclose)(void); +typedef long (CALLBACK* CDRgetTN)(unsigned char *); +typedef long (CALLBACK* CDRgetTD)(unsigned char , unsigned char *); +typedef long (CALLBACK* CDRreadTrack)(unsigned char *); +typedef unsigned char * (CALLBACK* CDRgetBuffer)(void); +typedef long (CALLBACK* CDRconfigure)(void); +typedef long (CALLBACK* CDRtest)(void); +typedef void (CALLBACK* CDRabout)(void); +typedef long (CALLBACK* CDRplay)(unsigned char *); +typedef long (CALLBACK* CDRstop)(void); +typedef long (CALLBACK* CDRsetfilename)(char *); +struct CdrStat { + uint32_t Type; + uint32_t Status; + unsigned char Time[3]; +}; +typedef long (CALLBACK* CDRgetStatus)(struct CdrStat *); +typedef char* (CALLBACK* CDRgetDriveLetter)(void); +struct SubQ { + char res0[11]; + unsigned char ControlAndADR; + unsigned char TrackNumber; + unsigned char IndexNumber; + unsigned char TrackRelativeAddress[3]; + unsigned char Filler; + unsigned char AbsoluteAddress[3]; + char res1[72]; +}; +typedef unsigned char* (CALLBACK* CDRgetBufferSub)(void); + +//cd rom function pointers +CDRinit CDR_init; +CDRshutdown CDR_shutdown; +CDRopen CDR_open; +CDRclose CDR_close; +CDRtest CDR_test; +CDRgetTN CDR_getTN; +CDRgetTD CDR_getTD; +CDRreadTrack CDR_readTrack; +CDRgetBuffer CDR_getBuffer; +CDRplay CDR_play; +CDRstop CDR_stop; +CDRgetStatus CDR_getStatus; +CDRgetDriveLetter CDR_getDriveLetter; +CDRgetBufferSub CDR_getBufferSub; +CDRconfigure CDR_configure; +CDRabout CDR_about; +CDRsetfilename CDR_setfilename; + +// spu plugin +typedef long (CALLBACK* SPUinit)(void); +typedef long (CALLBACK* SPUshutdown)(void); +typedef long (CALLBACK* SPUclose)(void); +typedef void (CALLBACK* SPUplaySample)(unsigned char); +typedef void (CALLBACK* SPUstartChannels1)(unsigned short); +typedef void (CALLBACK* SPUstartChannels2)(unsigned short); +typedef void (CALLBACK* SPUstopChannels1)(unsigned short); +typedef void (CALLBACK* SPUstopChannels2)(unsigned short); +typedef void (CALLBACK* SPUputOne)(uint32_t,unsigned short); +typedef unsigned short (CALLBACK* SPUgetOne)(uint32_t); +typedef void (CALLBACK* SPUsetAddr)(unsigned char, unsigned short); +typedef void (CALLBACK* SPUsetPitch)(unsigned char, unsigned short); +typedef void (CALLBACK* SPUsetVolumeL)(unsigned char, short ); +typedef void (CALLBACK* SPUsetVolumeR)(unsigned char, short ); +//psemu pro 2 functions from now.. +typedef void (CALLBACK* SPUwriteRegister)(unsigned long, unsigned short); +typedef unsigned short (CALLBACK* SPUreadRegister)(unsigned long); +typedef void (CALLBACK* SPUwriteDMA)(unsigned short); +typedef unsigned short (CALLBACK* SPUreadDMA)(void); +typedef void (CALLBACK* SPUwriteDMAMem)(unsigned short *, int); +typedef void (CALLBACK* SPUreadDMAMem)(unsigned short *, int); +typedef void (CALLBACK* SPUplayADPCMchannel)(xa_decode_t *); +typedef void (CALLBACK* SPUregisterCallback)(void (CALLBACK *callback)(void)); +typedef void (CALLBACK* SPUregisterCDDAVolume)(void (*CDDAVcallback)(unsigned short,unsigned short)); +typedef long (CALLBACK* SPUconfigure)(void); +typedef long (CALLBACK* SPUtest)(void); +typedef void (CALLBACK* SPUabout)(void); +typedef struct +{ + char szSPUName[8]; + unsigned long ulFreezeVersion; + unsigned long ulFreezeSize; + unsigned char cSPUPort[0x200]; + //unsigned char cSPURam[0x80000]; + xa_decode_t xaS; +} SPUFreeze_t; +typedef long (CALLBACK* SPUfreeze)(uint32_t, SPUFreeze_t *); +typedef void (CALLBACK* SPUasync)(uint32_t); + +//SPU POINTERS +SPUconfigure SPU_configure; +SPUabout SPU_about; +SPUinit SPU_init; +SPUshutdown SPU_shutdown; +SPUtest SPU_test; +SPUopen SPU_open; +SPUclose SPU_close; +SPUplaySample SPU_playSample; +SPUstartChannels1 SPU_startChannels1; +SPUstartChannels2 SPU_startChannels2; +SPUstopChannels1 SPU_stopChannels1; +SPUstopChannels2 SPU_stopChannels2; +SPUputOne SPU_putOne; +SPUgetOne SPU_getOne; +SPUsetAddr SPU_setAddr; +SPUsetPitch SPU_setPitch; +SPUsetVolumeL SPU_setVolumeL; +SPUsetVolumeR SPU_setVolumeR; +SPUwriteRegister SPU_writeRegister; +SPUreadRegister SPU_readRegister; +SPUwriteDMA SPU_writeDMA; +SPUreadDMA SPU_readDMA; +SPUwriteDMAMem SPU_writeDMAMem; +SPUreadDMAMem SPU_readDMAMem; +SPUplayADPCMchannel SPU_playADPCMchannel; +SPUfreeze SPU_freeze; +SPUregisterCallback SPU_registerCallback; +SPUregisterCDDAVolume SPU_registerCDDAVolume; +SPUasync SPU_async; + +// PAD Functions + +typedef long (CALLBACK* PADconfigure)(void); +typedef void (CALLBACK* PADabout)(void); +typedef long (CALLBACK* PADinit)(long); +typedef long (CALLBACK* PADshutdown)(void); +typedef long (CALLBACK* PADtest)(void); +typedef long (CALLBACK* PADclose)(void); +typedef long (CALLBACK* PADquery)(void); +typedef long (CALLBACK* PADreadPort1)(PadDataS*); +typedef long (CALLBACK* PADreadPort2)(PadDataS*); +typedef long (CALLBACK* PADkeypressed)(void); +typedef unsigned char (CALLBACK* PADstartPoll)(int); +typedef unsigned char (CALLBACK* PADpoll)(unsigned char); +typedef void (CALLBACK* PADsetSensitive)(int); + +//PAD POINTERS +PADconfigure PAD1_configure; +PADabout PAD1_about; +PADinit PAD1_init; +PADshutdown PAD1_shutdown; +PADtest PAD1_test; +PADopen PAD1_open; +PADclose PAD1_close; +PADquery PAD1_query; +PADreadPort1 PAD1_readPort1; +PADkeypressed PAD1_keypressed; +PADstartPoll PAD1_startPoll; +PADpoll PAD1_poll; +PADsetSensitive PAD1_setSensitive; + +PADconfigure PAD2_configure; +PADabout PAD2_about; +PADinit PAD2_init; +PADshutdown PAD2_shutdown; +PADtest PAD2_test; +PADopen PAD2_open; +PADclose PAD2_close; +PADquery PAD2_query; +PADreadPort2 PAD2_readPort2; +PADkeypressed PAD2_keypressed; +PADstartPoll PAD2_startPoll; +PADpoll PAD2_poll; +PADsetSensitive PAD2_setSensitive; + +// NET plugin + +typedef long (CALLBACK* NETinit)(void); +typedef long (CALLBACK* NETshutdown)(void); +typedef long (CALLBACK* NETclose)(void); +typedef long (CALLBACK* NETconfigure)(void); +typedef long (CALLBACK* NETtest)(void); +typedef void (CALLBACK* NETabout)(void); +typedef void (CALLBACK* NETpause)(void); +typedef void (CALLBACK* NETresume)(void); +typedef long (CALLBACK* NETqueryPlayer)(void); +typedef long (CALLBACK* NETsendData)(void *, int, int); +typedef long (CALLBACK* NETrecvData)(void *, int, int); +typedef long (CALLBACK* NETsendPadData)(void *, int); +typedef long (CALLBACK* NETrecvPadData)(void *, int); + +typedef struct { + char EmuName[32]; + char CdromID[9]; // ie. 'SCPH12345', no \0 trailing character + char CdromLabel[11]; + void *psxMem; + GPUshowScreenPic GPU_showScreenPic; + GPUdisplayText GPU_displayText; + PADsetSensitive PAD_setSensitive; + char GPUpath[256]; // paths must be absolute + char SPUpath[256]; + char CDRpath[256]; + char MCD1path[256]; + char MCD2path[256]; + char BIOSpath[256]; // 'HLE' for internal bios + char Unused[1024]; +} netInfo; + +typedef long (CALLBACK* NETsetInfo)(netInfo *); +typedef long (CALLBACK* NETkeypressed)(int) +; + + +// NET function pointers +NETinit NET_init; +NETshutdown NET_shutdown; +NETopen NET_open; +NETclose NET_close; +NETtest NET_test; +NETconfigure NET_configure; +NETabout NET_about; +NETpause NET_pause; +NETresume NET_resume; +NETqueryPlayer NET_queryPlayer; +NETsendData NET_sendData; +NETrecvData NET_recvData; +NETsendPadData NET_sendPadData; +NETrecvPadData NET_recvPadData; +NETsetInfo NET_setInfo; +NETkeypressed NET_keypressed; + +int LoadCDRplugin(char *CDRdll); +int LoadGPUplugin(char *GPUdll); +int LoadSPUplugin(char *SPUdll); +int LoadPAD1plugin(char *PAD1dll); +int LoadPAD2plugin(char *PAD2dll); +int LoadNETplugin(char *NETdll); + +void CALLBACK clearDynarec(void); + +#endif /* __PLUGINS_H__ */ diff --git a/ppc/pR3000A.c b/ppc/pR3000A.c new file mode 100644 index 0000000..abe02f4 --- /dev/null +++ b/ppc/pR3000A.c @@ -0,0 +1,2819 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../psxcommon.h" +#include "ppc.h" +#include "reguse.h" +#include "pR3000A.h" +#include "../r3000a.h" +#include "../psxhle.h" +#include "../Gamecube/DEBUG.h" + +/* variable declarations */ +static u32 psxRecLUT[0x010000]; +static char recMem[RECMEM_SIZE] __attribute__((aligned(32))); /* the recompiled blocks will be here */ +static char recRAM[0x200000] __attribute__((aligned(32))); /* and the ptr to the blocks here */ +static char recROM[0x080000] __attribute__((aligned(32))); /* and here */ + +static u32 pc; /* recompiler pc */ +static u32 pcold; /* recompiler oldpc */ +static int count; /* recompiler intruction count */ +static int branch; /* set for branch */ +static u32 target; /* branch target */ +static u32 resp; +static u32 cop2readypc = 0; +static u32 idlecyclecount = 0; +static iRegisters iRegs[34]; + +int psxCP2time[64] = { + 2 , 16, 1 , 1 , 1 , 1 , 8 , 1 , // 00 + 1 , 1 , 1 , 1 , 6 , 1 , 1 , 1 , // 08 + 8 , 8 , 8 , 19, 13, 1 , 44, 1 , // 10 + 1 , 1 , 1 , 17, 11, 1 , 14, 1 , // 18 + 30, 1 , 1 , 1 , 1 , 1 , 1 , 1 , // 20 + 5 , 8 , 17, 1 , 1 , 5 , 6 , 1 , // 28 + 23, 1 , 1 , 1 , 1 , 1 , 1 , 1 , // 30 + 1 , 1 , 1 , 1 , 1 , 6 , 5 , 39 // 38 +}; + +static void (*recBSC[64])(); +static void (*recSPC[64])(); +static void (*recREG[32])(); +static void (*recCP0[32])(); +static void (*recCP2[64])(); +static void (*recCP2BSC[32])(); + +static HWRegister HWRegisters[NUM_HW_REGISTERS]; +static int HWRegUseCount; +static int DstCPUReg; +static int UniqueRegAlloc; + +static int GetFreeHWReg(); +static void InvalidateCPURegs(); +static void DisposeHWReg(int index); +static void FlushHWReg(int index); +static void FlushAllHWReg(); +static void MapPsxReg32(int reg); +static void FlushPsxReg32(int hwreg); +static int UpdateHWRegUsage(int hwreg, int usage); +static int GetHWReg32(int reg); +static int PutHWReg32(int reg); +static int GetSpecialIndexFromHWRegs(int which); +static int GetHWRegFromCPUReg(int cpureg); +static int MapRegSpecial(int which); +static void FlushRegSpecial(int hwreg); +static int GetHWRegSpecial(int which); +static int PutHWRegSpecial(int which); +static void recRecompile(); +static void recError(); + +// used in debug.c for dynarec free space printing +u32 dyna_used = 0; +u32 dyna_total = RECMEM_SIZE; + +/* --- Generic register mapping --- */ + +static int GetFreeHWReg() +{ + int index; + + if (DstCPUReg != -1) { + index = GetHWRegFromCPUReg(DstCPUReg); + DstCPUReg = -1; + } else { + int i; + // LRU algorith with a twist ;) + for (i=0; i= 13) { + index = i; + break; + } + else if (HWRegisters[i].lastUsed < least) { + least = HWRegisters[i].lastUsed; + index = i; + } + } + } + + // Cycle the registers + if (HWRegisters[index].usage == HWUSAGE_NONE) { + for (; i= 13 && + HWRegisters[i].lastUsed < least) { + least = HWRegisters[i].lastUsed; + index = i; + break; + } + } + } + } + } + +/* if (HWRegisters[index].code < 13 && HWRegisters[index].code > 3) { + SysPrintf("Allocating volatile register %i\n", HWRegisters[index].code); + } + if (HWRegisters[index].usage != HWUSAGE_NONE) { + SysPrintf("RegUse too big. Flushing %i\n", HWRegisters[index].code); + }*/ + if (HWRegisters[index].usage & (HWUSAGE_RESERVED | HWUSAGE_HARDWIRED)) { + if (HWRegisters[index].usage & HWUSAGE_RESERVED) { + SysPrintf("Error! Trying to map a new register to a reserved register (r%i)", + HWRegisters[index].code); + } + if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) { + SysPrintf("Error! Trying to map a new register to a hardwired register (r%i)", + HWRegisters[index].code); + } + } + + if (HWRegisters[index].lastUsed != 0) { + UniqueRegAlloc = 0; + } + + // Make sure the register is really flushed! + FlushHWReg(index); + HWRegisters[index].usage = HWUSAGE_NONE; + HWRegisters[index].flush = NULL; + + return index; +} + +static void FlushHWReg(int index) +{ + if (index < 0) return; + if (HWRegisters[index].usage == HWUSAGE_NONE) return; + + if (HWRegisters[index].flush) { + HWRegisters[index].usage |= HWUSAGE_RESERVED; + HWRegisters[index].flush(index); + HWRegisters[index].flush = NULL; + } + + if (HWRegisters[index].usage & HWUSAGE_HARDWIRED) { + HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE); + } else { + HWRegisters[index].usage = HWUSAGE_NONE; + } +} + +// get rid of a mapped register without flushing the contents to the memory +static void DisposeHWReg(int index) +{ + if (index < 0) return; + if (HWRegisters[index].usage == HWUSAGE_NONE) return; + + HWRegisters[index].usage &= ~(HWUSAGE_READ | HWUSAGE_WRITE); + if (HWRegisters[index].usage == HWUSAGE_NONE) { + SysPrintf("Error! not correctly disposing register (r%i)", HWRegisters[index].code); + } + + FlushHWReg(index); +} + +// operated on cpu registers +__inline static void FlushCPURegRange(int start, int end) +{ + int i; + + if (end <= 0) end = 31; + if (start <= 0) start = 0; + + for (i=0; i= start && HWRegisters[i].code <= end) + if (HWRegisters[i].flush) + FlushHWReg(i); + } + + for (i=0; i= start && HWRegisters[i].code <= end) + FlushHWReg(i); + } +} + +static void FlushAllHWReg() +{ + FlushCPURegRange(0,31); +} + +static void InvalidateCPURegs() +{ + FlushCPURegRange(0,12); +} + +/* --- Mapping utility functions --- */ + +static void MoveHWRegToCPUReg(int cpureg, int hwreg) +{ + int dstreg; + + if (HWRegisters[hwreg].code == cpureg) + return; + + dstreg = GetHWRegFromCPUReg(cpureg); + + HWRegisters[dstreg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG); + if (HWRegisters[hwreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) { + FlushHWReg(dstreg); + MR(HWRegisters[dstreg].code, HWRegisters[hwreg].code); + } else { + if (HWRegisters[dstreg].usage & (HWUSAGE_READ | HWUSAGE_WRITE)) { + MR(HWRegisters[hwreg].code, HWRegisters[dstreg].code); + } + else if (HWRegisters[dstreg].usage != HWUSAGE_NONE) { + FlushHWReg(dstreg); + } + } + + HWRegisters[dstreg].code = HWRegisters[hwreg].code; + HWRegisters[hwreg].code = cpureg; +} + +static int UpdateHWRegUsage(int hwreg, int usage) +{ + HWRegisters[hwreg].lastUsed = ++HWRegUseCount; + if (usage & HWUSAGE_WRITE) { + HWRegisters[hwreg].usage &= ~HWUSAGE_CONST; + } + if (!(usage & HWUSAGE_INITED)) { + HWRegisters[hwreg].usage &= ~HWUSAGE_INITED; + } + HWRegisters[hwreg].usage |= usage; + + return HWRegisters[hwreg].code; +} + +static int GetHWRegFromCPUReg(int cpureg) +{ + int i; + for (i=0; i= 0) { + if (HWRegisters[index].usage & HWUSAGE_WRITE) + break; + } + index = MapRegSpecial(which); + HWRegisters[index].flush = NULL; + break; + default: + if (index == -1) { + usage |= HWUSAGE_INITED; + index = MapRegSpecial(which); + + HWRegisters[index].usage |= HWUSAGE_RESERVED; + switch (which) { + case ARG1: + case ARG2: + case ARG3: + MoveHWRegToCPUReg(3+(which-ARG1), index); + /*reg = GetHWRegFromCPUReg(3+(which-ARG1)); + + if (HWRegisters[reg].usage != HWUSAGE_NONE) { + HWRegisters[reg].usage &= ~(HWUSAGE_HARDWIRED | HWUSAGE_ARG); + if (HWRegisters[reg].flush != NULL && HWRegisters[reg].usage & (HWUSAGE_WRITE | HWUSAGE_READ)) { + MR(HWRegisters[index].code, HWRegisters[reg].code); + } else { + FlushHWReg(reg); + } + } + HWRegisters[reg].code = HWRegisters[index].code; + if (!(HWRegisters[index].code >= 3 && HWRegisters[index].code <=31)) + SysPrintf("Error! Register allocation"); + HWRegisters[index].code = 3+(which-ARG1);*/ + HWRegisters[index].flush = NULL; + + usage |= HWUSAGE_RESERVED | HWUSAGE_HARDWIRED | HWUSAGE_ARG; + break; + } + } + HWRegisters[index].usage &= ~HWUSAGE_RESERVED; + break; + } + + DstCPUReg = -1; + + return UpdateHWRegUsage(index, usage); +} + +static void MapConst(int reg, u32 _const) { + if (reg == 0) + return; + if (IsConst(reg) && iRegs[reg].k == _const) + return; + + DisposeHWReg(iRegs[reg].reg); + iRegs[reg].k = _const; + iRegs[reg].state = ST_CONST; +} + +static void MapCopy(int dst, int src) +{ + // do it the lazy way for now + MR(PutHWReg32(dst), GetHWReg32(src)); +} + +static void iFlushReg(u32 nextpc, int reg) { + if (!IsMapped(reg) && IsConst(reg)) { + GetHWReg32(reg); + } + if (IsMapped(reg)) { + if (nextpc) { + int use = nextPsxRegUse(nextpc, reg); + if ((use & REGUSE_RW) == REGUSE_WRITE) { + DisposeHWReg(iRegs[reg].reg); + } else { + FlushHWReg(iRegs[reg].reg); + } + } else { + FlushHWReg(iRegs[reg].reg); + } + } +} + +static void iFlushRegs(u32 nextpc) { + int i; + + for (i=1; i> 26; + switch (tmp) { + case 0x10: // COP0 + switch (_Rs_) { + case 0x00: // MFC0 + case 0x02: // CFC0 + return 1; + } + break; + case 0x12: // COP2 + switch (_Funct_) { + case 0x00: + switch (_Rs_) { + case 0x00: // MFC2 + case 0x02: // CFC2 + return 1; + } + break; + } + break; + case 0x32: // LWC2 + return 1; + default: + if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR + return 1; + } + break; + } + return 0; +} + +/* set a pending branch */ +static void SetBranch() { + int treg; + branch = 1; + psxRegs.code = PSXMu32(pc); + pc+=4; + + if (iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = idlecyclecount + (pc - pcold)/4; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + treg = GetHWRegSpecial(TARGET); + MR(PutHWRegSpecial(ARG2), treg); + DisposeHWReg(GetHWRegFromCPUReg(treg)); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + recBSC[psxRegs.code>>26](); + + iFlushRegs(0); + treg = GetHWRegSpecial(TARGET); + MR(PutHWRegSpecial(PSXPC), GetHWRegSpecial(TARGET)); // FIXME: this line should not be needed + DisposeHWReg(GetHWRegFromCPUReg(treg)); + FlushAllHWReg(); + + count = idlecyclecount + (pc - pcold)/4; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + // TODO: don't return if target is compiled + Return(); +} + +static void iJump(u32 branchPC) { + u32 *b1, *b2; + branch = 1; + psxRegs.code = PSXMu32(pc); + pc+=4; + + if (iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = idlecyclecount + (pc - pcold)/4; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + LIW(PutHWRegSpecial(ARG2), branchPC); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + recBSC[psxRegs.code>>26](); + + iFlushRegs(branchPC); + LIW(PutHWRegSpecial(PSXPC), branchPC); + FlushAllHWReg(); + + count = idlecyclecount + (pc - pcold)/4; + //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) { + // LIW(PutHWRegSpecial(CYCLECOUNT), 0); + //} else { + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + //} + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + if (!Config.HLE && Config.PsxOut && + ((branchPC & 0x1fffff) == 0xa0 || + (branchPC & 0x1fffff) == 0xb0 || + (branchPC & 0x1fffff) == 0xc0)) + CALLFunc((u32)psxJumpTest); + + // always return for now... + //Return(); + + // maybe just happened an interruption, check so + LIW(0, branchPC); + CMPLW(GetHWRegSpecial(PSXPC), 0); + BNE_L(b1); + + LIW(3, PC_REC(branchPC)); + LWZ(3, 0, 3); + CMPLWI(3, 0); + BNE_L(b2); + + B_DST(b1); + Return(); + + // next bit is already compiled - jump right to it + B_DST(b2); + MTCTR(3); + BCTR(); +} + +static void iBranch(u32 branchPC, int savectx) { + HWRegister HWRegistersS[NUM_HW_REGISTERS]; + iRegisters iRegsS[NUM_REGISTERS]; + int HWRegUseCountS = 0; + u32 respold=0; + u32 *b1, *b2; + + if (savectx) { + respold = resp; + memcpy(iRegsS, iRegs, sizeof(iRegs)); + memcpy(HWRegistersS, HWRegisters, sizeof(HWRegisters)); + HWRegUseCountS = HWRegUseCount; + } + + branch = 1; + psxRegs.code = PSXMu32(pc); + + // the delay test is only made when the branch is taken + // savectx == 0 will mean that :) + if (savectx == 0 && iLoadTest() == 1) { + iFlushRegs(0); + LIW(0, psxRegs.code); + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); + /* store cycle */ + count = idlecyclecount + ((pc+4) - pcold)/4; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + + LIW(PutHWRegSpecial(ARG2), branchPC); + LIW(PutHWRegSpecial(ARG1), _Rt_); + LIW(GetHWRegSpecial(PSXPC), pc); + FlushAllHWReg(); + CALLFunc((u32)psxDelayTest); + + Return(); + return; + } + + pc+= 4; + recBSC[psxRegs.code>>26](); + + iFlushRegs(branchPC); + LIW(PutHWRegSpecial(PSXPC), branchPC); + FlushAllHWReg(); + + /* store cycle */ + count = idlecyclecount + (pc - pcold)/4; + //if (/*psxRegs.code == 0 &&*/ count == 2 && branchPC == pcold) { + // LIW(PutHWRegSpecial(CYCLECOUNT), 0); + //} else { + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + //} + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + + // always return for now... + //Return(); + + LIW(0, branchPC); + CMPLW(GetHWRegSpecial(PSXPC), 0); + BNE_L(b1); + + LIW(3, PC_REC(branchPC)); + LWZ(3, 0, 3); + CMPLWI(3, 0); + BNE_L(b2); + + B_DST(b1); + Return(); + + B_DST(b2); + MTCTR(3); + BCTR(); + + // maybe just happened an interruption, check so +/* CMP32ItoM((u32)&psxRegs.pc, branchPC); + j8Ptr[1] = JE8(0); + RET(); + + x86SetJ8(j8Ptr[1]); + MOV32MtoR(EAX, PC_REC(branchPC)); + TEST32RtoR(EAX, EAX); + j8Ptr[2] = JNE8(0); + RET(); + + x86SetJ8(j8Ptr[2]); + JMP32R(EAX);*/ + + pc-= 4; + if (savectx) { + resp = respold; + memcpy(iRegs, iRegsS, sizeof(iRegs)); + memcpy(HWRegisters, HWRegistersS, sizeof(HWRegisters)); + HWRegUseCount = HWRegUseCountS; + } +} + + +void iDumpRegs() { + int i, j; + + printf("%08x %08x\n", psxRegs.pc, psxRegs.cycle); + for (i=0; i<4; i++) { + for (j=0; j<8; j++) + printf("%08x ", psxRegs.GPR.r[j*i]); + printf("\n"); + } +} + +void iDumpBlock(char *ptr) { +/* FILE *f; + u32 i; + + SysPrintf("dump1 %x:%x, %x\n", psxRegs.pc, pc, psxCurrentCycle); + + for (i = psxRegs.pc; i < pc; i+=4) + SysPrintf("%s\n", disR3000AF(PSXMu32(i), i)); + + fflush(stdout); + f = fopen("dump1", "w"); + fwrite(ptr, 1, (u32)x86Ptr - (u32)ptr, f); + fclose(f); + system("ndisasmw -u dump1"); + fflush(stdout);*/ +} + +#define REC_FUNC(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ +/* branch = 2; */\ +} + +#define REC_SYS(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ + branch = 2; \ + iRet(); \ +} + +#define REC_BRANCH(f) \ +void psx##f(); \ +static void rec##f() { \ + iFlushRegs(0); \ + LIW(PutHWRegSpecial(ARG1), (u32)psxRegs.code); \ + STW(GetHWRegSpecial(ARG1), OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + LIW(PutHWRegSpecial(PSXPC), (u32)pc); \ + FlushAllHWReg(); \ + CALLFunc((u32)psx##f); \ + branch = 2; \ + iRet(); \ +} + +#define CP2_FUNC(f) \ +void gte##f(); \ +static void rec##f() { \ + if (pc < cop2readypc) idlecyclecount += ((cop2readypc - pc)>>2); \ + iFlushRegs(0); \ + LIW(0, (u32)psxRegs.code); \ + STW(0, OFFSET(&psxRegs, &psxRegs.code), GetHWRegSpecial(PSXREGS)); \ + FlushAllHWReg(); \ + CALLFunc ((u32)gte##f); \ + cop2readypc = pc + (psxCP2time[_fFunct_(psxRegs.code)]<<2); \ +} + +#define CP2_FUNCNC(f) \ +void gte##f(); \ +static void rec##f() { \ + if (pc < cop2readypc) idlecyclecount += ((cop2readypc - pc)>>2); \ + iFlushRegs(0); \ + CALLFunc ((u32)gte##f); \ +/* branch = 2; */\ + cop2readypc = pc + psxCP2time[_fFunct_(psxRegs.code)]; \ +} + +static int allocMem() { + int i; + + for (i=0; i<0x80; i++) psxRecLUT[i + 0x0000] = (u32)&recRAM[(i & 0x1f) << 16]; + memcpy(psxRecLUT + 0x8000, psxRecLUT, 0x80 * 4); + memcpy(psxRecLUT + 0xa000, psxRecLUT, 0x80 * 4); + + for (i=0; i<0x08; i++) psxRecLUT[i + 0xbfc0] = (u32)&recROM[i << 16]; + + return 0; +} + +static int recInit() { + return allocMem(); +} + +static void recReset() { + memset(recRAM, 0, 0x200000); + memset(recROM, 0, 0x080000); + + ppcInit(); + ppcSetPtr((u32 *)recMem); + + branch = 0; + memset(iRegs, 0, sizeof(iRegs)); + iRegs[0].state = ST_CONST; + iRegs[0].k = 0; +} + +static void recShutdown() { + ppcShutdown(); +} + +static void recError() { + SysReset(); + ClosePlugins(); + SysMessage("Unrecoverable error while running recompiler\n"); + SysRunGui(); +} + +__inline static void execute() { + void (**recFunc)(); + char *p; + + p = (char*)PC_REC(psxRegs.pc); + /*if (p != NULL)*/ recFunc = (void (**)()) (u32)p; + /*else { recError(); return; }*/ + + if (*recFunc == 0) { + recRecompile(); + } + recRun(*recFunc, (u32)&psxRegs, (u32)&psxM); +} + +static void recExecute() { + while(!stop) execute(); +} + +static void recExecuteBlock() { + execute(); +} + +static void recClear(u32 Addr, u32 Size) { + memset((void*)PC_REC(Addr), 0, Size * 4); +} + +static void recNULL() { +// SysMessage("recUNK: %8.8x\n", psxRegs.code); +} + +/********************************************************* +* goes to opcodes tables... * +* Format: table[something....] * +*********************************************************/ + +//REC_SYS(SPECIAL); +static void recSPECIAL() { + recSPC[_Funct_](); +} + +static void recREGIMM() { + recREG[_Rt_](); +} + +static void recCOP0() { + recCP0[_Rs_](); +} + +//REC_SYS(COP2); +static void recCOP2() { + recCP2[_Funct_](); +} + +static void recBASIC() { + recCP2BSC[_Rs_](); +} + +//end of Tables opcodes... + +/* - Arithmetic with immediate operand - */ +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ + +static void recADDIU() { +// Rt = Rs + Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k + _Imm_); + } else { + if (_Imm_ == 0) { + MapCopy(_Rt_, _Rs_); + } else { + ADDI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _Imm_); + } + } +} + +static void recADDI() { +// Rt = Rs + Im + recADDIU(); +} + +//CR0: SIGN | POSITIVE | ZERO | SOVERFLOW | SOVERFLOW | OVERFLOW | CARRY +static void recSLTI() { +// Rt = Rs < Im (signed) + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, (s32)iRegs[_Rs_].k < _Imm_); + } else { + if (_Imm_ == 0) { + SRWI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), 31); + } else { + int reg; + CMPWI(GetHWReg32(_Rs_), _Imm_); + reg = PutHWReg32(_Rt_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } + } +} + +static void recSLTIU() { +// Rt = Rs < Im (unsigned) + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k < _ImmU_); + } else { + int reg; + CMPLWI(GetHWReg32(_Rs_), _Imm_); + reg = PutHWReg32(_Rt_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } +} + +static void recANDI() { +// Rt = Rs And Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k & _ImmU_); + } else { + ANDI_(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } +} + +static void recORI() { +// Rt = Rs Or Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k | _ImmU_); + } else { + if (_Imm_ == 0) { + MapCopy(_Rt_, _Rs_); + } else { + ORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } + } +} + +static void recXORI() { +// Rt = Rs Xor Im + if (!_Rt_) return; + + if (IsConst(_Rs_)) { + MapConst(_Rt_, iRegs[_Rs_].k ^ _ImmU_); + } else { + XORI(PutHWReg32(_Rt_), GetHWReg32(_Rs_), _ImmU_); + } +} + +//end of * Arithmetic with immediate operand + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ + +static void recLUI() { +// Rt = Imm << 16 + if (!_Rt_) return; + + MapConst(_Rt_, psxRegs.code << 16); +} + +//End of Load Higher ..... + +/* - Register arithmetic - */ +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ + +static void recADDU() { +// Rd = Rs + Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k + iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), (s16)iRegs[_Rs_].k); + } else if ((iRegs[_Rs_].k & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k>>16); + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (s16)iRegs[_Rt_].k); + } else if ((iRegs[_Rt_].k & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k>>16); + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + ADD(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recADD() { +// Rd = Rs + Rt + recADDU(); +} + +static void recSUBU() { +// Rd = Rs - Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k - iRegs[_Rt_].k); + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((s32)(s16)(-iRegs[_Rt_].k) == (s32)(-iRegs[_Rt_].k)) { + ADDI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), -iRegs[_Rt_].k); + } else if (((-iRegs[_Rt_].k) & 0xffff) == 0) { + ADDIS(PutHWReg32(_Rd_), GetHWReg32(_Rs_), (-iRegs[_Rt_].k)>>16); + } else { + SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + SUB(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recSUB() { +// Rd = Rs - Rt + recSUBU(); +} + +static void recAND() { +// Rd = Rs And Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k & iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + // TODO: implement shifted (ANDIS) versions of these + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + ANDI_(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + AND(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recOR() { +// Rd = Rs Or Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k | iRegs[_Rt_].k); + } + else { + if (_Rs_ == _Rt_) { + MapCopy(_Rd_, _Rs_); + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + ORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + ORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + OR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recXOR() { +// Rd = Rs Xor Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k ^ iRegs[_Rt_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + XORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + XORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else { + XOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recNOR() { +// Rd = Rs Nor Rt + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, ~(iRegs[_Rs_].k | iRegs[_Rt_].k)); + } /*else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + NORI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + NORI(PutHWReg32(_Rd_), GetHWReg32(_Rs_), iRegs[_Rt_].k); + } else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } */else { + NOR(PutHWReg32(_Rd_), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } +} + +static void recSLT() { +// Rd = Rs < Rt (signed) + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, (s32)iRegs[_Rs_].k < (s32)iRegs[_Rt_].k); + } else { // TODO: add immidiate cases + int reg; + CMPW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + reg = PutHWReg32(_Rd_); + LI(reg, 1); + BLT(1); + LI(reg, 0); + } +} + +static void recSLTU() { +// Rd = Rs < Rt (unsigned) + if (!_Rd_) return; + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rs_].k < iRegs[_Rt_].k); + } else { // TODO: add immidiate cases + SUBFC(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + SUBFE(PutHWReg32(_Rd_), GetHWReg32(_Rd_), GetHWReg32(_Rd_)); + NEG(PutHWReg32(_Rd_), GetHWReg32(_Rd_)); + } +} + +//End of * Register arithmetic + +/* - mult/div & Register trap logic - */ +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ + +int DoShift(u32 k) +{ + u32 i; + for (i=0; i<30; i++) { + if (k == (1ul << i)) + return i; + } + return -1; +} + +// FIXME: doesn't work in GT - wrong way marker +static void recMULT() { +// Lo/Hi = Rs * Rt (signed) + s32 k; int r; + int usehi, uselo; + + if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) || + (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + u64 res = (s64)((s64)(s32)iRegs[_Rs_].k * (s64)(s32)iRegs[_Rt_].k); + MapConst(REG_LO, (res & 0xffffffff)); + MapConst(REG_HI, ((res >> 32) & 0xffffffff)); + return; + } + + if (IsConst(_Rs_)) { + k = (s32)iRegs[_Rs_].k; + r = _Rt_; + } else if (IsConst(_Rt_)) { + k = (s32)iRegs[_Rt_].k; + r = _Rs_; + } else { + r = -1; + k = 0; + } + + // FIXME: this should not be needed!!! +// uselo = isPsxRegUsed(pc, REG_LO); +// usehi = isPsxRegUsed(pc, REG_HI); + uselo = 1; //isPsxRegUsed(pc, REG_LO); + usehi = 1; //isPsxRegUsed(pc, REG_HI); + + + if (r != -1) { + int shift = DoShift(k); + if (shift != -1) { + if (uselo) { + SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift) + } + if (usehi) { + SRAWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift); + } + } else { + //if ((s32)(s16)k == k) { + // MULLWI(PutHWReg32(REG_LO), GetHWReg32(r), k); + // MULHWI(PutHWReg32(REG_HI), GetHWReg32(r), k); + //} else + { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + } + } else { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHW(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recMULTU() { +// Lo/Hi = Rs * Rt (unsigned) + u32 k; int r; + int usehi, uselo; + + if ((IsConst(_Rs_) && iRegs[_Rs_].k == 0) || + (IsConst(_Rt_) && iRegs[_Rt_].k == 0)) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + + if (IsConst(_Rs_) && IsConst(_Rt_)) { + u64 res = (u64)((u64)(u32)iRegs[_Rs_].k * (u64)(u32)iRegs[_Rt_].k); + MapConst(REG_LO, (res & 0xffffffff)); + MapConst(REG_HI, ((res >> 32) & 0xffffffff)); + return; + } + + if (IsConst(_Rs_)) { + k = (s32)iRegs[_Rs_].k; + r = _Rt_; + } else if (IsConst(_Rt_)) { + k = (s32)iRegs[_Rt_].k; + r = _Rs_; + } else { + r = -1; + k = 0; + } + + uselo = isPsxRegUsed(pc, REG_LO); + usehi = isPsxRegUsed(pc, REG_HI); + + if (r != -1) { + int shift = DoShift(k); + if (shift != -1) { + if (uselo) { + SLWI(PutHWReg32(REG_LO), GetHWReg32(r), shift); + } + if (usehi) { + SRWI(PutHWReg32(REG_HI), GetHWReg32(r), 31-shift); + } + } else { + { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + } + } else { + if (uselo) { + MULLW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + if (usehi) { + MULHWU(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } +} + +static void recDIV() { +// Lo/Hi = Rs / Rt (signed) + int usehi; + + if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(REG_LO, (s32)iRegs[_Rs_].k / (s32)iRegs[_Rt_].k); + MapConst(REG_HI, (s32)iRegs[_Rs_].k % (s32)iRegs[_Rt_].k); + return; + } + + usehi = isPsxRegUsed(pc, REG_HI); + + if (IsConst(_Rt_)) { + int shift = DoShift(iRegs[_Rt_].k); + if (shift != -1) { + SRAWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift); + ADDZE(PutHWReg32(REG_LO), GetHWReg32(REG_LO)); + if (usehi) { + RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, (31-shift), 31); + } + } else if (iRegs[_Rt_].k == 3) { + // http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html + LIS(PutHWReg32(REG_HI), 0x5555); + ADDI(PutHWReg32(REG_HI), GetHWReg32(REG_HI), 0x5556); + MULHW(PutHWReg32(REG_LO), GetHWReg32(REG_HI), GetHWReg32(_Rs_)); + SRWI(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 31); + ADD(PutHWReg32(REG_LO), GetHWReg32(REG_LO), GetHWReg32(REG_HI)); + if (usehi) { + MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), 3); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } else { + DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + if ((iRegs[_Rt_].k & 0x7fff) == iRegs[_Rt_].k) { + MULLI(PutHWReg32(REG_HI), GetHWReg32(REG_LO), iRegs[_Rt_].k); + } else { + MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_)); + } + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } + } else { + DIVW(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(REG_LO), GetHWReg32(_Rt_)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } +} + +static void recDIVU() { +// Lo/Hi = Rs / Rt (unsigned) + int usehi; + + if (IsConst(_Rs_) && iRegs[_Rs_].k == 0) { + MapConst(REG_LO, 0); + MapConst(REG_HI, 0); + return; + } + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(REG_LO, (u32)iRegs[_Rs_].k / (u32)iRegs[_Rt_].k); + MapConst(REG_HI, (u32)iRegs[_Rs_].k % (u32)iRegs[_Rt_].k); + return; + } + + usehi = isPsxRegUsed(pc, REG_HI); + + if (IsConst(_Rt_)) { + int shift = DoShift(iRegs[_Rt_].k); + if (shift != -1) { + SRWI(PutHWReg32(REG_LO), GetHWReg32(_Rs_), shift); + if (usehi) { + RLWINM(PutHWReg32(REG_HI), GetHWReg32(_Rs_), 0, (31-shift), 31); + } + } else { + DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } + } else { + DIVWU(PutHWReg32(REG_LO), GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + if (usehi) { + MULLW(PutHWReg32(REG_HI), GetHWReg32(_Rt_), GetHWReg32(REG_LO)); + SUB(PutHWReg32(REG_HI), GetHWReg32(_Rs_), GetHWReg32(REG_HI)); + } + } +} + +//End of * Register mult/div & Register trap logic + +/* - memory access - */ + +static void preMemRead() +{ + int rs; + + ReserveArgs(1); + if (_Rs_ != _Rt_) { + DisposeHWReg(iRegs[_Rt_].reg); + } + rs = GetHWReg32(_Rs_); + if (rs != 3 || _Imm_ != 0) { + ADDI(PutHWRegSpecial(ARG1), rs, _Imm_); + } + if (_Rs_ == _Rt_) { + DisposeHWReg(iRegs[_Rt_].reg); + } + InvalidateCPURegs(); + //FlushAllHWReg(); +} + +static void preMemWrite(int size) +{ + int rs; + + ReserveArgs(2); + rs = GetHWReg32(_Rs_); + if (rs != 3 || _Imm_ != 0) { + ADDI(PutHWRegSpecial(ARG1), rs, _Imm_); + } + if (size == 1) { + RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 24, 31); + //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xff); + } else if (size == 2) { + RLWINM(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0, 16, 31); + //ANDI_(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_), 0xffff); + } else { + MR(PutHWRegSpecial(ARG2), GetHWReg32(_Rt_)); + } + + InvalidateCPURegs(); + //FlushAllHWReg(); +} + +static void recLB() { +// Rt = mem[Rs + Im] (signed) + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRs8(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LBZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LBZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSB(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r8 %x\n", addr); + }*/ + + preMemRead(); + CALLFunc((u32)psxMemRead8); + if (_Rt_) { + EXTSB(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL)); + DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL)); + } +} + +static void recLBU() { +// Rt = mem[Rs + Im] (unsigned) + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu8(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LBZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LBZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r8 %x\n", addr); + }*/ + + preMemRead(); + CALLFunc((u32)psxMemRead8); + + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +static void recLH() { +// Rt = mem[Rs + Im] (signed) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRs16(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + EXTSH(PutHWReg32(_Rt_), GetHWReg32(_Rt_)); + return; + } + // SysPrintf("unhandled r16 %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead16); + if (_Rt_) { + EXTSH(PutHWReg32(_Rt_), GetHWRegSpecial(RETVAL)); + DisposeHWReg(GetSpecialIndexFromHWRegs(RETVAL)); + } +} + +static void recLHU() { +// Rt = mem[Rs + Im] (unsigned) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu16(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LHBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80) { + if (addr >= 0x1f801c00 && addr < 0x1f801e00) { + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), addr); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)SPU_readRegister); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + } + switch (addr) { + case 0x1f801100: case 0x1f801110: case 0x1f801120: + if (!_Rt_) return; + + ReserveArgs(1); + LIW(PutHWRegSpecial(ARG1), (addr >> 4) & 0x3); + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)psxRcntRcount); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + + case 0x1f801104: case 0x1f801114: case 0x1f801124: + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxCounters[(addr >> 4) & 0x3].mode); + LWZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + + case 0x1f801108: case 0x1f801118: case 0x1f801128: + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxCounters[(addr >> 4) & 0x3].target); + LWZ(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + } + // SysPrintf("unhandled r16u %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead16); + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +static void recLW() { +// Rt = mem[Rs + Im] (unsigned) + + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0xfff0) == 0xbfc0) { + if (!_Rt_) return; + // since bios is readonly it won't change + MapConst(_Rt_, psxRu32(addr)); + return; + } + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxM[addr & 0x1fffff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xfff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + } + if (t == 0x1f80) { + switch (addr) { + case 0x1f801080: case 0x1f801084: case 0x1f801088: + case 0x1f801090: case 0x1f801094: case 0x1f801098: + case 0x1f8010a0: case 0x1f8010a4: case 0x1f8010a8: + case 0x1f8010b0: case 0x1f8010b4: case 0x1f8010b8: + case 0x1f8010c0: case 0x1f8010c4: case 0x1f8010c8: + case 0x1f8010d0: case 0x1f8010d4: case 0x1f8010d8: + case 0x1f8010e0: case 0x1f8010e4: case 0x1f8010e8: + case 0x1f801070: case 0x1f801074: + case 0x1f8010f0: case 0x1f8010f4: + if (!_Rt_) return; + + LIW(PutHWReg32(_Rt_), (u32)&psxH[addr & 0xffff]); + LWBRX(PutHWReg32(_Rt_), 0, GetHWReg32(_Rt_)); + return; + + case 0x1f801810: + if (!_Rt_) return; + + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)GPU_readData); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + + case 0x1f801814: + if (!_Rt_) return; + + DisposeHWReg(iRegs[_Rt_].reg); + InvalidateCPURegs(); + CALLFunc((u32)GPU_readStatus); + + SetDstCPUReg(3); + PutHWReg32(_Rt_); + return; + } + } +// SysPrintf("unhandled r32 %x\n", addr); + } + + preMemRead(); + CALLFunc((u32)psxMemRead32); + if (_Rt_) { + SetDstCPUReg(3); + PutHWReg32(_Rt_); + } +} + +REC_FUNC(LWL); +REC_FUNC(LWR); +REC_FUNC(SWL); +REC_FUNC(SWR); + +static void recSB() { +// mem[Rs + Im] = Rt + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (IsConst(_Rt_)) { + MOV8ItoM((u32)&psxM[addr & 0x1fffff], (u8)iRegs[_Rt_].k); + } else { + MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV8RtoM((u32)&psxM[addr & 0x1fffff], EAX); + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (IsConst(_Rt_)) { + MOV8ItoM((u32)&psxH[addr & 0xfff], (u8)iRegs[_Rt_].k); + } else { + MOV8MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV8RtoM((u32)&psxH[addr & 0xfff], EAX); + } + return; + } +// SysPrintf("unhandled w8 %x\n", addr); + }*/ + + preMemWrite(1); + CALLFunc((u32)psxMemWrite8); +} + +static void recSH() { +// mem[Rs + Im] = Rt + + /*if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + if (IsConst(_Rt_)) { + MOV16ItoM((u32)&psxM[addr & 0x1fffff], (u16)iRegs[_Rt_].k); + } else { + MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV16RtoM((u32)&psxM[addr & 0x1fffff], EAX); + } + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + if (IsConst(_Rt_)) { + MOV16ItoM((u32)&psxH[addr & 0xfff], (u16)iRegs[_Rt_].k); + } else { + MOV16MtoR(EAX, (u32)&psxRegs.GPR.r[_Rt_]); + MOV16RtoM((u32)&psxH[addr & 0xfff], EAX); + } + return; + } + if (t == 0x1f80) { + if (addr >= 0x1f801c00 && addr < 0x1f801e00) { + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + PUSH32I (addr); + CALL32M ((u32)&SPU_writeRegister); +#ifndef __WIN32__ + resp+= 8; +#endif + return; + } + } +// SysPrintf("unhandled w16 %x\n", addr); + }*/ + + preMemWrite(2); + CALLFunc((u32)psxMemWrite16); +} + +static void recSW() { +// mem[Rs + Im] = Rt + //u32 *b1, *b2; +#if 0 + if (IsConst(_Rs_)) { + u32 addr = iRegs[_Rs_].k + _Imm_; + int t = addr >> 16; + + if ((t & 0x1fe0) == 0 && (t & 0x1fff) != 0) { + LIW(0, addr & 0x1fffff); + STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0); + return; + } + if (t == 0x1f80 && addr < 0x1f801000) { + LIW(0, (u32)&psxH[addr & 0xfff]); + STWBRX(GetHWReg32(_Rt_), 0, 0); + return; + } + if (t == 0x1f80) { + switch (addr) { + case 0x1f801080: case 0x1f801084: + case 0x1f801090: case 0x1f801094: + case 0x1f8010a0: case 0x1f8010a4: + case 0x1f8010b0: case 0x1f8010b4: + case 0x1f8010c0: case 0x1f8010c4: + case 0x1f8010d0: case 0x1f8010d4: + case 0x1f8010e0: case 0x1f8010e4: + case 0x1f801074: + case 0x1f8010f0: + LIW(0, (u32)&psxH[addr & 0xffff]); + STWBRX(GetHWReg32(_Rt_), 0, 0); + return; + +/* case 0x1f801810: + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + CALL32M((u32)&GPU_writeData); +#ifndef __WIN32__ + resp+= 4; +#endif + return; + + case 0x1f801814: + if (IsConst(_Rt_)) { + PUSH32I(iRegs[_Rt_].k); + } else { + PUSH32M((u32)&psxRegs.GPR.r[_Rt_]); + } + CALL32M((u32)&GPU_writeStatus); +#ifndef __WIN32__ + resp+= 4; +#endif*/ + } + } +// SysPrintf("unhandled w32 %x\n", addr); + } + +/* LIS(0, 0x0079 + ((_Imm_ <= 0) ? 1 : 0)); + CMPLW(GetHWReg32(_Rs_), 0); + BGE_L(b1); + + //SaveContext(); + ADDI(0, GetHWReg32(_Rs_), _Imm_); + RLWINM(0, GetHWReg32(_Rs_), 0, 11, 31); + STWBRX(GetHWReg32(_Rt_), GetHWRegSpecial(PSXMEM), 0); + B_L(b2); + + B_DST(b1);*/ +#endif + preMemWrite(4); + CALLFunc((u32)psxMemWrite32); + + //B_DST(b2); +} + +static void recSLL() { +// Rd = Rt << Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rt_].k << _Sa_); + } else { + SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} + +static void recSRL() { +// Rd = Rt >> Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, iRegs[_Rt_].k >> _Sa_); + } else { + SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} + +static void recSRA() { +// Rd = Rt >> Sa + if (!_Rd_) return; + + if (IsConst(_Rt_)) { + MapConst(_Rd_, (s32)iRegs[_Rt_].k >> _Sa_); + } else { + SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), _Sa_); + } +} + + +/* - shift ops - */ + +static void recSLLV() { +// Rd = Rt << Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, iRegs[_Rt_].k << iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SLWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SLW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} + +static void recSRLV() { +// Rd = Rt >> Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, iRegs[_Rt_].k >> iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SRWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SRW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} + +static void recSRAV() { +// Rd = Rt >> Rs + if (!_Rd_) return; + + if (IsConst(_Rt_) && IsConst(_Rs_)) { + MapConst(_Rd_, (s32)iRegs[_Rt_].k >> iRegs[_Rs_].k); + } else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + SRAWI(PutHWReg32(_Rd_), GetHWReg32(_Rt_), iRegs[_Rs_].k); + } else { + SRAW(PutHWReg32(_Rd_), GetHWReg32(_Rt_), GetHWReg32(_Rs_)); + } +} + +static void recSYSCALL() { +// dump=1; + iFlushRegs(0); + + ReserveArgs(2); + LIW(PutHWRegSpecial(PSXPC), pc - 4); + LIW(PutHWRegSpecial(ARG1), 0x20); + LIW(PutHWRegSpecial(ARG2), (branch == 1 ? 1 : 0)); + FlushAllHWReg(); + CALLFunc ((u32)psxException); + + branch = 2; + iRet(); +} + +static void recBREAK() { +} + +static void recMFHI() { +// Rd = Hi + if (!_Rd_) return; + + if (IsConst(REG_HI)) { + MapConst(_Rd_, iRegs[REG_HI].k); + } else { + MapCopy(_Rd_, REG_HI); + } +} + +static void recMTHI() { +// Hi = Rs + + if (IsConst(_Rs_)) { + MapConst(REG_HI, iRegs[_Rs_].k); + } else { + MapCopy(REG_HI, _Rs_); + } +} + +static void recMFLO() { +// Rd = Lo + if (!_Rd_) return; + + if (IsConst(REG_LO)) { + MapConst(_Rd_, iRegs[REG_LO].k); + } else { + MapCopy(_Rd_, REG_LO); + } +} + +static void recMTLO() { +// Lo = Rs + + if (IsConst(_Rs_)) { + MapConst(REG_LO, iRegs[_Rs_].k); + } else { + MapCopy(REG_LO, _Rs_); + } +} + +/* - branch ops - */ + +static void recBLTZ() { +// Branch if Rs < 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k < 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGTZ() { +// Branch if Rs > 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k > 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBLTZAL() { +// Branch if Rs < 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k < 0) { + MapConst(31, pc + 4); + + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLT_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + MapConst(31, pc + 4); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGEZAL() { +// Branch if Rs >= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k >= 0) { + MapConst(31, pc + 4); + + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + MapConst(31, pc + 4); + + iBranch(bpc, 0); + pc+=4; +} + +static void recJ() { +// j target + + iJump(_Target_ * 4 + (pc & 0xf0000000)); +} + +static void recJAL() { +// jal target + MapConst(31, pc + 4); + + iJump(_Target_ * 4 + (pc & 0xf0000000)); +} + +static void recJR() { +// jr Rs + + if (IsConst(_Rs_)) { + iJump(iRegs[_Rs_].k); + //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k); + } else { + MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_)); + SetBranch(); + } +} + +static void recJALR() { +// jalr Rs + + if (_Rd_) { + MapConst(_Rd_, pc + 4); + } + + if (IsConst(_Rs_)) { + iJump(iRegs[_Rs_].k); + //LIW(PutHWRegSpecial(TARGET), iRegs[_Rs_].k); + } else { + MR(PutHWRegSpecial(TARGET), GetHWReg32(_Rs_)); + SetBranch(); + } +} + +static void recBEQ() { +// Branch if Rs == Rt + u32 bpc = _Imm_ * 4 + pc; + + if (_Rs_ == _Rt_) { + iJump(bpc); + } + else { + if (IsConst(_Rs_) && IsConst(_Rt_)) { + if (iRegs[_Rs_].k == iRegs[_Rt_].k) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + u32 *b; + + BEQ_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; + } +} + +static void recBNE() { +// Branch if Rs != Rt + u32 bpc = _Imm_ * 4 + pc; + + if (_Rs_ == _Rt_) { + iJump(pc+4); + } + else { + if (IsConst(_Rs_) && IsConst(_Rt_)) { + if (iRegs[_Rs_].k != iRegs[_Rt_].k) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + else if (IsConst(_Rs_) && !IsMapped(_Rs_)) { + if ((iRegs[_Rs_].k & 0xffff) == iRegs[_Rs_].k) { + CMPLWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else if ((s32)(s16)iRegs[_Rs_].k == (s32)iRegs[_Rs_].k) { + CMPWI(GetHWReg32(_Rt_), iRegs[_Rs_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else if (IsConst(_Rt_) && !IsMapped(_Rt_)) { + if ((iRegs[_Rt_].k & 0xffff) == iRegs[_Rt_].k) { + CMPLWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else if ((s32)(s16)iRegs[_Rt_].k == (s32)iRegs[_Rt_].k) { + CMPWI(GetHWReg32(_Rs_), iRegs[_Rt_].k); + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + } + else { + CMPLW(GetHWReg32(_Rs_), GetHWReg32(_Rt_)); + } + + u32 *b; + BNE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; + } +} + +static void recBLEZ() { +// Branch if Rs <= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k <= 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BLE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + +static void recBGEZ() { +// Branch if Rs >= 0 + u32 bpc = _Imm_ * 4 + pc; + u32 *b; + + if (IsConst(_Rs_)) { + if ((s32)iRegs[_Rs_].k >= 0) { + iJump(bpc); return; + } else { + iJump(pc+4); return; + } + } + + CMPWI(GetHWReg32(_Rs_), 0); + BGE_L(b); + + iBranch(pc+4, 1); + + B_DST(b); + + iBranch(bpc, 0); + pc+=4; +} + + +REC_FUNC(RFE); + +static void recMFC0() { +// Rt = Cop0->Rd + if (!_Rt_) return; + + LWZ(PutHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); +} + +static void recCFC0() { +// Rt = Cop0->Rd + + recMFC0(); +} + +static void recMTC0() { +// Cop0->Rd = Rt + + /*if (IsConst(_Rt_)) { + switch (_Rd_) { + case 12: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k); + break; + case 13: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k & ~(0xfc00)); + break; + default: + MOV32ItoM((u32)&psxRegs.CP0.r[_Rd_], iRegs[_Rt_].k); + break; + } + } else*/ { + switch (_Rd_) { + case 13: + RLWINM(0,GetHWReg32(_Rt_),0,22,15); // & ~(0xfc00) + STW(0, OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); + break; + default: + STW(GetHWReg32(_Rt_), OFFSET(&psxRegs, &psxRegs.CP0.r[_Rd_]), GetHWRegSpecial(PSXREGS)); + break; + } + } + + if (_Rd_ == 12 || _Rd_ == 13) { + iFlushRegs(0); + LIW(PutHWRegSpecial(PSXPC), (u32)pc); + FlushAllHWReg(); + CALLFunc((u32)psxTestSWInts); + if(_Rd_ == 12) { + LWZ(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS)); + ORIS(0, 0, 0x8000); + STW(0, OFFSET(&psxRegs, &psxRegs.interrupt), GetHWRegSpecial(PSXREGS)); + } + branch = 2; + iRet(); + } +} + +static void recCTC0() { +// Cop0->Rd = Rt + + recMTC0(); +} + +// GTE function callers +CP2_FUNC(MFC2); +CP2_FUNC(MTC2); +CP2_FUNC(CFC2); +CP2_FUNC(CTC2); +CP2_FUNC(LWC2); +CP2_FUNC(SWC2); + +CP2_FUNCNC(RTPS); +CP2_FUNC(OP); +CP2_FUNCNC(NCLIP); +CP2_FUNCNC(DPCS); +CP2_FUNCNC(INTPL); +CP2_FUNC(MVMVA); +CP2_FUNCNC(NCDS); +CP2_FUNCNC(NCDT); +CP2_FUNCNC(CDP); +CP2_FUNCNC(NCCS); +CP2_FUNCNC(CC); +CP2_FUNCNC(NCS); +CP2_FUNCNC(NCT); +CP2_FUNC(SQR); +CP2_FUNCNC(DCPL); +CP2_FUNCNC(DPCT); +CP2_FUNCNC(AVSZ3); +CP2_FUNCNC(AVSZ4); +CP2_FUNCNC(RTPT); +CP2_FUNC(GPF); +CP2_FUNC(GPL); +CP2_FUNCNC(NCCT); + +static void recHLE() { + iFlushRegs(0); + FlushAllHWReg(); + + if ((psxRegs.code & 0x3ffffff) == (psxRegs.code & 0x7)) { + CALLFunc((u32)psxHLEt[psxRegs.code & 0x7]); + } else { + // somebody else must have written to current opcode for this to happen!!!! + CALLFunc((u32)psxHLEt[0]); // call dummy function + } + + count = idlecyclecount + (pc - pcold)/4 + 20; + ADDI(PutHWRegSpecial(CYCLECOUNT), GetHWRegSpecial(CYCLECOUNT), count); + FlushAllHWReg(); + CALLFunc((u32)psxBranchTest); + Return(); + + branch = 2; +} + +static void (*recBSC[64])() = { + recSPECIAL, recREGIMM, recJ , recJAL , recBEQ , recBNE , recBLEZ, recBGTZ, + recADDI , recADDIU , recSLTI, recSLTIU, recANDI, recORI , recXORI, recLUI , + recCOP0 , recNULL , recCOP2, recNULL , recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL , recNULL, recNULL, recNULL, recNULL, + recLB , recLH , recLWL , recLW , recLBU , recLHU , recLWR , recNULL, + recSB , recSH , recSWL , recSW , recNULL, recNULL, recSWR , recNULL, + recNULL , recNULL , recLWC2, recNULL , recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recSWC2, recHLE , recNULL, recNULL, recNULL, recNULL +}; + +static void (*recSPC[64])() = { + recSLL , recNULL, recSRL , recSRA , recSLLV , recNULL , recSRLV, recSRAV, + recJR , recJALR, recNULL, recNULL, recSYSCALL, recBREAK, recNULL, recNULL, + recMFHI, recMTHI, recMFLO, recMTLO, recNULL , recNULL , recNULL, recNULL, + recMULT, recMULTU, recDIV, recDIVU, recNULL , recNULL , recNULL, recNULL, + recADD , recADDU, recSUB , recSUBU, recAND , recOR , recXOR , recNOR , + recNULL, recNULL, recSLT , recSLTU, recNULL , recNULL , recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL , recNULL , recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL , recNULL , recNULL, recNULL +}; + +static void (*recREG[32])() = { + recBLTZ , recBGEZ , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recBLTZAL, recBGEZAL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL , recNULL , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void (*recCP0[32])() = { + recMFC0, recNULL, recCFC0, recNULL, recMTC0, recNULL, recCTC0, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recRFE , recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void (*recCP2[64])() = { + recBASIC, recRTPS , recNULL , recNULL, recNULL, recNULL , recNCLIP, recNULL, // 00 + recNULL , recNULL , recNULL , recNULL, recOP , recNULL , recNULL , recNULL, // 08 + recDPCS , recINTPL, recMVMVA, recNCDS, recCDP , recNULL , recNCDT , recNULL, // 10 + recNULL , recNULL , recNULL , recNCCS, recCC , recNULL , recNCS , recNULL, // 18 + recNCT , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 20 + recSQR , recDCPL , recDPCT , recNULL, recNULL, recAVSZ3, recAVSZ4, recNULL, // 28 + recRTPT , recNULL , recNULL , recNULL, recNULL, recNULL , recNULL , recNULL, // 30 + recNULL , recNULL , recNULL , recNULL, recNULL, recGPF , recGPL , recNCCT // 38 +}; + +static void (*recCP2BSC[32])() = { + recMFC2, recNULL, recCFC2, recNULL, recMTC2, recNULL, recCTC2, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, + recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL, recNULL +}; + +static void recRecompile() { + u32 *ptr; + int i; + + cop2readypc = 0; + idlecyclecount = 0; + + // initialize state variables + UniqueRegAlloc = 1; + HWRegUseCount = 0; + DstCPUReg = -1; + memset(HWRegisters, 0, sizeof(HWRegisters)); + for (i=0; i= (RECMEM_SIZE - 0x10000)) // fix me. don't just assume 0x10000 + recReset(); +#ifdef TAG_CODE + ppcAlign(); +#endif + ptr = ppcPtr; + + // tell the LUT where to find us + PC_REC32(psxRegs.pc) = (u32)ppcPtr; + + pcold = pc = psxRegs.pc; + + //where did 500 come from? + for (count=0; count<500;) { + char *p = (char *)PSXM(pc); + if (p == NULL) recError(); + psxRegs.code = SWAP32(*(u32 *)p); + pc+=4; count++; + recBSC[psxRegs.code>>26](); + + if (branch) { + branch = 0; + break; + } + } + if(!branch) { + iFlushRegs(pc); + LIW(PutHWRegSpecial(PSXPC), pc); + iRet(); + } + + DCFlushRange((u8*)ptr,(u32)(u8*)ppcPtr-(u32)(u8*)ptr); + ICInvalidateRange((u8*)ptr,(u32)(u8*)ppcPtr-(u32)(u8*)ptr); + +#ifdef TAG_CODE + sprintf((char *)ppcPtr, "PC=%08x", pcold); //causes misalignment + ppcPtr += strlen((char *)ppcPtr); +#endif + dyna_used = ((u32)ppcPtr - (u32)recMem)/1024; +} + + +R3000Acpu psxRec = { + recInit, + recReset, + recExecute, + recExecuteBlock, + recClear, + recShutdown +}; + diff --git a/ppc/pR3000A.h b/ppc/pR3000A.h new file mode 100644 index 0000000..3d99999 --- /dev/null +++ b/ppc/pR3000A.h @@ -0,0 +1,147 @@ +/* Pcsx - Pc Psx Emulator + * Copyright (C) 1999-2003 Pcsx Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _pR3000A_H_ +#define _pR3000A_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../psxcommon.h" +#include "ppc.h" +#include "reguse.h" +#include "../r3000a.h" +#include "../psxhle.h" +#include "../Gamecube/DEBUG.h" + +/* defines */ +#ifdef HW_DOL +#define RECMEM_SIZE (6*1024*1024) +#elif HW_RVL +#define RECMEM_SIZE (7*1024*1024) +#endif +#define NUM_REGISTERS 34 +#undef _Op_ +#define _Op_ _fOp_(psxRegs.code) +#undef _Funct_ +#define _Funct_ _fFunct_(psxRegs.code) +#undef _Rd_ +#define _Rd_ _fRd_(psxRegs.code) +#undef _Rt_ +#define _Rt_ _fRt_(psxRegs.code) +#undef _Rs_ +#define _Rs_ _fRs_(psxRegs.code) +#undef _Sa_ +#define _Sa_ _fSa_(psxRegs.code) +#undef _Im_ +#define _Im_ _fIm_(psxRegs.code) +#undef _Target_ +#define _Target_ _fTarget_(psxRegs.code) + +#undef _Imm_ +#define _Imm_ _fImm_(psxRegs.code) +#undef _ImmU_ +#define _ImmU_ _fImmU_(psxRegs.code) + +#undef PC_REC +#undef PC_REC8 +#undef PC_REC16 +#undef PC_REC32 +#define PC_REC(x) (psxRecLUT[x >> 16] + (x & 0xffff)) +#define PC_REC8(x) (*(u8 *)PC_REC(x)) +#define PC_REC16(x) (*(u16*)PC_REC(x)) +#define PC_REC32(x) (*(u32*)PC_REC(x)) +#define OFFSET(X,Y) ((u32)(Y)-(u32)(X)) + +#define ST_UNK 0x00 +#define ST_CONST 0x01 +#define ST_MAPPED 0x02 + +//#define NO_CONSTANT +#ifdef NO_CONSTANT +#define IsConst(reg) 0 +#else +#define IsConst(reg) (iRegs[reg].state & ST_CONST) +#endif +#define IsMapped(reg) (iRegs[reg].state & ST_MAPPED) + + +#define REG_LO 32 +#define REG_HI 33 + +// Hardware register usage +#define HWUSAGE_NONE 0x00 + +#define HWUSAGE_READ 0x01 +#define HWUSAGE_WRITE 0x02 +#define HWUSAGE_CONST 0x04 +#define HWUSAGE_ARG 0x08 /* used as an argument for a function call */ + +#define HWUSAGE_RESERVED 0x10 /* won't get flushed when flushing all regs */ +#define HWUSAGE_SPECIAL 0x20 /* special purpose register */ +#define HWUSAGE_HARDWIRED 0x40 /* specific hardware register mapping that is never disposed */ +#define HWUSAGE_INITED 0x80 +#define HWUSAGE_PSXREG 0x100 + +/* externals */ +extern void SysRunGui(); +extern void SysMessage(char *fmt, ...); +extern void SysReset(); +extern void SysPrintf(char *fmt, ...); +extern int stop; + +/* structs */ +typedef struct { + int state; + u32 k; + int reg; +} iRegisters; + +// Remember to invalidate the special registers if they are modified by compiler +enum { + ARG1 = 3, + ARG2 = 4, + ARG3 = 5, + PSXREGS, // ptr + PSXMEM, // ptr + CYCLECOUNT, // ptr + PSXPC, // ptr + TARGETPTR, // ptr + TARGET, // ptr + RETVAL, + REG_RZERO, + REG_WZERO +}; + +typedef struct { + int code; + u32 k; + int usage; + int lastUsed; + + void (*flush)(int hwreg); + int private; +} HWRegister; + +#endif diff --git a/ppc/pasm.s b/ppc/pasm.s new file mode 100644 index 0000000..7af9e0b --- /dev/null +++ b/ppc/pasm.s @@ -0,0 +1,153 @@ +#define r0 0 +#define r1 1 +#define sp 1 +#define r2 2 +#define toc 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + +# avoid touching r13 and r2 to conform to eabi spec + +# void recRun(register void (*func)(), register u32 hw1, register u32 hw2) +.text +.align 4 +.globl recRun +recRun: + # prologue code + mflr r0 # move from LR to r0 + stmw r14, -72(r1) # store non-volatiles (-72 == -(32-14)*4) + stw r0, 4(r1) # store old LR + stwu r1, -80(r1) # increment and store sp (-80 == -((32-14)*4+8)) + + # execute code + mtctr r3 # move func ptr to ctr + mr r31, r4 # save hw1 to r31 + mr r30, r5 # save hw2 to r30 + bctrl # branch to ctr (*func) + +# void returnPC() +.text +.align 4 +.globl returnPC +returnPC: + # end code + lwz r0, 84(r1) # re-load LR (84 == (32-14)*4+8+4) + addi r1, r1, 80 # increment SP (80 == (32-14)*4+8) + mtlr r0 # set LR + lmw r14, -72(r1) # reload non-volatiles (-72 == -((32-14)*4)) + blr # return + +#// Memory functions that only works with a linear memory +# +# .text +# .align 4 +# .globl dynMemRead8 +#dynMemRead8: +#// assumes that memory pointer is in r30 +# addis r2,r3,-0x1f80 +# srwi. r4,r2,16 +# bne+ .norm8 +# cmplwi r2,0x1000 +# blt- .norm8 +# b psxHwRead8 +#.norm8: +# clrlwi r5,r3,3 +# lbzx r3,r5,r30 +# blr +# +# .text +# .align 4 +# .globl dynMemRead16 +#dynMemRead16: +#// assumes that memory pointer is in r30 +# addis r2,r3,-0x1f80 +# srwi. r4,r2,16 +# bne+ .norm16 +# cmplwi r2,0x1000 +# blt- .norm16 +# b psxHwRead16 +#.norm16: +# clrlwi r5,r3,3 +# lhbrx r3,r5,r30 +# blr +# +# .text +# .align 4 +# .globl dynMemRead32 +#dynMemRead32: +#// assumes that memory pointer is in r30 +# addis r2,r3,-0x1f80 +# srwi. r4,r2,16 +# bne+ .norm32 +# cmplwi r2,0x1000 +# blt- .norm32 +# b psxHwRead32 +#.norm32: +# clrlwi r5,r3,3 +# lwbrx r3,r5,r30 +# blr +# +#/* +# N P Z +# 0 0 0 X +#- 0 0 1 X +# 1 0 0 X +# 1 0 1 X +# +#P | (!N & Z) +#P | !(N | !Z) +#*/ +# +# .text +# .align 4 +# .globl dynMemWrite32 +#dynMemWrite32: +#// assumes that memory pointer is in r30 +# addis r2,r3,-0x1f80 +# srwi. r5,r2,16 +# bne+ .normw32 +# cmplwi r2,0x1000 +# blt .normw32 +# b psxHwWrite32 +#.normw32: +# mtcrf 0xFF, r3 +# clrlwi r5,r3,3 +# crandc 0, 2, 0 +# cror 2, 1, 0 +# bne+ .okw32 +# // write test +# li r2,0x0130 +# addis r2,r2,0xfffe +# cmplw r3,r2 +# bnelr +#.okw32: +# stwbrx r4,r5,r30 +# blr + diff --git a/ppc/ppc.c b/ppc/ppc.c new file mode 100644 index 0000000..ba38b4b --- /dev/null +++ b/ppc/ppc.c @@ -0,0 +1,33 @@ +/* + * ix86 core v0.5.1 + * Authors: linuzappz + * alexey silinov + */ + +#include +#include + +#include "ppc.h" + +// General Purpose hardware registers +int cpuHWRegisters[NUM_HW_REGISTERS] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 +}; + +u32 *ppcPtr; + +void ppcInit() { +} +void ppcSetPtr(u32 *ptr) { + ppcPtr = ptr; +} +inline void ppcAlign() { + // forward align (if we need to) + if((u32)ppcPtr%4) + ppcPtr = (u32*)(((u32)ppcPtr + 4) & ~(3)); +} + +void ppcShutdown() { +} + diff --git a/ppc/ppc.h b/ppc/ppc.h new file mode 100644 index 0000000..ee40785 --- /dev/null +++ b/ppc/ppc.h @@ -0,0 +1,74 @@ +/* + * ppc definitions v0.5.1 + * Authors: linuzappz + * alexey silinov + */ + +#ifndef __PPC_H__ +#define __PPC_H__ + +// include basic types +#include "../psxcommon.h" +#include "ppc_mnemonics.h" + +#define NUM_HW_REGISTERS 28 + +/* general defines */ +#define write8(val) *(u8 *)ppcPtr = val; ppcPtr++; +#define write16(val) *(u16*)ppcPtr = val; ppcPtr+=2; +#define write32(val) *(u32*)ppcPtr = val; ppcPtr+=4; +#define write64(val) *(u64*)ppcPtr = val; ppcPtr+=8; + +#define CALLFunc(FUNC) \ +{ \ + u32 _func = (FUNC); \ + ReleaseArgs(); \ + if ((_func & 0x1fffffc) == _func) { \ + BLA(_func); \ + } else { \ + LIW(0, _func); \ + MTCTR(0); \ + BCTRL(); \ + } \ +} + +extern int cpuHWRegisters[NUM_HW_REGISTERS]; + +extern u32 *ppcPtr; +extern u8 *j8Ptr[32]; +extern u32 *j32Ptr[32]; + +void ppcInit(); +void ppcSetPtr(u32 *ptr); +void ppcShutdown(); + +extern inline void ppcAlign(); +void returnPC(); +void recRun(void (*func)(), u32 hw1, u32 hw2); +u8 dynMemRead8(u32 mem); +u16 dynMemRead16(u32 mem); +u32 dynMemRead32(u32 mem); +void dynMemWrite32(u32 mem, u32 val); + +#endif /* __PPC_H__ */ + + + + + + + + + + + + + + + + + + + + + diff --git a/ppc/ppc_mnemonics.h b/ppc/ppc_mnemonics.h new file mode 100644 index 0000000..ed0d8bd --- /dev/null +++ b/ppc/ppc_mnemonics.h @@ -0,0 +1,521 @@ +// ppc_mnemonics.h + +#define INSTR (*(ppcPtr)++) + +/* Link register related */ +#define MFLR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0802A6 | (_reg << 21));} + +#define MTLR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0803A6 | (_reg << 21));} + +#define MTCTR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C0903A6 | (_reg << 21));} + +#define BLR() \ + {INSTR = (0x4E800020);} + +#define BGTLR() \ + {INSTR = (0x4D810020);} + + +/* Load ops */ +#define LI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x38000000 | (_reg << 21) | ((IMM) & 0xffff));} + +#define LIS(REG_DST, IMM) \ + {int _dst = (REG_DST); \ + INSTR = (0x3C000000 | (_dst << 21) | ((IMM) & 0xffff));} + +#define LWZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0x80000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LWZX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00002E | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LWBRX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00042C | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LHZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xA0000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LHA(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xA8000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LHBRX(REG_DST, REG, REG_OFF) \ + {int _reg = (REG), _off = (REG_OFF); int _dst=(REG_DST); \ + INSTR = (0x7C00062C | (_dst << 21) | (_reg << 16) | (_off << 11));} + +#define LBZ(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0x88000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define LMW(REG_DST, OFFSET, REG) \ + {int _reg = (REG); int _dst=(REG_DST); \ + INSTR = (0xB8000000 | (_dst << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + + + +/* Store ops */ +#define STMW(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0xBC000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STW(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x90000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STWBRX(REG_SRC, REG, REG_OFF) \ + {int _reg = (REG), _src=(REG_SRC), _off = (REG_OFF); \ + INSTR = (0x7C00052C | (_src << 21) | (_reg << 16) | (_off << 11));} + +#define STH(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0xB0000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STHBRX(REG_SRC, REG, REG_OFF) \ + {int _reg = (REG), _src=(REG_SRC), _off = (REG_OFF); \ + INSTR = (0x7C00072C | (_src << 21) | (_reg << 16) | (_off << 11));} + +#define STB(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x98000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + +#define STWU(REG_SRC, OFFSET, REG) \ + {int _reg = (REG), _src=(REG_SRC); \ + INSTR = (0x94000000 | (_src << 21) | (_reg << 16) | ((OFFSET) & 0xffff));} + + +/* Arithmic ops */ +#define ADDI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x38000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDIS(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x3C000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define MR(REG_DST, REG_SRC) \ + {int __src = (REG_SRC); int __dst=(REG_DST); \ + if (__src != __dst) {ADDI(__dst, __src, 0)}} + +#define ADD(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000214 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000614 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDEO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000514 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDE(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000114 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDCO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000414 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define ADDIC(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x30000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDIC_(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x34000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define ADDZE(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000194 | (_dst << 21) | (_src << 16));} + +#define SUBF(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000050 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000450 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFC(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000010 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFE(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000110 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFCO(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000410 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUBFCO_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000411 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define SUB(REG_DST, REG1, REG2) \ + {SUBF(REG_DST, REG2, REG1)} + +#define SUBO(REG_DST, REG1, REG2) \ + {SUBFO(REG_DST, REG2, REG1)} + +#define SUBCO(REG_DST, REG1, REG2) \ + {SUBFCO(REG_DST, REG2, REG1)} + +#define SUBCO_(REG_DST, REG1, REG2) \ + {SUBFCO_(REG_DST, REG2, REG1)} +/* Duplicate +#define SRAWI(REG_DST, REG_SRC, SHIFT) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000670 | (_src << 21) | (_dst << 16) | (SHIFT << 11));} +*/ +#define MULHW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000096 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULLW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0001D6 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULHWU(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000016 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define MULLI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x1C000000 | (_dst << 21) | (_src << 16) | ((IMM) & 0xffff));} + +#define DIVW(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0003D6 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + +#define DIVWU(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000396 | (_dst << 21) | (_reg1 << 16) | (_reg2 << 11));} + + +/* Branch ops */ +#define B_FROM(VAR) VAR = ppcPtr +#define B_DST(VAR) *VAR = *VAR | (((s16)((u32)ppcPtr - (u32)VAR)) & 0xfffc) + +#define B(DST) \ + {INSTR = (0x48000000 | (((s32)(((DST)+1)<<2)) & 0x3fffffc));} + +#define B_L(VAR) \ + {B_FROM(VAR); INSTR = (0x48000000);} + +#define BA(DST) \ + {INSTR = (0x48000002 | ((s32)((DST) & 0x3fffffc)));} + +#define BLA(DST) \ + {INSTR = (0x48000003 | ((s32)((DST) & 0x3fffffc)));} + +#define BNS(DST) \ + {INSTR = (0x40830000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BNE(DST) \ + {INSTR = (0x40820000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BNE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40820000);} + +#define BEQ(DST) \ + {INSTR = (0x41820000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BEQ_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41820000);} + +#define BLT(DST) \ + {INSTR = (0x41800000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BLT_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41800000);} + +#define BGT(DST) \ + {INSTR = (0x41810000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BGT_L(VAR) \ + {B_FROM(VAR); INSTR = (0x41810000);} + +#define BGE(DST) \ + {INSTR = (0x40800000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BGE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40800000);} + +#define BLE(DST) \ + {INSTR = (0x40810000 | (((s16)(((DST)+1)<<2)) & 0xfffc));} + +#define BLE_L(VAR) \ + {B_FROM(VAR); INSTR = (0x40810000);} + +#define BCTRL() \ + {INSTR = (0x4E800421);} + +#define BCTR() \ + {INSTR = (0x4E800420);} + + +/* compare ops */ +#define CMPLWI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x28000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLWI2(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x29000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLWI7(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2B800000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPLW(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C000040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPLW1(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C800040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPLW2(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7D000040 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C000000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW1(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7C800000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPW2(REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); \ + INSTR = (0x7D000000 | (_reg1 << 16) | (_reg2 << 11));} + +#define CMPWI(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2C000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define CMPWI2(REG, IMM) \ + {int _reg = (REG); \ + INSTR = (0x2D000000 | (_reg << 16) | ((IMM) & 0xffff));} + +#define MTCRF(MASK, REG) \ + {int _reg = (REG); \ + INSTR = (0x7C000120 | (_reg << 21) | (((MASK)&0xff)<<12));} + +#define MFCR(REG) \ + {int _reg = (REG); \ + INSTR = (0x7C000026 | (_reg << 21));} + +#define CROR(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000382 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRXOR(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000182 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRNAND(CR_DST, CR1, CR2) \ + {INSTR = (0x4C0001C2 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + +#define CRANDC(CR_DST, CR1, CR2) \ + {INSTR = (0x4C000102 | ((CR_DST) << 21) | ((CR1) << 16) | ((CR2) << 11));} + + +/* shift ops */ +#define RLWINM(REG_DST, REG_SRC, SHIFT, START, END) \ + {int _src = (REG_SRC); int _dst = (REG_DST); \ + INSTR = (0x54000000 | (_src << 21) | (_dst << 16) | (SHIFT << 11) | (START << 6) | (END << 1));} + +#define RLWINM_(REG_DST, REG_SRC, SHIFT, START, END) \ + {int _src = (REG_SRC); int _dst = (REG_DST); \ + INSTR = (0x54000001 | (_src << 21) | (_dst << 16) | (SHIFT << 11) | (START << 6) | (END << 1));} + +#define CLRRWI(REG_DST, REG_SRC, LEN) \ + RLWINM(REG_DST, REG_SRC, 0, 0, 31-LEN) + +#define SLWI(REG_DST, REG_SRC, SHIFT) \ + {int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + {RLWINM(REG_DST, REG_SRC, _shift, 0, (31-_shift))}} + +#define SRWI(REG_DST, REG_SRC, SHIFT) \ + {int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + RLWINM(REG_DST, REG_SRC, (32-_shift), _shift, 31)} + +#define SLW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000030 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000430 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRAW(REG_DST, REG_SRC, REG_SHIFT) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x7C000630 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define SRAWI(REG_DST, REG_SRC, SHIFT) \ + {int _src = (REG_SRC); int _dst = (REG_DST); int _shift = (SHIFT); \ + if (_shift==0) {MR(REG_DST, REG_SRC)} else \ + INSTR = (0x7C000670 | (_src << 21) | (_dst << 16) | (_shift << 11));} + +#define RLWNM(REG_DST, REG_SRC, REG_SHIFT, START, END) \ + {int _src = (REG_SRC), _shift = (REG_SHIFT); int _dst = (REG_DST); \ + INSTR = (0x5C000000 | (_src << 21) | (_dst << 16) | (_shift << 11) | (START << 6) | (END << 1));} + +/* other ops */ +#define ORI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC), _imm = (IMM); int _dst = (REG_DST); \ + if (!((_imm == 0) && ((_src^_dst) == 0))) \ + INSTR = (0x60000000 | (_src << 21) | (_dst << 16) | (_imm & 0xffff));} + +#define ORIS(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC), _imm = (IMM); int _dst = (REG_DST); \ + if (!((_imm == 0) && ((_src^_dst) == 0))) \ + INSTR = (0x64000000 | (_src << 21) | (_dst << 16) | (_imm & 0xffff));} + +#define OR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000378 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define OR_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000379 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define XORI(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x68000000 | (_src << 21) | (_dst << 16) | ((IMM) & 0xffff));} + +#define XOR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000278 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define XOR_(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000279 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define ANDI_(REG_DST, REG_SRC, IMM) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x70000000 | (_src << 21) | (_dst << 16) | ((IMM) & 0xffff));} + +#define AND(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C000038 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define NOR(REG_DST, REG1, REG2) \ + {int _reg1 = (REG1), _reg2 = (REG2); int _dst=(REG_DST); \ + INSTR = (0x7C0000f8 | (_reg1 << 21) | (_dst << 16) | (_reg2 << 11));} + +#define NEG(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C0000D0 | (_dst << 21) | (_src << 16));} + +#define NOP() \ + {INSTR = 0x60000000;} + +#define MCRXR(CR_DST) \ + {INSTR = (0x7C000400 | (CR_DST << 23));} + +#define EXTSB(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000774 | (_src << 21) | (_dst << 16));} + +#define EXTSH(REG_DST, REG_SRC) \ + {int _src = (REG_SRC); int _dst=(REG_DST); \ + INSTR = (0x7C000734 | (_src << 21) | (_dst << 16));} + + +/* floating point ops */ +#define FDIVS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC000024 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FDIV(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC000024 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FMULS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC000032 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FMUL(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC000032 | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FADDS(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xEC00002A | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FADD(FPR_DST, FPR1, FPR2) \ + {INSTR = (0xFC00002A | (FPR_DST << 21) | (FPR1 << 16) | (FPR2 << 11));} + +#define FRSP(FPR_DST, FPR_SRC) \ + {INSTR = (0xFC000018 | (FPR_DST << 21) | (FPR_SRC << 11));} + +#define FCTIW(FPR_DST, FPR_SRC) \ + {INSTR = (0xFC00001C | (FPR_DST << 21) | (FPR_SRC << 11));} + + +#define LFS(FPR_DST, OFFSET, REG) \ + {INSTR = (0xC0000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define STFS(FPR_DST, OFFSET, REG) \ + {INSTR = (0xD0000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define LFD(FPR_DST, OFFSET, REG) \ + {INSTR = (0xC8000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + +#define STFD(FPR_DST, OFFSET, REG) \ + {INSTR = (0xD8000000 | (FPR_DST << 21) | (REG << 16) | ((OFFSET) & 0xffff));} + + + +/* extra combined opcodes */ +#if 1 +#define LIW(REG, IMM) /* Load Immidiate Word */ \ +{ \ + int __reg = (REG); u32 __imm = (u32)(IMM); \ + if ((s32)__imm == (s32)((s16)__imm)) \ + { \ + LI(__reg, (s32)((s16)__imm)); \ + } else if (__reg == 0) { \ + LIS(__reg, (((u32)__imm)>>16)); \ + if ((((u32)__imm) & 0xffff) != 0) \ + { \ + ORI(__reg, __reg, __imm); \ + } \ + } else { \ + if ((((u32)__imm) & 0xffff) == 0) { \ + LIS(__reg, (((u32)__imm)>>16)); \ + } else { \ + LI(__reg, __imm); \ + ADDIS(__reg, __reg, ((u32)__imm+0x8000)>>16); \ + } \ + } \ +} +#else +#define LIW(REG, IMM) /* Load Immidiate Word */ \ +{ \ + int __reg = (REG); u32 __imm = (u32)(IMM); \ + if ((s32)__imm == (s32)((s16)__imm)) \ + { \ + LI(__reg, (s32)((s16)__imm)); \ + } \ + else \ + { \ + LIS(__reg, (((u32)__imm)>>16)); \ + if ((((u32)__imm) & 0xffff) != 0) \ + { \ + ORI(__reg, __reg, __imm); \ + } \ + } \ +} +#endif diff --git a/ppc/reguse.c b/ppc/reguse.c new file mode 100644 index 0000000..9172dac --- /dev/null +++ b/ppc/reguse.c @@ -0,0 +1,419 @@ + +#include "../psxcommon.h" +#include "reguse.h" + +#include "../r3000a.h" + +//#define SAME_CYCLE_MODE + +static const int useBSC[64] = { + /*recSPECIAL*/ REGUSE_SUB | REGUSE_SPECIAL, + /*recREGIMM*/ REGUSE_SUB | REGUSE_REGIMM, + /*recJ*/ REGUSE_JUMP, + /*recJAL*/ REGUSE_JUMP | REGUSE_R31_W, + /*recBEQ*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, + /*recBNE*/ REGUSE_BRANCH | REGUSE_RS_R | REGUSE_RT_R, + /*recBLEZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recBGTZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recADDI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recADDIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recSLTI*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recSLTIU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_W, + /*recANDI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recXORI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_W, + /*recLUI*/ REGUSE_ACC | REGUSE_RT_W, + /*recCOP0*/ REGUSE_SUB | REGUSE_COP0, + REGUSE_NONE, + /*recCOP2*/ REGUSE_SUB | REGUSE_COP2, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recLB*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLH*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLWL*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, + /*recLW*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLBU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLHU*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT_W, + /*recLWR*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_RT, + REGUSE_NONE, + /*recSB*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + /*recSH*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + /*recSWL*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, + /*recSW*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_RT_R, + REGUSE_NONE, REGUSE_NONE, + /*recSWR*/ REGUSE_MEM | REGUSE_RS_R | REGUSE_RT_R, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recLWC2*/ REGUSE_MEM_R | REGUSE_RS_R | REGUSE_COP2_RT_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recSWC2*/ REGUSE_MEM_W | REGUSE_RS_R | REGUSE_COP2_RT_R, + /*recHLE*/ REGUSE_UNKNOWN, // TODO: can this be done in a better way + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE +}; + +static const int useSPC[64] = { + /*recSLL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, + /*recSRL*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + /*recSRA*/ REGUSE_ACC | REGUSE_RT_R | REGUSE_RD_W, + /*recSLLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, + /*recSRLV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSRAV*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recJR*/ REGUSE_JUMPR | REGUSE_RS_R, + /*recJALR*/ REGUSE_JUMPR | REGUSE_RS_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, + /*rSYSCALL*/ REGUSE_SYS | REGUSE_PC | REGUSE_COP0_STATUS | REGUSE_EXCEPTION, + /*recBREAK*/ REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recMFHI*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_HI_R, + /*recMTHI*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_HI_W, + /*recMFLO*/ REGUSE_LOGIC | REGUSE_RD_W | REGUSE_LO_R, + /*recMTLO*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_LO_W, + REGUSE_NONE, REGUSE_NONE , REGUSE_NONE, REGUSE_NONE, + /*recMULT*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recMULTU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recDIV*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + /*recDIVU*/ REGUSE_MULT | REGUSE_RS_R | REGUSE_RT_R | REGUSE_LO_W | REGUSE_HI_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recADD*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recADDU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSUB*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSUBU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recAND*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recXOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recNOR*/ REGUSE_LOGIC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, + /*recSLT*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + /*recSLTU*/ REGUSE_ACC | REGUSE_RS_R | REGUSE_RT_R | REGUSE_RD_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE +}; + +static const int useREGIMM[32] = { + /*recBLTZ*/ REGUSE_BRANCH | REGUSE_RS_R, + /*recBGEZ*/ REGUSE_BRANCH | REGUSE_RS_R, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, + /*recBLTZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, + /*recBGEZAL*/REGUSE_BRANCH | REGUSE_RS_R | REGUSE_R31_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE +}; + +static const int useCP0[32] = { + /*recMFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, + REGUSE_NONE, + /*recCFC0*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP0_RD_R, + REGUSE_NONE, + /*recMTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, + REGUSE_NONE, + /*recCTC0*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP0_RD_W, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recRFE*/ REGUSE_LOGIC | REGUSE_COP0_STATUS, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE +}; + +// TODO: make more explicit +static const int useCP2[64] = { + /*recBASIC*/ REGUSE_SUB | REGUSE_BASIC, + /*recRTPS*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recNCLIP*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recOP*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recDPCS*/ REGUSE_GTE, + /*recINTPL*/ REGUSE_GTE, + /*recMVMVA*/ REGUSE_GTE, + /*recNCDS*/ REGUSE_GTE, + /*recCDP*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCDT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recNCCS*/ REGUSE_GTE, + /*recCC*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCS*/ REGUSE_GTE, + REGUSE_NONE, + /*recNCT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, + /*recSQR*/ REGUSE_GTE, + /*recDCPL*/ REGUSE_GTE, + /*recDPCT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, + /*recAVSZ3*/ REGUSE_GTE, + /*recAVSZ4*/ REGUSE_GTE, + REGUSE_NONE, + /*recRTPT*/ REGUSE_GTE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, REGUSE_NONE, + /*recGPF*/ REGUSE_GTE, + /*recGPL*/ REGUSE_GTE, + /*recNCCT*/ REGUSE_GTE +}; + +static const int useCP2BSC[32] = { + /*recMFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, + REGUSE_NONE, + /*recCFC2*/ REGUSE_LOGIC | REGUSE_RT_W | REGUSE_COP2_RD_R, + REGUSE_NONE, + /*recMTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, + REGUSE_NONE, + /*recCTC2*/ REGUSE_LOGIC | REGUSE_RT_R | REGUSE_COP2_RD_W, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE, + REGUSE_NONE +}; + +static int getRegUse(u32 code) __attribute__ ((__pure__)); +static int getRegUse(u32 code) +{ + int use = useBSC[code>>26]; + + switch (use & REGUSE_SUBMASK) { + case REGUSE_NONE: + break; + case REGUSE_SPECIAL: + use = useSPC[_fFunct_(code)]; + break; + case REGUSE_REGIMM: + use = useREGIMM[_fRt_(code)]; + break; + case REGUSE_COP0: + use = useCP0[_fRs_(code)]; + break; + case REGUSE_COP2: + use = useCP2[_fFunct_(code)]; + if ((use & REGUSE_SUBMASK) == REGUSE_BASIC) + use = useCP2BSC[_fRs_(code)]; + break; + default: + use = REGUSE_UNKNOWN; + break; + } + + if ((use & REGUSE_COP0_RD_W)) { + if (_fRd_(code) == 12 || _fRd_(code) == 13) { + use = REGUSE_UNKNOWN; + } + } + + return use; +} + +/* returns how psxreg is used in the code instruction */ +int useOfPsxReg(u32 code, int use, int psxreg) +{ + int retval = REGUSE_NONE; + + // get use if it wasn't supplied + if (-1 == use) use = getRegUse(code); + + // if we don't know what the usage is, assume it's read from + if (REGUSE_UNKNOWN == use) return REGUSE_READ; + + if (psxreg < 32) { + // check for 3 standard types + if ((use & REGUSE_RT) && _fRt_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RT_R) ? REGUSE_READ:0) | ((use & REGUSE_RT_W) ? REGUSE_WRITE:0); + } + if ((use & REGUSE_RS) && _fRs_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RS_R) ? REGUSE_READ:0) | ((use & REGUSE_RS_W) ? REGUSE_WRITE:0); + } + if ((use & REGUSE_RD) && _fRd_(code) == (u32)psxreg) { + retval |= ((use & REGUSE_RD_R) ? REGUSE_READ:0) | ((use & REGUSE_RD_W) ? REGUSE_WRITE:0); + } + // some instructions explicitly writes to r31 + if ((use & REGUSE_R31_W) && 31 == psxreg) { + retval |= REGUSE_WRITE; + } + } else if (psxreg == 32) { // Special register LO + retval |= ((use & REGUSE_LO_R) ? REGUSE_READ:0) | ((use & REGUSE_LO_W) ? REGUSE_WRITE:0); + } else if (psxreg == 33) { // Special register HI + retval |= ((use & REGUSE_HI_R) ? REGUSE_READ:0) | ((use & REGUSE_HI_W) ? REGUSE_WRITE:0); + } + + return retval; +} + +//#define NOREGUSE_FOLLOW + +static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) __attribute__ ((__pure__, __unused__)); +static int _nextPsxRegUse(u32 pc, int psxreg, int numInstr) +{ + u32 code; + int i, reguse = 0; + + for (i=0; i= 2) break; // only follow 1 branch + } + if (reguse == REGUSE_NONE) return reguse; + + if (bPC) { + reguse1 = reguse; + pc = bPC; bPC = 0; + b = 1; + goto retry; + } + + return reguse1 | reguse; +#endif +} + +int isPsxRegUsed(u32 pc, int psxreg) +{ + int use = nextPsxRegUse(pc, psxreg); + + if (use == REGUSE_NONE) + return 2; // unknown use - assume it is used + else if (use & REGUSE_READ) + return 1; // the next use is a read + else + return 0; // the next use is a write, i.e. current value is not important +} diff --git a/ppc/reguse.h b/ppc/reguse.h new file mode 100644 index 0000000..69001ef --- /dev/null +++ b/ppc/reguse.h @@ -0,0 +1,77 @@ + +#ifndef __REGUSE_H__ +#define __REGUSE_H__ + +// include basic types +#include "../psxcommon.h" + +#define REGUSE_NONE 0x0000 +#define REGUSE_UNKNOWN 0x0001 + +//sub functions +#define REGUSE_SPECIAL 0x0002 +#define REGUSE_REGIMM 0x0004 +#define REGUSE_COP0 0x0006 +#define REGUSE_COP2 0x0008 +#define REGUSE_BASIC 0x000a +#define REGUSE_SUBMASK 0x000e /* sub function mask */ + +#define REGUSE_ACC 0x0010 /* accumulator */ +#define REGUSE_LOGIC 0x0020 /* logic operations */ +#define REGUSE_MULT 0x0030 /* multiplier */ +#define REGUSE_JUMP 0x0040 /* jump to dest */ +#define REGUSE_JUMPR 0x0050 /* jump to reg */ +#define REGUSE_BRANCH 0x0060 /* branch */ +#define REGUSE_MEM_R 0x0070 /* read from memory */ +#define REGUSE_MEM_W 0x0080 /* write to memory */ +#define REGUSE_MEM 0x0090 /* read and write to memory */ +#define REGUSE_SYS 0x00a0 /* syscall */ +#define REGUSE_GTE 0x00b0 /* gte operation */ +#define REGUSE_SUB 0x00f0 /* sub usage */ +#define REGUSE_TYPEM 0x00f0 /* type mask */ + + +#define REGUSE_RS_R 0x0100 +#define REGUSE_RS_W 0x0200 +#define REGUSE_RS (REGUSE_RS_R | REGUSE_RS_W) +#define REGUSE_RT_R 0x0400 +#define REGUSE_RT_W 0x0800 +#define REGUSE_RT (REGUSE_RT_R | REGUSE_RT_W) +#define REGUSE_RD_R 0x1000 +#define REGUSE_RD_W 0x2000 +#define REGUSE_RD (REGUSE_RD_R | REGUSE_RD_W) + +#define REGUSE_R31_W 0x4000 /* writes to link register (r31) */ +#define REGUSE_PC 0x8000 /* reads pc */ + +#define REGUSE_LO_R 0x10000 +#define REGUSE_LO_W 0x20000 +#define REGUSE_LO (REGUSE_LO_R | REGUSE_LO_W) +#define REGUSE_HI_R 0x40000 +#define REGUSE_HI_W 0x80000 +#define REGUSE_HI (REGUSE_HI_R | REGUSE_HI_W) + +#define REGUSE_COP0_RD_R 0x100000 +#define REGUSE_COP0_RD_W 0x200000 +#define REGUSE_COP0_RD (REGUSE_COP0_RD_R | REGUSE_COP0_RD_W) +#define REGUSE_COP0_STATUS 0x400000 +#define REGUSE_EXCEPTION 0x800000 + +#define REGUSE_COP2_RT_R 0x1000000 +#define REGUSE_COP2_RT_W 0x2000000 +#define REGUSE_COP2_RT (REGUSE_COP2_RT_R | REGUSE_COP2_RT_W) +#define REGUSE_COP2_RD_R 0x4000000 +#define REGUSE_COP2_RD_W 0x8000000 +#define REGUSE_COP2_RD (REGUSE_COP2_RD_R | REGUSE_COP2_RD_W) + + +// specific register use +#define REGUSE_READ 1 +#define REGUSE_WRITE 2 +#define REGUSE_RW 3 + +int useOfPsxReg(u32 code, int use, int psxreg) __attribute__ ((__pure__));; +int nextPsxRegUse(u32 pc, int psxreg) __attribute__ ((__pure__));; +int isPsxRegUsed(u32 pc, int psxreg) __attribute__ ((__pure__));; + +#endif /* __REGUSE_H__ */ diff --git a/psemu_plugin_defs.h b/psemu_plugin_defs.h new file mode 100644 index 0000000..62f0f95 --- /dev/null +++ b/psemu_plugin_defs.h @@ -0,0 +1,283 @@ +#ifndef _PSEMU_PLUGIN_DEFS_H +#define _PSEMU_PLUGIN_DEFS_H + +// header version +#define _PPDK_HEADER_VERSION 3 + +#define PLUGIN_VERSION 1 + +// plugin type returned by PSEgetLibType (types can be merged if plugin is multi type!) +#define PSE_LT_CDR 1 +#define PSE_LT_GPU 2 +#define PSE_LT_SPU 4 +#define PSE_LT_PAD 8 +#define PSE_LT_NET 16 + +// DLL function return codes +#define PSE_ERR_SUCCESS 0 // every function in DLL if completed sucessfully should return this value +#define PSE_ERR_FATAL -1 // undefined error but fatal one, that kills all functionality + +// XXX_Init return values +// Those return values apply to all libraries +// currently obsolete - preserved for compatibilty + +#define PSE_INIT_ERR_SUCCESS 0 // initialization went OK +#define PSE_INIT_ERR_NOTCONFIGURED -2 // this driver is not configured +#define PSE_INIT_ERR_NOHARDWARE -3 // this driver can not operate properly on this hardware or hardware is not detected + +/* GPU PlugIn */ + + +// GPU_Test return values + +// sucess, everything configured, and went OK. +#define PSE_GPU_ERR_SUCCESS 0 + +// ERRORS +// this error might be returned as critical error but none of below +#define PSE_GPU_ERR -20 + + +// this driver is not configured +#define PSE_GPU_ERR_NOTCONFIGURED PSE_GPU_ERR - 1 +// this driver failed Init +#define PSE_GPU_ERR_INIT PSE_GPU_ERR - 2 + +// WARNINGS +// this warning might be returned as undefined warning but allowing driver to continue +#define PSE_GPU_WARN 20 + + + + +// GPU_Query - will be implemented soon + +typedef struct +{ + uint32_t flags; + uint32_t status; + void* window; + unsigned char reserved[100]; +} gpuQueryS; + +// gpuQueryS.flags +// if driver can operate in both modes it must support GPU_changeMode(); +#define PSE_GPU_FLAGS_FULLSCREEN 1 // this driver can operate in fullscreen mode +#define PSE_GPU_FLAGS_WINDOWED 2 // this driver can operate in windowed mode + +// gpuQueryS.status +#define PSE_GPU_STATUS_WINDOWWRONG 1 // this driver cannot operate in this windowed mode + +// GPU_Query End - will be implemented in v2 + + +/* CDR PlugIn */ + +// CDR_Test return values + +// sucess, everything configured, and went OK. +#define PSE_CDR_ERR_SUCCESS 0 + +// general failure (error undefined) +#define PSE_CDR_ERR_FAILURE -1 + +// ERRORS +#define PSE_CDR_ERR -40 +// this driver is not configured +#define PSE_CDR_ERR_NOTCONFIGURED PSE_CDR_ERR - 0 +// if this driver is unable to read data from medium +#define PSE_CDR_ERR_NOREAD PSE_CDR_ERR - 1 + +// WARNINGS +#define PSE_CDR_WARN 40 +// if this driver emulates lame mode ie. can read only 2048 tracks and sector header is emulated +// this might happen to CDROMS that do not support RAW mode reading - surelly it will kill many games +#define PSE_CDR_WARN_LAMECD PSE_CDR_WARN + 0 + + + + +/* SPU PlugIn */ + +// some info retricted (now!) + +// sucess, everything configured, and went OK. +#define PSE_SPU_ERR_SUCCESS 0 + +// ERRORS +// this error might be returned as critical error but none of below +#define PSE_SPU_ERR -60 + +// this driver is not configured +#define PSE_SPU_ERR_NOTCONFIGURED PSE_SPU_ERR - 1 +// this driver failed Init +#define PSE_SPU_ERR_INIT PSE_SPU_ERR - 2 + + +// WARNINGS +// this warning might be returned as undefined warning but allowing driver to continue +#define PSE_SPU_WARN 60 + + + + +/* PAD PlugIn */ + +/* + + functions that must be exported from PAD Plugin + + long PADinit(long flags); // called only once when PSEmu Starts + void PADshutdown(void); // called when PSEmu exits + long PADopen(PadInitS *); // called when PSEmu is running program + long PADclose(void); + long PADconfigure(void); + void PADabout(void); + long PADtest(void); // called from Configure Dialog and after PADopen(); + long PADquery(void); + + long PADreadPort1(PadDataS *); + long PADreadPort2(PadDataS *); + +*/ + +// PADquery responses (notice - values ORed) +// PSEmu will use them also in PADinit to tell Plugin which Ports will use +// notice that PSEmu will call PADinit and PADopen only once when they are from +// same plugin + +// might be used in port 1 (must support PADreadPort1() function) +#define PSE_PAD_USE_PORT1 1 +// might be used in port 2 (must support PADreadPort2() function) +#define PSE_PAD_USE_PORT2 2 + + + +// MOUSE SCPH-1030 +#define PSE_PAD_TYPE_MOUSE 1 +// NEGCON - 16 button analog controller SLPH-00001 +#define PSE_PAD_TYPE_NEGCON 2 +// GUN CONTROLLER - gun controller SLPH-00014 from Konami +#define PSE_PAD_TYPE_GUN 3 +// STANDARD PAD SCPH-1080, SCPH-1150 +#define PSE_PAD_TYPE_STANDARD 4 +// ANALOG JOYSTICK SCPH-1110 +#define PSE_PAD_TYPE_ANALOGJOY 5 +// GUNCON - gun controller SLPH-00034 from Namco +#define PSE_PAD_TYPE_GUNCON 6 +// ANALOG CONTROLLER SCPH-1150 +#define PSE_PAD_TYPE_ANALOGPAD 7 + + +// sucess, everything configured, and went OK. +#define PSE_PAD_ERR_SUCCESS 0 +// general plugin failure (undefined error) +#define PSE_PAD_ERR_FAILURE -1 + + +// ERRORS +// this error might be returned as critical error but none of below +#define PSE_PAD_ERR -80 +// this driver is not configured +#define PSE_PAD_ERR_NOTCONFIGURED PSE_PAD_ERR - 1 +// this driver failed Init +#define PSE_PAD_ERR_INIT PSE_PAD_ERR - 2 + + +// WARNINGS +// this warning might be returned as undefined warning but allowing driver to continue +#define PSE_PAD_WARN 80 + + +typedef struct +{ + // controler type - fill it withe predefined values above + unsigned char controllerType; + + // status of buttons - every controller fills this field + unsigned short buttonStatus; + + // for analog pad fill those next 4 bytes + // values are analog in range 0-255 where 128 is center position + unsigned char rightJoyX, rightJoyY, leftJoyX, leftJoyY; + + // for mouse fill those next 2 bytes + // values are in range -128 - 127 + unsigned char moveX, moveY; + + unsigned char reserved[91]; + +} PadDataS; + +/* NET PlugIn v2 */ +/* Added by linuzappz@pcsx.net */ + +/* Modes bits for NETsendData/NETrecvData */ +#define PSE_NET_BLOCKING 0x00000000 +#define PSE_NET_NONBLOCKING 0x00000001 + +/* note: unsupported fields should be zeroed. + +typedef struct { + char EmuName[32]; + char CdromID[9]; // ie. 'SCPH12345', no \0 trailing character + char CdromLabel[11]; + void *psxMem; + GPUshowScreenPic GPU_showScreenPic; + GPUdisplayText GPU_displayText; + PADsetSensitive PAD_setSensitive; + char GPUpath[256]; + char SPUpath[256]; + char CDRpath[256]; + char MCD1path[256]; + char MCD2path[256]; + char BIOSpath[256]; // 'HLE' for internal bios + char Unused[1024]; +} netInfo; + +*/ + +/* + basic funcs: + + long NETopen(HWND hWnd) + opens the connection. + shall return 0 on success, else -1. + -1 is also returned if the user selects offline mode. + + long NETclose() + closes the connection. + shall return 0 on success, else -1. + + void NETpause() + this is called when the user paused the emulator. + + void NETresume() + this is called when the user resumed the emulator. + + long NETqueryPlayer() + returns player number + + long NETsendPadData(void *pData, int Size) + this should be called for the first pad only on each side. + + long NETrecvPadData(void *pData, int Pad) + call this for Pad 1/2 to get the data sent by the above func. + + extended funcs: + + long NETsendData(void *pData, int Size, int Mode) + sends Size bytes from pData to the other side. + + long NETrecvData(void *pData, int Size, int Mode) + receives Size bytes from pData to the other side. + + void NETsetInfo(netInfo *info); + sets the netInfo struct. + + void NETkeypressed(int key) (linux only) + key is a XK_?? (X11) keycode. +*/ + + +#endif // _PSEMU_PLUGIN_DEFS_H diff --git a/psxbios.c b/psxbios.c new file mode 100644 index 0000000..89a0221 --- /dev/null +++ b/psxbios.c @@ -0,0 +1,2476 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Internal emulated HLE BIOS. +*/ + +#include +#include +#include +#include +#include + +#include +extern char mcd1Written; +extern char mcd2Written; + +#include "psxbios.h" +#include "psxhw.h" + +//We try to emulate bios :) HELP US :P + +char *biosA0n[256] = { +// 0x00 + "open", "lseek", "read", "write", + "close", "ioctl", "exit", "sys_a0_07", + "getc", "putc", "todigit", "atof", + "strtoul", "strtol", "abs", "labs", +// 0x10 + "atoi", "atol", "atob", "setjmp", + "longjmp", "strcat", "strncat", "strcmp", + "strncmp", "strcpy", "strncpy", "strlen", + "index", "rindex", "strchr", "strrchr", +// 0x20 + "strpbrk", "strspn", "strcspn", "strtok", + "strstr", "toupper", "tolower", "bcopy", + "bzero", "bcmp", "memcpy", "memset", + "memmove", "memcmp", "memchr", "rand", +// 0x30 + "srand", "qsort", "strtod", "malloc", + "free", "lsearch", "bsearch", "calloc", + "realloc", "InitHeap", "_exit", "getchar", + "putchar", "gets", "puts", "printf", +// 0x40 + "sys_a0_40", "LoadTest", "Load", "Exec", + "FlushCache", "InstallInterruptHandler", "GPU_dw", "mem2vram", + "SendGPUStatus", "GPU_cw", "GPU_cwb", "SendPackets", + "sys_a0_4c", "GetGPUStatus", "GPU_sync", "sys_a0_4f", +// 0x50 + "sys_a0_50", "LoadExec", "GetSysSp", "sys_a0_53", + "_96_init()", "_bu_init()", "_96_remove()", "sys_a0_57", + "sys_a0_58", "sys_a0_59", "sys_a0_5a", "dev_tty_init", + "dev_tty_open", "sys_a0_5d", "dev_tty_ioctl","dev_cd_open", +// 0x60 + "dev_cd_read", "dev_cd_close", "dev_cd_firstfile", "dev_cd_nextfile", + "dev_cd_chdir", "dev_card_open", "dev_card_read", "dev_card_write", + "dev_card_close", "dev_card_firstfile", "dev_card_nextfile","dev_card_erase", + "dev_card_undelete","dev_card_format", "dev_card_rename", "dev_card_6f", +// 0x70 + "_bu_init", "_96_init", "_96_remove", "sys_a0_73", + "sys_a0_74", "sys_a0_75", "sys_a0_76", "sys_a0_77", + "_96_CdSeekL", "sys_a0_79", "sys_a0_7a", "sys_a0_7b", + "_96_CdGetStatus", "sys_a0_7d", "_96_CdRead", "sys_a0_7f", +// 0x80 + "sys_a0_80", "sys_a0_81", "sys_a0_82", "sys_a0_83", + "sys_a0_84", "_96_CdStop", "sys_a0_86", "sys_a0_87", + "sys_a0_88", "sys_a0_89", "sys_a0_8a", "sys_a0_8b", + "sys_a0_8c", "sys_a0_8d", "sys_a0_8e", "sys_a0_8f", +// 0x90 + "sys_a0_90", "sys_a0_91", "sys_a0_92", "sys_a0_93", + "sys_a0_94", "sys_a0_95", "AddCDROMDevice", "AddMemCardDevide", + "DisableKernelIORedirection", "EnableKernelIORedirection", "sys_a0_9a", "sys_a0_9b", + "SetConf", "GetConf", "sys_a0_9e", "SetMem", +// 0xa0 + "_boot", "SystemError", "EnqueueCdIntr", "DequeueCdIntr", + "sys_a0_a4", "ReadSector", "get_cd_status", "bufs_cb_0", + "bufs_cb_1", "bufs_cb_2", "bufs_cb_3", "_card_info", + "_card_load", "_card_auto", "bufs_cd_4", "sys_a0_af", +// 0xb0 + "sys_a0_b0", "sys_a0_b1", "do_a_long_jmp", "sys_a0_b3", + "?? sub_function", +}; + +char *biosB0n[256] = { +// 0x00 + "SysMalloc", "sys_b0_01", "sys_b0_02", "sys_b0_03", + "sys_b0_04", "sys_b0_05", "sys_b0_06", "DeliverEvent", + "OpenEvent", "CloseEvent", "WaitEvent", "TestEvent", + "EnableEvent", "DisableEvent", "OpenTh", "CloseTh", +// 0x10 + "ChangeTh", "sys_b0_11", "InitPAD", "StartPAD", + "StopPAD", "PAD_init", "PAD_dr", "ReturnFromExecption", + "ResetEntryInt", "HookEntryInt", "sys_b0_1a", "sys_b0_1b", + "sys_b0_1c", "sys_b0_1d", "sys_b0_1e", "sys_b0_1f", +// 0x20 + "UnDeliverEvent", "sys_b0_21", "sys_b0_22", "sys_b0_23", + "sys_b0_24", "sys_b0_25", "sys_b0_26", "sys_b0_27", + "sys_b0_28", "sys_b0_29", "sys_b0_2a", "sys_b0_2b", + "sys_b0_2c", "sys_b0_2d", "sys_b0_2e", "sys_b0_2f", +// 0x30 + "sys_b0_30", "sys_b0_31", "open", "lseek", + "read", "write", "close", "ioctl", + "exit", "sys_b0_39", "getc", "putc", + "getchar", "putchar", "gets", "puts", +// 0x40 + "cd", "format", "firstfile", "nextfile", + "rename", "delete", "undelete", "AddDevice", + "RemoteDevice", "PrintInstalledDevices", "InitCARD", "StartCARD", + "StopCARD", "sys_b0_4d", "_card_write", "_card_read", +// 0x50 + "_new_card", "Krom2RawAdd", "sys_b0_52", "sys_b0_53", + "_get_errno", "_get_error", "GetC0Table", "GetB0Table", + "_card_chan", "sys_b0_59", "sys_b0_5a", "ChangeClearPAD", + "_card_status", "_card_wait", +}; + +char *biosC0n[256] = { +// 0x00 + "InitRCnt", "InitException", "SysEnqIntRP", "SysDeqIntRP", + "get_free_EvCB_slot", "get_free_TCB_slot", "ExceptionHandler", "InstallExeptionHandler", + "SysInitMemory", "SysInitKMem", "ChangeClearRCnt", "SystemError", + "InitDefInt", "sys_c0_0d", "sys_c0_0e", "sys_c0_0f", +// 0x10 + "sys_c0_10", "sys_c0_11", "InstallDevices", "FlushStfInOutPut", + "sys_c0_14", "_cdevinput", "_cdevscan", "_circgetc", + "_circputc", "ioabort", "sys_c0_1a", "KernelRedirect", + "PatchAOTable", +}; + +//#define r0 (psxRegs.GPR.n.r0) +#define at (psxRegs.GPR.n.at) +#define v0 (psxRegs.GPR.n.v0) +#define v1 (psxRegs.GPR.n.v1) +#define a0 (psxRegs.GPR.n.a0) +#define a1 (psxRegs.GPR.n.a1) +#define a2 (psxRegs.GPR.n.a2) +#define a3 (psxRegs.GPR.n.a3) +#define t0 (psxRegs.GPR.n.t0) +#define t1 (psxRegs.GPR.n.t1) +#define t2 (psxRegs.GPR.n.t2) +#define t3 (psxRegs.GPR.n.t3) +#define t4 (psxRegs.GPR.n.t4) +#define t5 (psxRegs.GPR.n.t5) +#define t6 (psxRegs.GPR.n.t6) +#define t7 (psxRegs.GPR.n.t7) +#define s0 (psxRegs.GPR.n.s0) +#define s1 (psxRegs.GPR.n.s1) +#define s2 (psxRegs.GPR.n.s2) +#define s3 (psxRegs.GPR.n.s3) +#define s4 (psxRegs.GPR.n.s4) +#define s5 (psxRegs.GPR.n.s5) +#define s6 (psxRegs.GPR.n.s6) +#define s7 (psxRegs.GPR.n.s7) +#define t8 (psxRegs.GPR.n.t6) +#define t9 (psxRegs.GPR.n.t7) +#define k0 (psxRegs.GPR.n.k0) +#define k1 (psxRegs.GPR.n.k1) +#define gp (psxRegs.GPR.n.gp) +#define sp (psxRegs.GPR.n.sp) +#define fp (psxRegs.GPR.n.s8) +#define ra (psxRegs.GPR.n.ra) +#define pc0 (psxRegs.pc) + +#define SANE_PSXM(mem) ((u8*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#define Ra0 ((char*)SANE_PSXM(a0)) +#define Ra1 ((char*)SANE_PSXM(a1)) +#define Ra2 ((char*)SANE_PSXM(a2)) +#define Ra3 ((char*)SANE_PSXM(a3)) +#define Rv0 ((char*)SANE_PSXM(v0)) +#define Rsp ((char*)SANE_PSXM(sp)) + + + +typedef struct _malloc_chunk { + unsigned long stat; + unsigned long size; + struct _malloc_chunk *fd; + struct _malloc_chunk *bk; +} malloc_chunk; + +#define INUSE 0x1 + +typedef struct { + u32 desc; + s32 status; + s32 mode; + u32 fhandler; +} EvCB[32]; + +#define EvStUNUSED 0x0000 +#define EvStWAIT 0x1000 +#define EvStACTIVE 0x2000 +#define EvStALREADY 0x4000 + +#define EvMdINTR 0x1000 +#define EvMdNOINTR 0x2000 + +/* +typedef struct { + long next; + long func1; + long func2; + long pad; +} SysRPst; +*/ + +typedef struct { + s32 status; + s32 mode; + u32 reg[32]; + u32 func; +} TCB; + +typedef struct { + u32 _pc0; + u32 gp0; + u32 t_addr; + u32 t_size; + u32 d_addr; + u32 d_size; + u32 b_addr; + u32 b_size; + u32 S_addr; + u32 s_size; + u32 _sp,_fp,_gp,ret,base; +} EXEC; + +struct DIRENTRY { + char name[20]; + long attr; + long size; + struct DIRENTRY *next; + long head; + char system[4]; +}; + +typedef struct { + char name[32]; + u32 mode; + u32 offset; + u32 size; + u32 mcfile; +} FileDesc; + +static u32 *jmp_int = NULL; +static int *pad_buf = NULL; +static char *pad_buf1,*pad_buf2;//shadow add +static int pad_buf1len,pad_buf2len;//shadow add + + +static u32 regs[35]; +static EvCB *Event; +static EvCB *HwEV; // 0xf0 +static EvCB *EvEV; // 0xf1 +static EvCB *RcEV; // 0xf2 +static EvCB *UeEV; // 0xf3 +static EvCB *SwEV; // 0xf4 +static EvCB *ThEV; // 0xff +static u32 *heap_addr = NULL; +static u32 SysIntRP[8]; +static int CardState = -1; +static TCB Thread[8]; +static int CurThread = 0; +static FileDesc FDesc[32]; + +static __inline void softCall(u32 pc) { + pc0 = pc; + ra = 0x80001000; + while (pc0 != 0x80001000) psxCpu->ExecuteBlock(); +} + +static __inline void softCall2(u32 pc) { + u32 sra = ra; + pc0 = pc; + ra = 0x80001000; + while (pc0 != 0x80001000) psxCpu->ExecuteBlock(); + ra = sra; +} + +static __inline void DeliverEvent(u32 ev, u32 spec) { + if (Event[ev][spec].status != SWAP32(EvStACTIVE)) return; + +// Event[ev][spec].status = SWAP32(EvStALREADY); + if (Event[ev][spec].mode == SWAP32(EvMdINTR)) { + softCall2(SWAP32(Event[ev][spec].fhandler)); + } else Event[ev][spec].status = SWAP32(EvStALREADY); +} + +/* * +// * +// * +// System calls A0 */ + + +void psxBios_abs() { // 0x0e + v0 = abs(a0); + pc0 = ra; +} + +void psxBios_labs() { // 0x0f + v0 = labs(a0); + pc0 = ra; +} + +void psxBios_atoi() { // 0x10 + v0 = atoi((char *)Ra0); + pc0 = ra; +} + +void psxBios_atol() { // 0x11 + v0 = atoi((char *)Ra0); + pc0 = ra; +} + +void psxBios_setjmp() { // 13 + u32 *jmp_buf= (u32*)Ra0; + int i; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x13]); +#endif + + jmp_buf[0] = SWAP32(ra); + jmp_buf[1] = SWAP32(sp); + jmp_buf[2] = SWAP32(fp); + for (i=0; i<8; i++) // s0-s7 + jmp_buf[3+i] = SWAP32(psxRegs.GPR.r[16+i]); + jmp_buf[11] = SWAP32(gp); + + v0 = 0; pc0 = ra; +} + +void psxBios_longjmp() { //14 + u32 *jmp_buf= (u32*)Ra0; + int i; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x14]); +#endif + + ra = SWAP32(jmp_buf[0]); /* ra */ + sp = SWAP32(jmp_buf[1]); /* sp */ + fp = SWAP32(jmp_buf[2]); /* fp */ + for (i=0; i<8; i++) // s0-s7 + psxRegs.GPR.r[16+i] = SWAP32(jmp_buf[3+i]); + gp = SWAP32(jmp_buf[11]); /* gp */ + + v0 = a1; pc0 = ra; +} + +void psxBios_strcat() { // 0x15 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s, %s\n", biosA0n[0x15], Ra0, Ra1); +#endif + + strcat(Ra0, Ra1); + v0 = a0; pc0 = ra; +} + +/*0x16*/void psxBios_strncat() { strncat(Ra0, Ra1, a2); v0 = a0; pc0 = ra;} + +void psxBios_strcmp() { // 0x17 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s (%lx), %s (%lx)\n", biosA0n[0x17], Ra0, a0, Ra1, a1); +#endif + + v0 = strcmp(Ra0, Ra1); + pc0 = ra; +} + +void psxBios_strncmp() { // 0x18 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s (%lx), %s (%lx), %d\n", biosA0n[0x18], Ra0, a0, Ra1, a1, a2); +#endif + + v0 = strncmp(Ra0, Ra1, a2); + pc0 = ra; +} + +/*0x19*/void psxBios_strcpy() { strcpy(Ra0, Ra1); v0 = a0; pc0 = ra;} +/*0x1a*/void psxBios_strncpy() { strncpy(Ra0, Ra1, a2); v0 = a0; pc0 = ra;} +/*0x1b*/void psxBios_strlen() { v0 = strlen(Ra0); pc0 = ra;} + +void psxBios_index() { // 0x1c + char *pcA0 = (char *)Ra0; + char *pcRet = strchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_rindex() { // 0x1d + char *pcA0 = (char *)Ra0; + char *pcRet = strrchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_strchr() { // 0x1e + char *pcA0 = (char *)Ra0; + char *pcRet = strchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_strrchr() { // 0x1f + char *pcA0 = (char *)Ra0; + char *pcRet = strrchr(pcA0, a1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_strpbrk() { // 0x20 + char *pcA0 = (char *)Ra0; + char *pcRet = strpbrk(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_strspn() { v0 = strspn ((char *)Ra0, (char *)Ra1); pc0 = ra;}/*21*/ +void psxBios_strcspn() { v0 = strcspn((char *)Ra0, (char *)Ra1); pc0 = ra;}/*22*/ + +void psxBios_strtok() { // 0x23 + char *pcA0 = (char *)Ra0; + char *pcRet = strtok(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +void psxBios_strstr() { // 0x24 + char *pcA0 = (char *)Ra0; + char *pcRet = strstr(pcA0, (char *)Ra1); + if(pcRet) + v0 = a0 + pcRet - pcA0; + else + v0 = 0; + pc0 = ra; +} + +/*0x25*/void psxBios_toupper() {v0 = toupper(a0); pc0 = ra;} +/*0x26*/void psxBios_tolower() {v0 = tolower(a0); pc0 = ra;} +/*0x27*/void psxBios_bcopy() {memcpy(Ra1,Ra0,a2); pc0=ra;} +/*0x28*/void psxBios_bzero() {memset(Ra0,0,a1); pc0=ra;} +/*0x29*/void psxBios_bcmp() {v0 = memcmp(Ra0,Ra1,a2); pc0=ra; } +/*0x2a*/void psxBios_memcpy() {memcpy(Ra0, Ra1, a2); v0 = a0; pc0 = ra;} +/*0x2b*/void psxBios_memset() {memset(Ra0, a1, a2); v0 = a0; pc0 = ra;} +/*0x2c*/void psxBios_memmove() {memmove(Ra0, Ra1, a2); v0 = a0; pc0 = ra;} +/*0x2d*/void psxBios_memcmp() {v0 = memcmp(Ra0, Ra1, a2); pc0 = ra;} + +void psxBios_memchr() { // 2e + void *ret = memchr(Ra0, a1, a2); + if (ret != NULL) v0 = (u32)((char*)ret - Ra0) + a0; + else v0 = 0; + pc0 = ra; +} + +void psxBios_rand() { // 2f + v0 = 1+(int) (32767.0*rand()/(RAND_MAX+1.0)); + pc0 = ra; +} + +void psxBios_srand() { // 30 + srand(a0); pc0 = ra; +} + +void psxBios_malloc() { // 33 + malloc_chunk *chunk; + malloc_chunk *fd; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x33]); +#endif + + chunk = (malloc_chunk *)heap_addr; + if (chunk == NULL) { v0 = 0; return; } + + for (; ((a0 > SWAP32(chunk->size)) || chunk->stat == SWAP32(INUSE)) || (chunk->fd != NULL); chunk = (malloc_chunk *)SWAP32((unsigned long)chunk->fd)); +//printf ("chunk %lx\n",chunk->size); + /* split free chunk */ + fd = chunk + sizeof(malloc_chunk) + a0; + fd->stat = SWAP32(chunk->stat); + fd->size = SWAP32(chunk->size - a0); + fd->fd = (malloc_chunk *)SWAP32((unsigned long)chunk->fd); + fd->bk = (malloc_chunk *)SWAP32((unsigned long)chunk); + + /* set new chunk */ + chunk->stat = SWAP32(INUSE); + chunk->size = SWAP32(a0); + chunk->fd = (malloc_chunk *)SWAP32((unsigned long)fd); + + v0 = ((unsigned long)chunk - (unsigned long)psxM) + sizeof(malloc_chunk); + v0|= 0x80000000; +// printf ("malloc %lx,%lx\n", v0, a0); + pc0 = ra; +} + +void psxBios_InitHeap() { // 39 + malloc_chunk *chunk; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x39]); +#endif + + heap_addr = (u32*)Ra0; + + chunk = (malloc_chunk *)heap_addr; + chunk->stat = 0; + if (((a0 & 0x1fffff) + a1)>= 0x200000) chunk->size = SWAP32(0x1ffffc - (a0 & 0x1fffff)); + else chunk->size = SWAP32(a1); + chunk->fd = NULL; + chunk->bk = NULL; + + //SysPrintf("InitHeap %lx,%lx : %lx\n",a0,a1,SWAP32(chunk->size)); + + pc0 = ra; +} + +void psxBios_getchar(){ v0 = getchar(); pc0=ra;} //0x3b + +void psxBios_printf() { // 3f + char tmp[1024]; + char tmp2[1024]; + unsigned long save[4]; + char *ptmp = tmp; + int n=1, i=0, j, t; + + memcpy(save, (char*)SANE_PSXM(sp), 4*4); + psxMu32ref(sp) = SWAP32((u32)a0); + psxMu32ref(sp + 4) = SWAP32((u32)a1); + psxMu32ref(sp + 8) = SWAP32((u32)a2); + psxMu32ref(sp + 12) = SWAP32((u32)a3); + + while (Ra0[i]) { + switch (Ra0[i]) { + case '%': + j = 0; + tmp2[j++] = '%'; +_start: + switch (Ra0[++i]) { + case '.': + case 'l': + tmp2[j++] = Ra0[i]; goto _start; + default: + if (Ra0[i] >= '0' && Ra0[i] <= '9') { + tmp2[j++] = Ra0[i]; + goto _start; + } + break; + } + tmp2[j++] = Ra0[i]; + tmp2[j] = 0; + + switch (Ra0[i]) { + case 'f': case 'F': + t = sp + n * 4; + ptmp+= sprintf(ptmp, tmp2, (float)psxMu32(t)); n++; break; + case 'a': case 'A': + case 'e': case 'E': + case 'g': case 'G': + t = sp + n * 4; + ptmp+= sprintf(ptmp, tmp2, (double)psxMu32(t)); n++; break; + case 'p': + case 'i': + case 'd': case 'D': + case 'o': case 'O': + case 'x': case 'X': + t = sp + n * 4; + ptmp+= sprintf(ptmp, tmp2, (unsigned int)psxMu32(t)); n++; break; + case 'c': + t = sp + n * 4; + ptmp+= sprintf(ptmp, tmp2, (unsigned char)psxMu32(t)); n++; break; + case 's': + t = sp + n * 4; + ptmp+= sprintf(ptmp, tmp2, (char*)PSXM(psxMu32(t))); n++; break; + case '%': + *ptmp++ = Ra0[i]; break; + } + i++; + break; + default: + *ptmp++ = Ra0[i++]; + } + } + *ptmp = 0; + + memcpy((char*)SANE_PSXM(sp), save, 4*4); + + //SysPrintf(tmp); + + pc0 = ra; +} + +/* + * long Load(char *name, struct EXEC *header); + */ + +void psxBios_Load() { // 42 + EXE_HEADER eheader; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s, %x\n", biosA0n[0x42], Ra0, a1); +#endif + + if (LoadCdromFile(Ra0, &eheader) == 0) { + memcpy(Ra1, ((char*)&eheader)+16, sizeof(EXEC)); + v0 = 1; + } else v0 = 0; + + pc0 = ra; +} + +/* + * int Exec(struct EXEC *header , int argc , char **argv); + */ + +void psxBios_Exec() { // 43 + EXEC *header = (EXEC*)Ra0; + u32 tmp; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosA0n[0x43], a0, a1, a2); +#endif + + header->_sp = SWAP32(sp); + header->_fp = SWAP32(fp); + header->_sp = SWAP32(sp); + header->_gp = SWAP32(gp); + header->ret = SWAP32(ra); + header->base = SWAP32(s0); + + if (header->S_addr != 0) { + tmp = SWAP32(header->S_addr) + SWAP32(header->s_size); + sp = tmp; + fp = sp; + } + + gp = SWAP32(header->gp0); + + s0 = a0; + + a0 = a1; + a1 = a2; + + ra = 0x8000; + pc0 = SWAP32(header->_pc0); +} + +void psxBios_FlushCache() { // 44 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x44]); +#endif + + pc0 = ra; +} + +void psxBios_GPU_dw() { // 0x46 + int size; + long *ptr; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x46]); +#endif + + GPU_writeData(0xa0000000); + GPU_writeData((a1<<16)|(a0&0xffff)); + GPU_writeData((a3<<16)|(a2&0xffff)); + size = (a2*a3+1)/2; + ptr = (long*)PSXM(Rsp[4]); //that is correct? + do { + GPU_writeData(SWAP32(*ptr)); + ptr++; + } while(--size); + + pc0 = ra; +} + +void psxBios_mem2vram() { // 0x47 + int size; + + GPU_writeData(0xa0000000); + GPU_writeData((a1<<16)|(a0&0xffff)); + GPU_writeData((a3<<16)|(a2&0xffff)); + size = (a2*a3+1)/2; + GPU_writeStatus(0x04000002); + psxHwWrite32(0x1f8010f4,0); + psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800); + psxHwWrite32(0x1f8010a0,(unsigned long)Rsp[4]);//might have a buggy... + psxHwWrite32(0x1f8010a4,((size/16)<<16)|16); + psxHwWrite32(0x1f8010a8,0x01000201); + + pc0 = ra; +} + +void psxBios_SendGPU() { // 0x48 + GPU_writeStatus(a0); + pc0 = ra; +} + +void psxBios_GPU_cw() { // 0x49 + GPU_writeData(a0); + pc0 = ra; +} + +void psxBios_GPU_cwb() { // 0x4a + long *ptr = (long*)Ra0; + int size = a1; + while(size--) { + GPU_writeData(SWAP32(*ptr)); + ptr++; + } + + pc0 = ra; +} + +void psxBios_GPU_SendPackets() { //4b: + GPU_writeStatus(0x04000002); + psxHwWrite32(0x1f8010f4,0); + psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800); + psxHwWrite32(0x1f8010a0,a0); + psxHwWrite32(0x1f8010a4,0); + psxHwWrite32(0x1f8010a8,0x010000401); + pc0 = ra; +} + +void psxBios_sys_a0_4c() { // 0x4c GPU relate + psxHwWrite32(0x1f8010a8,0x00000401); + GPU_writeData(0x0400000); + GPU_writeData(0x0200000); + GPU_writeData(0x0100000); + + pc0 = ra; +} + +void psxBios_GPU_GetGPUStatus() { // 0x4d + v0 = GPU_readStatus(); + pc0 = ra; +} + +#undef s_addr + +void psxBios_LoadExec() { // 51 + EXEC *header = (EXEC*)PSXM(0xf000); + u32 s_addr, s_size; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s: %x,%x\n", biosA0n[0x51], Ra0, a1, a2); +#endif + s_addr = a1; s_size = a2; + + a1 = 0xf000; + psxBios_Load(); + + header->S_addr = SWAP32(s_addr); + header->s_size = SWAP32(s_size); + + a0 = 0xf000; a1 = 0; a2 = 0; + psxBios_Exec(); +} + +void psxBios__bu_init() { // 70 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x70]); +#endif + + DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 + DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + pc0 = ra; +} + +void psxBios__96_init() { // 71 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x71]); +#endif + + pc0 = ra; +} + +void psxBios__96_remove() { // 72 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosA0n[0x72]); +#endif + + pc0 = ra; +} + +void psxBios__card_info() { // ab +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0); +#endif + +// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 + DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + v0 = 1; pc0 = ra; +} + +void psxBios__card_load() { // ac +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xac], a0); +#endif + +// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 + DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + v0 = 1; pc0 = ra; +} + +/* System calls B0 */ + +void psxBios_SetRCnt() { // 02 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x02]); +#endif + + a0&= 0x3; + if (a0 != 3) { + unsigned long mode=0; + + psxRcntWtarget(a0, a1); + if (a2&0x1000) mode|= 0x050; // Interrupt Mode + if (a2&0x0100) mode|= 0x008; // Count to 0xffff + if (a2&0x0010) mode|= 0x001; // Timer stop mode + if (a0 == 2) { if (a2&0x0001) mode|= 0x200; } // System Clock mode + else { if (a2&0x0001) mode|= 0x100; } // System Clock mode + + psxRcntWmode(a0, mode); + } + pc0 = ra; +} + +void psxBios_GetRCnt() { // 03 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x03]); +#endif + + a0&= 0x3; + if (a0 != 3) v0 = psxRcntRcount(a0); + else v0 = 0; + pc0 = ra; +} + +void psxBios_StartRCnt() { // 04 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x04]); +#endif + + a0&= 0x3; + if (a0 != 3) psxHu32ref(0x1074)|= SWAP32((u32)((1<<(a0+4)))); + else psxHu32ref(0x1074)|= SWAPu32(0x1); + + v0 = 1; pc0 = ra; +} + +void psxBios_StopRCnt() { // 05 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x05]); +#endif + + a0&= 0x3; + if (a0 != 3) psxHu32ref(0x1074)&= SWAP32((u32)(~(1<<(a0+4)))); + else psxHu32ref(0x1074)&= SWAPu32(~0x1); + + pc0 = ra; +} + +void psxBios_ResetRCnt() { // 06 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x06]); +#endif + + a0&= 0x3; + if (a0 != 3) { + psxRcntWmode(a0, 0); + psxRcntWtarget(a0, 0); + psxRcntWcount(a0, 0); + } + pc0 = ra; +} + + +/* gets ev for use with Event */ +#define GetEv() \ + ev = (a0 >> 24) & 0xf; \ + if (ev == 0xf) ev = 0x5; \ + ev*= 32; \ + ev+= a0&0x1f; + +/* gets spec for use with Event */ +#define GetSpec() \ + spec = 0; \ + switch (a1) { \ + case 0x0301: spec = 16; break; \ + case 0x0302: spec = 17; break; \ + default: \ + for (i=0; i<16; i++) if (a1 & (1 << i)) { spec = i; break; } \ + break; \ + } + +void psxBios_DeliverEvent() { // 07 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x07], ev, spec); +#endif + + DeliverEvent(ev, spec); + + pc0 = ra; +} + +void psxBios_OpenEvent() { // 08 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x (class:%lx, spec:%lx, mode:%lx, func:%lx)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3); +#endif + + Event[ev][spec].status = SWAP32(EvStWAIT); + Event[ev][spec].mode = SWAP32(a2); + Event[ev][spec].fhandler = SWAP32(a3); + + v0 = ev | (spec << 8); + pc0 = ra; +} + +void psxBios_CloseEvent() { // 09 + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec); +#endif + + Event[ev][spec].status = SWAP32(EvStUNUSED); + + v0 = 1; pc0 = ra; +} + +void psxBios_WaitEvent() { // 0a + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec); +#endif + + Event[ev][spec].status = SWAP32(EvStACTIVE); + + v0 = 1; pc0 = ra; +} + +void psxBios_TestEvent() { // 0b + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + + if (Event[ev][spec].status == SWAP32(EvStALREADY)) { + Event[ev][spec].status = SWAP32(EvStACTIVE); v0 = 1; + } else v0 = 0; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x: %x\n", biosB0n[0x0b], ev, spec, v0); +#endif + + pc0 = ra; +} + +void psxBios_EnableEvent() { // 0c + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec); +#endif + + Event[ev][spec].status = SWAP32(EvStACTIVE); + + v0 = 1; pc0 = ra; +} + +void psxBios_DisableEvent() { // 0d + int ev, spec; + + ev = a0 & 0xff; + spec = (a0 >> 8) & 0xff; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec); +#endif + + Event[ev][spec].status = SWAP32(EvStWAIT); + + v0 = 1; pc0 = ra; +} + +/* + * long OpenTh(long (*func)(), unsigned long sp, unsigned long gp); + */ + +void psxBios_OpenTh() { // 0e + int th; + + for (th=1; th<8; th++) + if (Thread[th].status == 0) break; + if (th>7) return; //No threads available? + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th); +#endif + + Thread[th].status = 1; + Thread[th].func = a0; + Thread[th].reg[29] = a1; + Thread[th].reg[28] = a2; + + v0 = th; pc0 = ra; +} + +/* + * int CloseTh(long thread); + */ + +void psxBios_CloseTh() { // 0f + int th = a0 & 0xff; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0f], th); +#endif + + if (Thread[th].status == 0) { + v0 = 0; + } else { + Thread[th].status = 0; + v0 = 1; + } + + pc0 = ra; +} + +/* + * int ChangeTh(long thread); + */ + +void psxBios_ChangeTh() { // 10 + int th = a0 & 0xff; + +#ifdef PSXBIOS_LOG +// PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x10], th); +#endif + + if (Thread[th].status == 0 || CurThread == th) { + v0 = 0; + + pc0 = ra; + } else { + v0 = 1; + + if (Thread[CurThread].status == 2) { + Thread[CurThread].status = 1; + Thread[CurThread].func = ra; + memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4); + } + + memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4); + pc0 = Thread[th].func; + Thread[th].status = 2; + CurThread = th; + } +} + +void psxBios_InitPAD() { // 0x12 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x12]); +#endif + + pad_buf1 = (char*)Ra0; + pad_buf1len = a1; + pad_buf2 = (char*)Ra2; + pad_buf2len = a3; + + v0 = 1; pc0 = ra; +} + +void psxBios_StartPAD() { // 13 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x13]); +#endif + + psxHwWrite16(0x1f801074, (unsigned short)(psxHwRead16(0x1f801074) | 0x1)); + psxRegs.CP0.n.Status |= 0x401; + + pc0 = ra; +} + +void psxBios_StopPAD() { // 14 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x14]); +#endif + + pad_buf1 = NULL; + pad_buf2 = NULL; + pc0 = ra; +} + +void psxBios_PAD_init() { // 15 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x15]); +#endif + + psxHwWrite16(0x1f801074, (u16)(psxHwRead16(0x1f801074) | 0x1)); + pad_buf = (int*)Ra1; + *pad_buf = SWAP32(-1); + psxRegs.CP0.n.Status |= 0x401; + + pc0 = ra; +} + +void psxBios_PAD_dr() { // 16 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x16]); +#endif + + v0 = -1; pc0 = ra; +} + +void psxBios_ReturnFromException() { // 17 + memcpy(psxRegs.GPR.r, regs, 32*4); + psxRegs.GPR.n.lo = regs[32]; + psxRegs.GPR.n.hi = regs[33]; + + pc0 = psxRegs.CP0.n.EPC; + if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); + +} + +void psxBios_ResetEntryInt() { // 18 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x18]); +#endif + + jmp_int = NULL; + pc0 = ra; +} + +void psxBios_HookEntryInt() { // 19 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x19]); +#endif + + jmp_int = (u32*)Ra0; + pc0 = ra; +} + +void psxBios_UnDeliverEvent() { // 0x20 + int ev, spec; + int i; + + GetEv(); + GetSpec(); + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x07], ev, spec); +#endif + + if (Event[ev][spec].status == SWAP32(EvStALREADY) && + Event[ev][spec].mode == SWAP32(EvMdNOINTR)) + Event[ev][spec].status = SWAP32(EvStACTIVE); + + pc0 = ra; +} + +#define buopen(slot) { \ + strcpy(FDesc[1 + slot].name, Ra0+5); \ + FDesc[1 + slot].offset = 0; \ + FDesc[1 + slot].mode = a1; \ + \ + for (i=1; i<16; i++) { \ + ptr = Mcd##slot##Data + 128 * i; \ + if ((*ptr & 0xF0) != 0x50) continue; \ + if (strcmp(FDesc[1 + slot].name, ptr+0xa)) continue; \ + FDesc[1 + slot].mcfile = i; \ + /*SysPrintf("open %s\n", ptr+0xa);*/ \ + v0 = 1 + slot; \ + break; \ + } \ + if (a1 & 0x200 && (s32)v0 == -1) { /* FCREAT */ \ + for (i=1; i<16; i++) { \ + int j, xor = 0; \ + \ + ptr = Mcd##slot##Data + 128 * i; \ + if ((*ptr & 0xF0) == 0x50) continue; \ + ptr[0] = 0x50 | (u8)(a1 >> 16); \ + ptr[4] = 0x00; \ + ptr[5] = 0x20; \ + ptr[6] = 0x00; \ + ptr[7] = 0x00; \ + ptr[8] = 'B'; \ + ptr[9] = 'I'; \ + strcpy(ptr+0xa, FDesc[1 + slot].name); \ + for (j=0; j<127; j++) xor^= ptr[j]; \ + ptr[127] = xor; \ + FDesc[1 + slot].mcfile = i; \ + /*SysPrintf("openC %s\n", ptr);*/ \ + v0 = 1 + slot; \ + mcd##slot##Written = 1; \ + break; \ + } \ + } \ +} + +/* + * int open(char *name , int mode); + */ + +void psxBios_open() { // 0x32 + int i; + char *ptr; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s,%x\n", biosB0n[0x32], Ra0, a1); +#endif + + v0 = -1; + + if (!strncmp(Ra0, "bu00", 4)) { + buopen(1); + } + + if (!strncmp(Ra0, "bu10", 4)) { + buopen(2); + } + + pc0 = ra; +} + +/* + * int lseek(int fd , int offset , int whence); + */ + +void psxBios_lseek() { // 0x33 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x33], a0, a1, a2); +#endif + + switch (a2) { + case 0: // SEEK_SET + FDesc[a0].offset = a1; + v0 = a1; +// DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 +// DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + break; + + case 1: // SEEK_CUR + FDesc[a0].offset+= a1; + v0 = FDesc[a0].offset; + break; + } + + pc0 = ra; +} + +#define buread(mcd) { \ + /*SysPrintf("read %d: %x,%x (%s)\n", FDesc[1 + mcd].mcfile, FDesc[1 + mcd].offset, a2, Mcd##mcd##Data + 128 * FDesc[1 + mcd].mcfile + 0xa);*/ \ + ptr = Mcd##mcd##Data + 8192 * FDesc[1 + mcd].mcfile + FDesc[1 + mcd].offset; \ + memcpy(Ra1, ptr, a2); \ + if (FDesc[1 + mcd].mode & 0x8000) v0 = 0; \ + else v0 = a2; \ + DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ + DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ +} + +/* + * int read(int fd , void *buf , int nbytes); + */ + +void psxBios_read() { // 0x34 + char *ptr; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x, %x, %x\n", biosB0n[0x34], a0, a1, a2); +#endif + + v0 = -1; + + switch (a0) { + case 2: buread(1); break; + case 3: buread(2); break; + } + + pc0 = ra; +} + +#define buwrite(slot) { \ + u32 offset = + 8192 * FDesc[1 + slot].mcfile + FDesc[1 + slot].offset; \ + /*SysPrintf("write %d: %x,%x\n", FDesc[1 + slot].mcfile, FDesc[1 + slot].offset, a2);*/ \ + ptr = Mcd##slot##Data + offset; \ + memcpy(ptr, Ra1, a2); \ + mcd##slot##Written = 1; \ + if (FDesc[1 + slot].mode & 0x8000) v0 = 0; \ + else v0 = a2; \ + DeliverEvent(0x11, 0x2); /* 0xf0000011, 0x0004 */ \ + DeliverEvent(0x81, 0x2); /* 0xf4000001, 0x0004 */ \ +} + +/* + * int write(int fd , void *buf , int nbytes); + */ + +void psxBios_write() { // 0x35/0x03 + char *ptr; + + if (a0 == 1) { // stdout + //char *ptr = Ra1; + + /*while (a2 > 0) { + SysPrintf("%c", *ptr++); a2--; + }*/ + a2 = 0; + pc0 = ra; return; + } +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x35], a0, a1, a2); +#endif + + v0 = -1; + + switch (a0) { + case 2: buwrite(1); break; + case 3: buwrite(2); break; + } + + pc0 = ra; +} + +/* + * int close(int fd); + */ + +void psxBios_close() { // 0x36 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x36], a0); +#endif + + v0 = a0; pc0 = ra; +} + +void psxBios_putchar () { // 3d + char tmp[12]; + + sprintf (tmp,"%c",(char)a0); + //SysPrintf(tmp); + + pc0 = ra; +} + +void psxBios_puts () { // 3e/3f + //SysPrintf(Ra0); + + pc0 = ra; +} + +char ffile[64], *pfile; +int nfile; + +#define bufile(mcd) { \ + while (nfile < 16) { \ + int match=1; \ + \ + ptr = Mcd##mcd##Data + 128 * nfile; \ + nfile++; \ + if ((*ptr & 0xF0) != 0x50) continue; \ + ptr+= 0xa; \ + for (i=0; i<20; i++) { \ + if (pfile[i] == ptr[i]) { \ + dir->name[i] = ptr[i]; \ + if (ptr[i] == 0) break; else continue; } \ + if (pfile[i] == '?') { \ + dir->name[i] = ptr[i]; continue; } \ + if (pfile[i] == '*') { \ + strcpy(dir->name+i, ptr+i); break; } \ + match = 0; break; \ + } \ + /*SysPrintf("%d : %s = %s + %s (match=%d)\n", nfile, dir->name, pfile, ptr, match);*/ \ + if (match == 0) continue; \ + dir->size = SWAP32(8192); \ + v0 = _dir; \ + break; \ + } \ +} + +/* + * struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir); + */ + +void psxBios_firstfile() { // 42 + struct DIRENTRY *dir = (struct DIRENTRY *)Ra1; + u32 _dir = a1; + char *ptr; + int i; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x42], Ra0); +#endif + + v0 = 0; + + strcpy(ffile, Ra0); + pfile = ffile+5; + nfile = 1; + if (!strncmp(Ra0, "bu00", 4)) { + bufile(1); + v0 = _dir; + } + + if (!strncmp(Ra0, "bu10", 4)) { + bufile(2); + v0 = _dir; + } + + pc0 = ra; +} + +/* + * struct DIRENTRY* nextfile(struct DIRENTRY *dir); + */ + +void psxBios_nextfile() { // 43 + struct DIRENTRY *dir = (struct DIRENTRY *)Ra0; + u32 _dir = a0; + char *ptr; + int i; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x43], dir->name); +#endif + + v0 = 0; + + if (!strncmp(ffile, "bu00", 4)) { + bufile(1); + } + + if (!strncmp(ffile, "bu10", 4)) { + bufile(2); + } + + pc0 = ra; +} + +#define budelete(slot) { \ + for (i=1; i<16; i++) { \ + ptr = Mcd##slot##Data + 128 * i; \ + if ((*ptr & 0xF0) != 0x50) continue; \ + if (strcmp(Ra0+5, ptr+0xa)) continue; \ + *ptr = (*ptr & 0xf) | 0xA0; \ + /*SysPrintf("delete %s\n", ptr+0xa);*/ \ + mcd##slot##Written = 1; \ + v0 = 1; \ + break; \ + } \ +} + +/* + * int delete(char *name); + */ + +void psxBios_delete() { // 45 + char *ptr; + int i; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %s\n", biosB0n[0x45], Ra0); +#endif + + v0 = 0; + + if (!strncmp(Ra0, "bu00", 4)) { + budelete(1); + } + + if (!strncmp(Ra0, "bu10", 4)) { + budelete(2); + } + + pc0 = ra; +} + +void psxBios_InitCARD() { // 4a +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x4a], a0); +#endif + + CardState = 0; + + pc0 = ra; +} + +void psxBios_StartCARD() { // 4b +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4b]); +#endif + + if (CardState == 0) CardState = 1; + + pc0 = ra; +} + +void psxBios_StopCARD() { // 4c +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4c]); +#endif + + if (CardState == 1) CardState = 0; + + pc0 = ra; +} + +void psxBios__card_write() { // 0x4e + int port; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x,%x,%x\n", biosB0n[0x4e], a0, a1, a2); +#endif + + port = a0 >> 4; + + if (port == 0) { + memcpy(Mcd1Data + a1 * 128, Ra2, 128); + mcd1Written = 1; + } else { + memcpy(Mcd2Data + a1 * 128, Ra2, 128); + mcd2Written = 1; + } + + DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 +// DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + v0 = 1; pc0 = ra; +} + +void psxBios__card_read() { // 0x4f + int port; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x4f]); +#endif + + port = a0 >> 4; + + if (port == 0) { + memcpy(Ra2, Mcd1Data + a1 * 128, 128); + } else { + memcpy(Ra2, Mcd2Data + a1 * 128, 128); + } + + DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004 +// DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004 + + v0 = 1; pc0 = ra; +} + +void psxBios__new_card() { // 0x50 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x50]); +#endif + + pc0 = ra; +} + +typedef struct { + char id[6]; + char fontname[8]; + unsigned char w,h; + unsigned char type; + unsigned char ntbl; + unsigned short codetbl[1]; +} FONTXHDR; + +void psxBios_Krom2RawAdd() { // 0x51 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x51]); +#endif +#if 1 + // FPSE rip + { + FONTXHDR *font = (FONTXHDR *)&psxRs8ref(0x20000); + unsigned short *ptbl = font->codetbl; + int size = ((font->w+7)/8)*font->h; + int code, n=0,i; + + a0 &= 0xffff; + v0 = 0; + code = a0; + + for(i=0;intbl;i++) { + if (code>=SWAP16p(&ptbl[0]) && code<=SWAP16p(&ptbl[1])) { + v0 = 0xbfc20000 + ((char*)&font->codetbl[font->ntbl*2] - (char *)font) + (code-SWAP16p(&ptbl[0])+n)*size+2; /* skip */ + break; + } + n += SWAP16p(&ptbl[1])-SWAP16p(&ptbl[0]) + 1; + ptbl+=2; + } + } +#else + a0 &= 0xffff; + + if (a0 == 0x8260) { + v0 = 0xbfc67266; + } else { + v0 = 0xffffffff; + } + +/* if (a0 > 0x8140 && a0 <= 0x84bf) { + hi = a0 >> 8; + hi -= 0x81; + if (hi < 4) { + switch (hi) { + case 1: + if (lo < 0x4f) { + + } else if (lo < 0x59) { + + } else if (lo < 0x60) { + + } else if (lo < 0x7a) { + offset = 8; + } + break; + default: + printf("unknown case\n"); + } + } + } else { + printf("unknown state\n"); + }*/ +#endif + pc0 = ra; +} + +void psxBios_GetC0Table() { // 56 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x56]); +#endif + + v0 = 0x674; pc0 = ra; +} + +void psxBios_GetB0Table() { // 57 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s\n", biosB0n[0x57]); +#endif + + v0 = 0x874; pc0 = ra; +} + +void psxBios_ChangeClearPad() { // 5b +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0); +#endif + + // TODO: find out if v0 should be set as is done in FS + + pc0 = ra; +} + +/* System calls C0 */ + +/* + * int SysEnqIntRP(int index , long *queue); + */ + +void psxBios_SysEnqIntRP() { // 02 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosC0n[0x02] ,a0); +#endif + + SysIntRP[a0] = a1; + + v0 = 0; pc0 = ra; +} + +/* + * int SysDeqIntRP(int index , long *queue); + */ + +void psxBios_SysDeqIntRP() { // 03 +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x\n", biosC0n[0x03], a0); +#endif + + SysIntRP[a0] = 0; + + v0 = 0; pc0 = ra; +} + +void psxBios_ChangeClearRCnt() { // 0a + u32 *ptr; + +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("psxBios_%s: %x, %x\n", biosC0n[0x0a], a0, a1); +#endif + + ptr = (u32*)PSXM((a0 << 2) + 0x8600); + v0 = SWAP32(*ptr); + *ptr = SWAP32(a1); + +// psxRegs.CP0.n.Status|= 0x404; +// + pc0 = ra; +} + +void psxBios_dummy() { +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("unk %lx call: %lx\n", pc0 & 0x1fffff, t1); +#endif + pc0 = ra; +} + +/* +// Added by GP +static void *fileload(char *file,void *buf) +{ + FILE *f; + int fsize; + + f = fopen(file,"rb"); + if (f==NULL) return NULL; + fseek(f,0,SEEK_END); + fsize = ftell(f); + fseek(f,0,SEEK_SET); + if (buf!=NULL || (buf = malloc(fsize))!=NULL) { + fread(buf,1,fsize,f); + } + fclose(f); + return buf; +} +*/ + +void (*biosA0[256])(); +void (*biosB0[256])(); +void (*biosC0[256])(); + +int psxBiosSetupTables() +{ + u32 base;//, size; + int i; + + for(i = 0; i < 256; i++) { + biosA0[i] = NULL; + biosB0[i] = NULL; + biosC0[i] = NULL; + } + biosA0[0x3e] = psxBios_puts; + biosA0[0x3f] = psxBios_printf; + + biosB0[0x3d] = psxBios_putchar; + biosB0[0x3f] = psxBios_puts; + + if (!Config.HLE) return 0; + + for(i = 0; i < 256; i++) { + if (biosA0[i] == NULL) biosA0[i] = psxBios_dummy; + if (biosB0[i] == NULL) biosB0[i] = psxBios_dummy; + if (biosC0[i] == NULL) biosC0[i] = psxBios_dummy; + } + + biosA0[0x00] = psxBios_open; + biosA0[0x01] = psxBios_lseek; + biosA0[0x02] = psxBios_read; + biosA0[0x03] = psxBios_write; + biosA0[0x04] = psxBios_close; + //biosA0[0x05] = psxBios_ioctl; + //biosA0[0x06] = psxBios_exit; + //biosA0[0x07] = psxBios_sys_a0_07; + //biosA0[0x08] = psxBios_getc; + //biosA0[0x09] = psxBios_putc; + //biosA0[0x0a] = psxBios_todigit; + //biosA0[0x0b] = psxBios_atof; + //biosA0[0x0c] = psxBios_strtoul; + //biosA0[0x0d] = psxBios_strtol; + biosA0[0x0e] = psxBios_abs; + biosA0[0x0f] = psxBios_labs; + biosA0[0x10] = psxBios_atoi; + biosA0[0x11] = psxBios_atol; + //biosA0[0x12] = psxBios_atob; + biosA0[0x13] = psxBios_setjmp; + biosA0[0x14] = psxBios_longjmp; + biosA0[0x15] = psxBios_strcat; + biosA0[0x16] = psxBios_strncat; + biosA0[0x17] = psxBios_strcmp; + biosA0[0x18] = psxBios_strncmp; + biosA0[0x19] = psxBios_strcpy; + biosA0[0x1a] = psxBios_strncpy; + biosA0[0x1b] = psxBios_strlen; + biosA0[0x1c] = psxBios_index; + biosA0[0x1d] = psxBios_rindex; + biosA0[0x1e] = psxBios_strchr; + biosA0[0x1f] = psxBios_strrchr; + biosA0[0x20] = psxBios_strpbrk; + biosA0[0x21] = psxBios_strspn; + biosA0[0x22] = psxBios_strcspn; + biosA0[0x23] = psxBios_strtok; + biosA0[0x24] = psxBios_strstr; + biosA0[0x25] = psxBios_toupper; + biosA0[0x26] = psxBios_tolower; + biosA0[0x27] = psxBios_bcopy; + biosA0[0x28] = psxBios_bzero; + biosA0[0x29] = psxBios_bcmp; + biosA0[0x2a] = psxBios_memcpy; + biosA0[0x2b] = psxBios_memset; + biosA0[0x2c] = psxBios_memmove; + biosA0[0x2d] = psxBios_memcmp; + biosA0[0x2e] = psxBios_memchr; + biosA0[0x2f] = psxBios_rand; + biosA0[0x30] = psxBios_srand; + //biosA0[0x31] = psxBios_qsort; + //biosA0[0x32] = psxBios_strtod; + biosA0[0x33] = psxBios_malloc; + //biosA0[0x34] = psxBios_free; + //biosA0[0x35] = psxBios_lsearch; + //biosA0[0x36] = psxBios_bsearch; + //biosA0[0x37] = psxBios_calloc; + //biosA0[0x38] = psxBios_realloc; + biosA0[0x39] = psxBios_InitHeap; + //biosA0[0x3a] = psxBios__exit; + biosA0[0x3b] = psxBios_getchar; + biosA0[0x3c] = psxBios_putchar; + //biosA0[0x3d] = psxBios_gets; + //biosA0[0x40] = psxBios_sys_a0_40; + //biosA0[0x41] = psxBios_LoadTest; + biosA0[0x42] = psxBios_Load; + biosA0[0x43] = psxBios_Exec; + biosA0[0x44] = psxBios_FlushCache; + //biosA0[0x45] = psxBios_InstallInterruptHandler; + biosA0[0x46] = psxBios_GPU_dw; + biosA0[0x47] = psxBios_mem2vram; + biosA0[0x48] = psxBios_SendGPU; + biosA0[0x49] = psxBios_GPU_cw; + biosA0[0x4a] = psxBios_GPU_cwb; + biosA0[0x4b] = psxBios_GPU_SendPackets; + biosA0[0x4c] = psxBios_sys_a0_4c; + biosA0[0x4d] = psxBios_GPU_GetGPUStatus; + //biosA0[0x4e] = psxBios_GPU_sync; + //biosA0[0x4f] = psxBios_sys_a0_4f; + //biosA0[0x50] = psxBios_sys_a0_50; + biosA0[0x51] = psxBios_LoadExec; + //biosA0[0x52] = psxBios_GetSysSp; + //biosA0[0x53] = psxBios_sys_a0_53; + //biosA0[0x54] = psxBios__96_init_a54; + //biosA0[0x55] = psxBios__bu_init_a55; + //biosA0[0x56] = psxBios__96_remove_a56; + //biosA0[0x57] = psxBios_sys_a0_57; + //biosA0[0x58] = psxBios_sys_a0_58; + //biosA0[0x59] = psxBios_sys_a0_59; + //biosA0[0x5a] = psxBios_sys_a0_5a; + //biosA0[0x5b] = psxBios_dev_tty_init; + //biosA0[0x5c] = psxBios_dev_tty_open; + //biosA0[0x5d] = psxBios_sys_a0_5d; + //biosA0[0x5e] = psxBios_dev_tty_ioctl; + //biosA0[0x5f] = psxBios_dev_cd_open; + //biosA0[0x60] = psxBios_dev_cd_read; + //biosA0[0x61] = psxBios_dev_cd_close; + //biosA0[0x62] = psxBios_dev_cd_firstfile; + //biosA0[0x63] = psxBios_dev_cd_nextfile; + //biosA0[0x64] = psxBios_dev_cd_chdir; + //biosA0[0x65] = psxBios_dev_card_open; + //biosA0[0x66] = psxBios_dev_card_read; + //biosA0[0x67] = psxBios_dev_card_write; + //biosA0[0x68] = psxBios_dev_card_close; + //biosA0[0x69] = psxBios_dev_card_firstfile; + //biosA0[0x6a] = psxBios_dev_card_nextfile; + //biosA0[0x6b] = psxBios_dev_card_erase; + //biosA0[0x6c] = psxBios_dev_card_undelete; + //biosA0[0x6d] = psxBios_dev_card_format; + //biosA0[0x6e] = psxBios_dev_card_rename; + //biosA0[0x6f] = psxBios_dev_card_6f; + biosA0[0x70] = psxBios__bu_init; + biosA0[0x71] = psxBios__96_init; + biosA0[0x72] = psxBios__96_remove; + //biosA0[0x73] = psxBios_sys_a0_73; + //biosA0[0x74] = psxBios_sys_a0_74; + //biosA0[0x75] = psxBios_sys_a0_75; + //biosA0[0x76] = psxBios_sys_a0_76; + //biosA0[0x77] = psxBios_sys_a0_77; + //biosA0[0x78] = psxBios__96_CdSeekL; + //biosA0[0x79] = psxBios_sys_a0_79; + //biosA0[0x7a] = psxBios_sys_a0_7a; + //biosA0[0x7b] = psxBios_sys_a0_7b; + //biosA0[0x7c] = psxBios__96_CdGetStatus; + //biosA0[0x7d] = psxBios_sys_a0_7d; + //biosA0[0x7e] = psxBios__96_CdRead; + //biosA0[0x7f] = psxBios_sys_a0_7f; + //biosA0[0x80] = psxBios_sys_a0_80; + //biosA0[0x81] = psxBios_sys_a0_81; + //biosA0[0x82] = psxBios_sys_a0_82; + //biosA0[0x83] = psxBios_sys_a0_83; + //biosA0[0x84] = psxBios_sys_a0_84; + //biosA0[0x85] = psxBios__96_CdStop; + //biosA0[0x86] = psxBios_sys_a0_86; + //biosA0[0x87] = psxBios_sys_a0_87; + //biosA0[0x88] = psxBios_sys_a0_88; + //biosA0[0x89] = psxBios_sys_a0_89; + //biosA0[0x8a] = psxBios_sys_a0_8a; + //biosA0[0x8b] = psxBios_sys_a0_8b; + //biosA0[0x8c] = psxBios_sys_a0_8c; + //biosA0[0x8d] = psxBios_sys_a0_8d; + //biosA0[0x8e] = psxBios_sys_a0_8e; + //biosA0[0x8f] = psxBios_sys_a0_8f; + //biosA0[0x90] = psxBios_sys_a0_90; + //biosA0[0x91] = psxBios_sys_a0_91; + //biosA0[0x92] = psxBios_sys_a0_92; + //biosA0[0x93] = psxBios_sys_a0_93; + //biosA0[0x94] = psxBios_sys_a0_94; + //biosA0[0x95] = psxBios_sys_a0_95; + //biosA0[0x96] = psxBios_AddCDROMDevice; + //biosA0[0x97] = psxBios_AddMemCardDevide; + //biosA0[0x98] = psxBios_DisableKernelIORedirection; + //biosA0[0x99] = psxBios_EnableKernelIORedirection; + //biosA0[0x9a] = psxBios_sys_a0_9a; + //biosA0[0x9b] = psxBios_sys_a0_9b; + //biosA0[0x9c] = psxBios_SetConf; + //biosA0[0x9d] = psxBios_GetConf; + //biosA0[0x9e] = psxBios_sys_a0_9e; + //biosA0[0x9f] = psxBios_SetMem; + //biosA0[0xa0] = psxBios__boot; + //biosA0[0xa1] = psxBios_SystemError; + //biosA0[0xa2] = psxBios_EnqueueCdIntr; + //biosA0[0xa3] = psxBios_DequeueCdIntr; + //biosA0[0xa4] = psxBios_sys_a0_a4; + //biosA0[0xa5] = psxBios_ReadSector; + //biosA0[0xa6] = psxBios_get_cd_status; + //biosA0[0xa7] = psxBios_bufs_cb_0; + //biosA0[0xa8] = psxBios_bufs_cb_1; + //biosA0[0xa9] = psxBios_bufs_cb_2; + //biosA0[0xaa] = psxBios_bufs_cb_3; + biosA0[0xab] = psxBios__card_info; + biosA0[0xac] = psxBios__card_load; + //biosA0[0axd] = psxBios__card_auto; + //biosA0[0xae] = psxBios_bufs_cd_4; + //biosA0[0xaf] = psxBios_sys_a0_af; + //biosA0[0xb0] = psxBios_sys_a0_b0; + //biosA0[0xb1] = psxBios_sys_a0_b1; + //biosA0[0xb2] = psxBios_do_a_long_jmp + //biosA0[0xb3] = psxBios_sys_a0_b3; + //biosA0[0xb4] = psxBios_sub_function; +//*******************B0 CALLS**************************** + //biosB0[0x00] = psxBios_SysMalloc; + //biosB0[0x01] = psxBios_sys_b0_01; + biosB0[0x02] = psxBios_SetRCnt; + biosB0[0x03] = psxBios_GetRCnt; + biosB0[0x04] = psxBios_StartRCnt; + biosB0[0x05] = psxBios_StopRCnt; + biosB0[0x06] = psxBios_ResetRCnt; + biosB0[0x07] = psxBios_DeliverEvent; + biosB0[0x08] = psxBios_OpenEvent; + biosB0[0x09] = psxBios_CloseEvent; + biosB0[0x0a] = psxBios_WaitEvent; + biosB0[0x0b] = psxBios_TestEvent; + biosB0[0x0c] = psxBios_EnableEvent; + biosB0[0x0d] = psxBios_DisableEvent; + biosB0[0x0e] = psxBios_OpenTh; + biosB0[0x0f] = psxBios_CloseTh; + biosB0[0x10] = psxBios_ChangeTh; + //biosB0[0x11] = psxBios_psxBios_b0_11; + biosB0[0x12] = psxBios_InitPAD; + biosB0[0x13] = psxBios_StartPAD; + biosB0[0x14] = psxBios_StopPAD; + biosB0[0x15] = psxBios_PAD_init; + biosB0[0x16] = psxBios_PAD_dr; + biosB0[0x17] = psxBios_ReturnFromException; + biosB0[0x18] = psxBios_ResetEntryInt; + biosB0[0x19] = psxBios_HookEntryInt; + //biosB0[0x1a] = psxBios_sys_b0_1a; + //biosB0[0x1b] = psxBios_sys_b0_1b; + //biosB0[0x1c] = psxBios_sys_b0_1c; + //biosB0[0x1d] = psxBios_sys_b0_1d; + //biosB0[0x1e] = psxBios_sys_b0_1e; + //biosB0[0x1f] = psxBios_sys_b0_1f; + biosB0[0x20] = psxBios_UnDeliverEvent; + //biosB0[0x21] = psxBios_sys_b0_21; + //biosB0[0x22] = psxBios_sys_b0_22; + //biosB0[0x23] = psxBios_sys_b0_23; + //biosB0[0x24] = psxBios_sys_b0_24; + //biosB0[0x25] = psxBios_sys_b0_25; + //biosB0[0x26] = psxBios_sys_b0_26; + //biosB0[0x27] = psxBios_sys_b0_27; + //biosB0[0x28] = psxBios_sys_b0_28; + //biosB0[0x29] = psxBios_sys_b0_29; + //biosB0[0x2a] = psxBios_sys_b0_2a; + //biosB0[0x2b] = psxBios_sys_b0_2b; + //biosB0[0x2c] = psxBios_sys_b0_2c; + //biosB0[0x2d] = psxBios_sys_b0_2d; + //biosB0[0x2e] = psxBios_sys_b0_2e; + //biosB0[0x2f] = psxBios_sys_b0_2f; + //biosB0[0x30] = psxBios_sys_b0_30; + //biosB0[0x31] = psxBios_sys_b0_31; + biosB0[0x32] = psxBios_open; + biosB0[0x33] = psxBios_lseek; + biosB0[0x34] = psxBios_read; + biosB0[0x35] = psxBios_write; + biosB0[0x36] = psxBios_close; + //biosB0[0x37] = psxBios_ioctl; + //biosB0[0x38] = psxBios_exit; + //biosB0[0x39] = psxBios_sys_b0_39; + //biosB0[0x3a] = psxBios_getc; + //biosB0[0x3b] = psxBios_putc; + biosB0[0x3c] = psxBios_getchar; + //biosB0[0x3e] = psxBios_gets; + //biosB0[0x40] = psxBios_cd; + //biosB0[0x41] = psxBios_format; + biosB0[0x42] = psxBios_firstfile; + biosB0[0x43] = psxBios_nextfile; + //biosB0[0x44] = psxBios_rename; + biosB0[0x45] = psxBios_delete; + //biosB0[0x46] = psxBios_undelete; + //biosB0[0x47] = psxBios_AddDevice; + //biosB0[0x48] = psxBios_RemoteDevice; + //biosB0[0x49] = psxBios_PrintInstalledDevices; + biosB0[0x4a] = psxBios_InitCARD; + biosB0[0x4b] = psxBios_StartCARD; + biosB0[0x4c] = psxBios_StopCARD; + //biosB0[0x4d] = psxBios_sys_b0_4d; + biosB0[0x4e] = psxBios__card_write; + biosB0[0x4f] = psxBios__card_read; + biosB0[0x50] = psxBios__new_card; + biosB0[0x51] = psxBios_Krom2RawAdd; + //biosB0[0x52] = psxBios_sys_b0_52; + //biosB0[0x53] = psxBios_sys_b0_53; + //biosB0[0x54] = psxBios__get_errno; + //biosB0[0x55] = psxBios__get_error; + biosB0[0x56] = psxBios_GetC0Table; + biosB0[0x57] = psxBios_GetB0Table; + //biosB0[0x58] = psxBios__card_chan; + //biosB0[0x59] = psxBios_sys_b0_59; + //biosB0[0x5a] = psxBios_sys_b0_5a; + biosB0[0x5b] = psxBios_ChangeClearPad; + //biosB0[0x5c] = psxBios__card_status; + //biosB0[0x5d] = psxBios__card_wait; +//*******************C0 CALLS**************************** + //biosC0[0x00] = psxBios_InitRCnt; + //biosC0[0x01] = psxBios_InitException; + biosC0[0x02] = psxBios_SysEnqIntRP; + biosC0[0x03] = psxBios_SysDeqIntRP; + //biosC0[0x04] = psxBios_get_free_EvCB_slot; + //biosC0[0x05] = psxBios_get_free_TCB_slot; + //biosC0[0x06] = psxBios_ExceptionHandler; + //biosC0[0x07] = psxBios_InstallExeptionHandler; + //biosC0[0x08] = psxBios_SysInitMemory; + //biosC0[0x09] = psxBios_SysInitKMem; + biosC0[0x0a] = psxBios_ChangeClearRCnt; + //biosC0[0x0b] = psxBios_SystemError; + //biosC0[0x0c] = psxBios_InitDefInt; + //biosC0[0x0d] = psxBios_sys_c0_0d; + //biosC0[0x0e] = psxBios_sys_c0_0e; + //biosC0[0x0f] = psxBios_sys_c0_0f; + //biosC0[0x10] = psxBios_sys_c0_10; + //biosC0[0x11] = psxBios_sys_c0_11; + //biosC0[0x12] = psxBios_InstallDevices; + //biosC0[0x13] = psxBios_FlushStfInOutPut; + //biosC0[0x14] = psxBios_sys_c0_14; + //biosC0[0x15] = psxBios__cdevinput; + //biosC0[0x16] = psxBios__cdevscan; + //biosC0[0x17] = psxBios__circgetc; + //biosC0[0x18] = psxBios__circputc; + //biosC0[0x19] = psxBios_ioabort; + //biosC0[0x1a] = psxBios_sys_c0_1a + //biosC0[0x1b] = psxBios_KernelRedirect; + //biosC0[0x1c] = psxBios_PatchAOTable; +//************** THE END *************************************** + + base = 0x1000; + //size = sizeof(EvCB) * 32; + Event = (void *)&psxR[base]; //base+= size*6; + HwEV = Event; + EvEV = Event + 32; + RcEV = Event + 32*2; + UeEV = Event + 32*3; + SwEV = Event + 32*4; + ThEV = Event + 32*5; + + return 1; +} + +void psxBiosInit() { + u32 *ptr; + + if (!psxBiosSetupTables()) + return; + + memset(Event, 0, sizeof(EvCB) * 32 * 6); + + ptr = (u32*)&psxM[0x0874]; // b0 table + ptr[0] = SWAPu32(0x4c54 - 0x884); + + ptr = (u32*)&psxM[0x0674]; // c0 table + ptr[6] = SWAPu32(0xc80); + + memset(SysIntRP, 0, sizeof(SysIntRP)); + memset(Thread, 0, sizeof(Thread)); + Thread[0].status = 2; // main thread + + // from FPSE +/* if (Config.BiosFont[0]) + fileload(Config.BiosFont,&psxRs8ref(0x20000)); + else + fileload("GONZN16X.TLF",&psxRs8ref(0x20000));*/ + // !from FPSE + + psxMu32ref(0x0150) = SWAPu32(0x160); + psxMu32ref(0x0154) = SWAPu32(0x320); + psxMu32ref(0x0160) = SWAPu32(0x248); + strcpy((char*)&psxM[0x248], "bu"); +/* psxMu32ref(0x0ca8) = SWAPu32(0x1f410004); + psxMu32ref(0x0cf0) = SWAPu32(0x3c020000); + psxMu32ref(0x0cf4) = SWAPu32(0x2442641c); + psxMu32ref(0x09e0) = SWAPu32(0x43d0); + psxMu32ref(0x4d98) = SWAPu32(0x946f000a); +*/ + // opcode HLE + psxRu32ref(0x0000) = SWAPu32((0x3b << 26) | 4); + psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0); + psxMu32ref(0x00a0) = SWAPu32((0x3b << 26) | 1); + psxMu32ref(0x00b0) = SWAPu32((0x3b << 26) | 2); + psxMu32ref(0x00c0) = SWAPu32((0x3b << 26) | 3); + psxMu32ref(0x4c54) = SWAPu32((0x3b << 26) | 0); + psxMu32ref(0x8000) = SWAPu32((0x3b << 26) | 5); + psxMu32ref(0x07a0) = SWAPu32((0x3b << 26) | 0); + psxMu32ref(0x0884) = SWAPu32((0x3b << 26) | 0); + psxMu32ref(0x0894) = SWAPu32((0x3b << 26) | 0); +} + +void psxBiosShutdown() { +} + +__inline void SaveRegs() { + memcpy(regs, psxRegs.GPR.r, 32*4); + regs[32] = psxRegs.GPR.n.lo; + regs[33] = psxRegs.GPR.n.hi; + regs[34] = psxRegs.pc; +} + +__inline void LoadRegs() { + memcpy(psxRegs.GPR.r, regs, 32*4); + psxRegs.GPR.n.lo = regs[32]; + psxRegs.GPR.n.hi = regs[33]; +} + + +#define psxBios_PADpoll(pad) { \ + PAD##pad##_startPoll(pad); \ + pad_buf##pad[0] = 0; \ + pad_buf##pad[1] = PAD##pad##_poll(0x42); \ + if (!(pad_buf##pad[1] & 0x0f)) { \ + bufcount = 32; \ + } else { \ + bufcount = (pad_buf##pad[1] & 0x0f) * 2; \ + } \ + PAD##pad##_poll(0); \ + i = 2; \ + while (bufcount--) { \ + pad_buf##pad[i++] = PAD##pad##_poll(0); \ + } \ +} + +void netError(); + +void biosInterrupt() { + int i, bufcount; + +// if (psxHu32(0x1070) & 0x1) { // Vsync + if (pad_buf) { + u32 *buf = (u32*)pad_buf; + + if (!Config.UseNet) { + PAD1_startPoll(1); + if (PAD1_poll(0x42) == 0x23) { + PAD1_poll(0); + *buf = SWAP32(PAD1_poll(0) << 8); + *buf|= SWAP32(PAD1_poll(0)); + PAD1_poll(0); + *buf&= SWAP32(~((PAD1_poll(0)>0x20)?1<<6:0)); + *buf&= SWAP32(~((PAD1_poll(0)>0x20)?1<<7:0)); + } else { + PAD1_poll(0); + *buf = SWAP32(PAD1_poll(0) << 8); + *buf|= SWAP32(PAD1_poll(0)); + } + + PAD2_startPoll(2); + if (PAD2_poll(0x42) == 0x23) { + PAD2_poll(0); + *buf|= SWAP32(PAD2_poll(0) << 24); + *buf|= SWAP32(PAD2_poll(0) << 16); + PAD2_poll(0); + *buf&= SWAP32(~((PAD2_poll(0)>0x20)?1<<22:0)); + *buf&= SWAP32(~((PAD2_poll(0)>0x20)?1<<23:0)); + } else { + PAD2_poll(0); + *buf|= SWAP32(PAD2_poll(0) << 24); + *buf|= SWAP32(PAD2_poll(0) << 16); + } + } else { + u16 data; + + PAD1_startPoll(1); + PAD1_poll(0x42); + PAD1_poll(0); + data = PAD1_poll(0) << 8; + data|= PAD1_poll(0); + + if (NET_sendPadData(&data, 2) == -1) + netError(); + + if (NET_recvPadData(&((u16*)buf)[0], 1) == -1) + netError(); + if (NET_recvPadData(&((u16*)buf)[1], 2) == -1) + netError(); + } + + } + if (Config.UseNet && pad_buf1 && pad_buf2) { + psxBios_PADpoll(1); + + if (NET_sendPadData(pad_buf1, i) == -1) + netError(); + + if (NET_recvPadData(pad_buf1, 1) == -1) + netError(); + if (NET_recvPadData(pad_buf2, 2) == -1) + netError(); + } else { + if (pad_buf1) { + psxBios_PADpoll(1); + } + + if (pad_buf2) { + psxBios_PADpoll(2); + } + } + + if (psxHu32(0x1070) & 0x1) { // Vsync + if (RcEV[3][1].status == SWAP32(EvStACTIVE)) { + softCall(SWAP32(RcEV[3][1].fhandler)); +// hwWrite32(0x1f801070, ~(1)); + } + } + + if (psxHu32(0x1070) & 0x70) { // Rcnt 0,1,2 + int i; + + for (i=0; i<3; i++) { + if (psxHu32(0x1070) & (1 << (i+4))) { + if (RcEV[i][1].status == SWAP32(EvStACTIVE)) { + softCall(SWAP32(RcEV[i][1].fhandler)); + } + psxHwWrite32(0x1f801070, ~(1 << (i+4))); + } + } + } +} + +void psxBiosException() { + int i; + + switch (psxRegs.CP0.n.Cause & 0x3c) { + case 0x00: // Interrupt +#ifdef PSXCPU_LOG +// PSXCPU_LOG("interrupt\n"); +#endif + SaveRegs(); + + biosInterrupt(); + + for (i=0; i<8; i++) { + if (SysIntRP[i]) { + u32 *queue = (u32*)PSXM(SysIntRP[i]); + + s0 = SWAP32(queue[2]); + softCall(SWAP32(queue[1])); + } + } + + if (jmp_int != NULL) { + int i; + + psxHwWrite32(0x1f801070, 0xffffffff); + + ra = SWAP32(jmp_int[0]); + sp = SWAP32(jmp_int[1]); + fp = SWAP32(jmp_int[2]); + for (i=0; i<8; i++) // s0-s7 + psxRegs.GPR.r[16+i] = SWAP32(jmp_int[3+i]); + gp = SWAP32(jmp_int[11]); + + v0 = 1; + pc0 = ra; + return; + } + psxHwWrite16(0x1f801070, 0); + break; + case 0x20: // Syscall +#ifdef PSXCPU_LOG +// PSXCPU_LOG("syscall exp %x\n", a0); +#endif + switch (a0) { + case 1: // EnterCritical - disable irq's + psxRegs.CP0.n.Status&=~0x404; break; + case 2: // ExitCritical - enable irq's + psxRegs.CP0.n.Status|= 0x404; break; + } + pc0 = psxRegs.CP0.n.EPC + 4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); + + return; + default: +#ifdef PSXCPU_LOG + PSXCPU_LOG("unk exp\n"); +#endif + break; + } + + pc0 = psxRegs.CP0.n.EPC; + if (psxRegs.CP0.n.Cause & 0x80000000) pc0+=4; + + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); + +} + +#define bfreeze(ptr, size) \ + if (Mode == 1) memcpy(&psxR[base], ptr, size); \ + if (Mode == 0) memcpy(ptr, &psxR[base], size); \ + base+=size; + +#define bfreezelast(ptr, size) \ + if (Mode == 1) memcpy(&psxR[base], ptr, size); \ + if (Mode == 0) memcpy(ptr, &psxR[base], size); + +#define bfreezes(ptr) bfreeze(ptr, sizeof(*ptr)) +#define bfreezeslast(ptr) bfreezelast(ptr, sizeof(*ptr)) +#define bfreezel(ptr) {*ptr=SWAP32p((void*)ptr); bfreeze(ptr, 4); *ptr=SWAP32p((void*)ptr);} + +#define bfreezepsxMptr(ptr) \ + if (Mode == 1) { \ + if (ptr) psxRu32ref(base) = SWAPu32((u32)ptr - (u32)psxM); \ + else psxRu32ref(base) = 0; \ + } else { \ + if (psxRu32(base)) *(u8**)&ptr = (u8*)(psxM + psxRu32(base)); \ + else ptr = NULL; \ + } \ + base+=4; + +static void biosSwap() +{ + int i, j; + + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include + +/* Define types */ +/*typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef intptr_t sptr; + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +typedef uintptr_t uptr; +*/ +/* Local includes */ +#include "system.h" +#include "coredebug.h" + +/* Ryan TODO WTF is this? */ +#if defined (__LINUX__) || defined (__MACOSX__) || defined(HW_RVL) || defined(HW_DOL) +#define strnicmp strncasecmp +#endif +#define __inline inline + +/* Enables NLS/internationalization if active */ +#ifdef ENABLE_NLS + +#include + +#undef _ +#define _(String) gettext(String) +#ifdef gettext_noop +# define N_(String) gettext_noop (String) +#else +# define N_(String) (String) +#endif + +#else + +#define _(msgid) msgid +#define N_(msgid) msgid + +#endif + +extern int Log; +void __Log(char *fmt, ...); + +typedef struct { + char Gpu[256]; + char Spu[256]; + char Cdr[256]; + char Pad1[256]; + char Pad2[256]; + char Net[256]; + char Mcd1[256]; + char Mcd2[256]; + char Bios[256]; + char BiosDir[MAXPATHLEN]; + char PluginsDir[MAXPATHLEN]; + long Xa; + long Sio; + long Mdec; + long PsxAuto; + long PsxType; /* NTSC or PAL */ + long Cdda; + long HLE; + long Cpu; + long Dbg; + long PsxOut; + long SpuIrq; + long RCntFix; + long UseNet; + long VSyncWA; +} PcsxConfig; + +extern PcsxConfig Config; + +extern char LoadCdBios; +extern int StatesC; +extern int cdOpenCase; +extern int NetOpened; + +#define gzfreeze(ptr, size) \ + if (Mode == 1) gzwrite(f, ptr, size); \ + if (Mode == 0) gzread(f, ptr, size); + +#define gzfreezel(ptr) gzfreeze(ptr, sizeof(ptr)) + +//#define BIAS 4 +#define BIAS 2 +#define PSXCLK 33868800 /* 33.8688 Mhz */ + +enum { + BIOS_USER_DEFINED, + BIOS_HLE +}; /* BIOS Types */ + +enum { + PSX_TYPE_NTSC, + PSX_TYPE_PAL +}; /* PSX Type */ + + +#endif /* __PSXCOMMON_H__ */ diff --git a/psxcounters.c b/psxcounters.c new file mode 100644 index 0000000..7b7409a --- /dev/null +++ b/psxcounters.c @@ -0,0 +1,251 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Internal PSX counters. +*/ + +#include "psxcounters.h" +#include "Gamecube/DEBUG.h" + +static int cnts = 4; +psxCounter psxCounters[5]; + +static void psxRcntUpd(unsigned long index) { + psxCounters[index].sCycle = psxRegs.cycle; + if (((!(psxCounters[index].mode & 1)) || (index!=2)) && + psxCounters[index].mode & 0x30) { + if (psxCounters[index].mode & 0x10) { // Interrupt on target + psxCounters[index].Cycle = ((psxCounters[index].target - psxCounters[index].count) * psxCounters[index].rate) / BIAS; + } else { // Interrupt on 0xffff + psxCounters[index].Cycle = ((0xffff - psxCounters[index].count) * psxCounters[index].rate) / BIAS; + } + } else psxCounters[index].Cycle = 0xffffffff; +// if (index == 2) SysPrintf("Cycle %x\n", psxCounters[index].Cycle); +} + +static void psxRcntReset(unsigned long index) { +// SysPrintf("psxRcntReset %x (mode=%x)\n", index, psxCounters[index].mode); + psxCounters[index].count = 0; + psxRcntUpd(index); + +// if (index == 2) SysPrintf("rcnt2 %x\n", psxCounters[index].mode); + psxHu32ref(0x1070)|= SWAPu32(psxCounters[index].interrupt); + psxRegs.interrupt|= 0x80000000; + if (!(psxCounters[index].mode & 0x40)) { // Only 1 interrupt + psxCounters[index].Cycle = 0xffffffff; + } // else Continuos interrupt mode +} + +static void psxRcntSet() { + int i; + + psxNextCounter = 0x7fffffff; + psxNextsCounter = psxRegs.cycle; + + for (i=0; i= psxCounters[3].Cycle) { + if (psxCounters[3].mode & 0x10000) { // VSync End (22 hsyncs) + psxCounters[3].mode&=~0x10000; + psxUpdateVSyncRate(); + psxRcntUpd(3); + GPU_updateLace(); // updateGPU + SysUpdate(); +#ifdef GTE_LOG + GTE_LOG("VSync\n"); +#endif + } else { // VSync Start (240 hsyncs) + psxCounters[3].mode|= 0x10000; + psxUpdateVSyncRateEnd(); + psxRcntUpd(3); + psxHu32ref(0x1070)|= SWAPu32(1); + psxRegs.interrupt|= 0x80000000; + } + } + + if ((psxRegs.cycle - psxCounters[0].sCycle) >= psxCounters[0].Cycle) { + psxRcntReset(0); + } + + if ((psxRegs.cycle - psxCounters[1].sCycle) >= psxCounters[1].Cycle) { + psxRcntReset(1); + } + + if ((psxRegs.cycle - psxCounters[2].sCycle) >= psxCounters[2].Cycle) { + psxRcntReset(2); + } + + if (cnts >= 5) { + if ((psxRegs.cycle - psxCounters[4].sCycle) >= psxCounters[4].Cycle) { +#ifdef PROFILE + start_section(AUDIO_SECTION); +#endif + SPU_async((psxRegs.cycle - psxCounters[4].sCycle) * BIAS); +#ifdef PROFILE + end_section(AUDIO_SECTION); +#endif + psxRcntReset(4); + } + } + + psxRcntSet(); +} + +void psxRcntWcount(u32 index, u32 value) { +// SysPrintf("writeCcount[%d] = %x\n", index, value); +// PSXCPU_LOG("writeCcount[%d] = %x\n", index, value); + psxCounters[index].count = value; + psxRcntUpd(index); + psxRcntSet(); +} + +void psxRcntWmode(u32 index, u32 value) { +// SysPrintf("writeCmode[%ld] = %lx\n", index, value); + psxCounters[index].mode = value; + psxCounters[index].count = 0; + if(index == 0) { + switch (value & 0x300) { + case 0x100: + psxCounters[index].rate = ((psxCounters[3].rate /** BIAS*/) / 386) / 262; // seems ok + break; + default: + psxCounters[index].rate = 1; + } + } + else if(index == 1) { + switch (value & 0x300) { + case 0x100: + psxCounters[index].rate = (psxCounters[3].rate /** BIAS*/) / 262; // seems ok + break; + default: + psxCounters[index].rate = 1; + } + } + else if(index == 2) { + switch (value & 0x300) { + case 0x200: + psxCounters[index].rate = 8; // 1/8 speed + break; + default: + psxCounters[index].rate = 1; // normal speed + } + } + + // Need to set a rate and target + psxRcntUpd(index); + psxRcntSet(); +} + +void psxRcntWtarget(u32 index, u32 value) { +// SysPrintf("writeCtarget[%ld] = %lx\n", index, value); + psxCounters[index].target = value; + psxRcntUpd(index); + psxRcntSet(); +} + +u32 psxRcntRcount(u32 index) { + u32 ret; + +// if ((!(psxCounters[index].mode & 1)) || (index!=2)) { + if (psxCounters[index].mode & 0x08) { // Wrap at target + if (Config.RCntFix) { // Parasite Eve 2 + ret = (psxCounters[index].count + /*BIAS **/ ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; + } else { + ret = (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; + } + } else { // Wrap at 0xffff + ret = (psxCounters[index].count + BIAS * (psxRegs.cycle / psxCounters[index].rate)) & 0xffff; + if (Config.RCntFix) { // Vandal Hearts 1/2 + ret/= 16; + } + } +// return (psxCounters[index].count + BIAS * ((psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate)) & 0xffff; +// } else return 0; + +// SysPrintf("readCcount[%ld] = %lx (mode %lx, target %lx, cycle %lx)\n", index, ret, psxCounters[index].mode, psxCounters[index].target, psxRegs.cycle); + + return ret; +} + +int psxRcntFreeze(gzFile f, int Mode) { + char Unused[4096 - sizeof(psxCounter)]; + + gzfreezel(psxCounters); + gzfreezel(Unused); + + return 0; +} diff --git a/psxcounters.h b/psxcounters.h new file mode 100644 index 0000000..b2767af --- /dev/null +++ b/psxcounters.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PSXCOUNTERS_H__ +#define __PSXCOUNTERS_H__ + +#include "psxcommon.h" +#include "r3000a.h" +#include "psxmem.h" +#include "plugins.h" + +typedef struct { + u32 count, mode, target; + u32 sCycle, Cycle, rate, interrupt; +} psxCounter; + +extern psxCounter psxCounters[5]; + +u32 psxNextCounter, psxNextsCounter; + +void psxRcntInit(); +void psxRcntUpdate(); +void psxRcntWcount(u32 index, u32 value); +void psxRcntWmode(u32 index, u32 value); +void psxRcntWtarget(u32 index, u32 value); +u32 psxRcntRcount(u32 index); +int psxRcntFreeze(gzFile f, int Mode); + +void psxUpdateVSyncRate(); + +#endif /* __PSXCOUNTERS_H__ */ diff --git a/psxdma.c b/psxdma.c new file mode 100644 index 0000000..4aaa617 --- /dev/null +++ b/psxdma.c @@ -0,0 +1,189 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Handles PSX DMA functions. +*/ +#include "Gamecube/DEBUG.h" +#include "psxdma.h" + +// Dma0/1 in mdec.c +// Dma3 in cdrom.c + +void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU + + u16 *ptr; + u32 size; + + switch (chcr) { + case 0x01000201: //cpu to spu transfer +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA4 SPU - mem2spu *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 5); +#endif + ptr = (u16 *)PSXM(madr); + if (ptr == NULL) { +#ifdef DEBUG_DMA + DEBUG_print("*** DMA4 SPU - mem2spu *** NULL Pointer!!!\n", 5); +#endif + break; + } + SPU_writeDMAMem(ptr, (bcr >> 16) * (bcr & 0xffff) * 2); + break; + + case 0x01000200: //spu to cpu transfer +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA4 SPU - spu2mem *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 6); +#endif + ptr = (u16 *)PSXM(madr); + if (ptr == NULL) { +#ifdef DEBUG_DMA + DEBUG_print("*** DMA4 SPU - spu2mem *** NULL Pointer!!!\n", 6); +#endif + break; + } + size = (bcr >> 16) * (bcr & 0xffff) * 2; + SPU_readDMAMem(ptr, size); + psxCpu->Clear(madr, size); + break; + +#ifdef DEBUG_DMA + default: + sprintf(txtbuffer,"*** DMA4 SPU - unknown *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 7); + break; +#endif + } + + HW_DMA4_CHCR &= SWAPu32(~0x01000000); + DMA_INTERRUPT(4); + +} + +void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU +#ifdef PROFILE + start_section(GFX_SECTION); +#endif + u32 *ptr; + u32 size; + + switch(chcr) { + case 0x01000200: // vram2mem +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA2 GPU - vram2mem *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 8); +#endif + ptr = (u32 *)PSXM(madr); + if (ptr == NULL) { +#ifdef DEBUG_DMA + DEBUG_print("*** DMA2 GPU - vram2mem *** NULL Pointer!!!\n", 8); +#endif + break; + } + size = (bcr >> 16) * (bcr & 0xffff); + GPU_readDataMem((unsigned long*)ptr, size); + psxCpu->Clear(madr, size); + break; + + case 0x01000201: // mem2vram +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA 2 - GPU mem2vram *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 9); +#endif + ptr = (u32 *)PSXM(madr); + if (ptr == NULL) { +#ifdef DEBUG_DMA + DEBUG_print("*** DMA2 GPU - mem2vram *** NULL Pointer!!!\n", 9); +#endif + break; + } + size = (bcr >> 16) * (bcr & 0xffff); + GPU_writeDataMem((unsigned long*)ptr, size); + GPUDMA_INT((size / 4) / BIAS); +#ifdef PROFILE + end_section(GFX_SECTION); +#endif + return; +// break; + + case 0x01000401: // dma chain +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA 2 - GPU dma chain *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 10); +#endif + GPU_dmaChain((u32 *)psxM, madr & 0x1fffff); + break; + +#ifdef DEBUG_DMA + default: + sprintf(txtbuffer,"*** DMA 2 - GPU unknown *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 11); + break; +#endif + } + + HW_DMA2_CHCR &= SWAPu32(~0x01000000); + DMA_INTERRUPT(2); +#ifdef PROFILE + end_section(GFX_SECTION); +#endif +} + +void gpuInterrupt() { + HW_DMA2_CHCR &= SWAPu32(~0x01000000); + DMA_INTERRUPT(2); +} + +void psxDma6(u32 madr, u32 bcr, u32 chcr) { + u32 *mem = (u32 *)PSXM(madr); + +#ifdef DEBUG_DMA + sprintf(txtbuffer,"*** DMA6 OT *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 12); +#endif + + if (chcr == 0x11000002) { + if (mem == NULL) { +#ifdef DEBUG_DMA + DEBUG_print("*** DMA6 OT *** NULL Pointer!!!\n", 12); +#endif + HW_DMA6_CHCR &= SWAPu32(~0x01000000); + DMA_INTERRUPT(6); + return; + } + + while (bcr--) { + *mem-- = SWAPu32((madr - 4) & 0xffffff); + madr -= 4; + } + mem++; *mem = SWAPu32(0xffffff); + } +#ifdef DEBUG_DMA + else { + // Unknown option + sprintf(txtbuffer,"*** DMA6 OT - unknown *** %08x addr = %08x size = %08x\n", chcr, madr, bcr); + DEBUG_print(txtbuffer, 13); + } +#endif + + HW_DMA6_CHCR &= SWAPu32(~0x01000000); + DMA_INTERRUPT(6); +} + diff --git a/psxdma.h b/psxdma.h new file mode 100644 index 0000000..d3cf298 --- /dev/null +++ b/psxdma.h @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PSXDMA_H__ +#define __PSXDMA_H__ + +#include "psxcommon.h" +#include "r3000a.h" +#include "psxhw.h" +#include "psxmem.h" + +#define GPUDMA_INT(eCycle) { \ + psxRegs.interrupt |= 0x01000000; \ + psxRegs.intCycle[3+24+1] = eCycle; \ + psxRegs.intCycle[3+24] = psxRegs.cycle; \ +} + +#define MDECOUTDMA_INT(eCycle) { \ + psxRegs.interrupt |= 0x02000000; \ + psxRegs.intCycle[5+24+1] = eCycle; \ + psxRegs.intCycle[5+24] = psxRegs.cycle; \ +} + +void psxDma2(u32 madr, u32 bcr, u32 chcr); +void psxDma3(u32 madr, u32 bcr, u32 chcr); +void psxDma4(u32 madr, u32 bcr, u32 chcr); +void psxDma6(u32 madr, u32 bcr, u32 chcr); +void gpuInterrupt(); + +#endif /* __PSXDMA_H__ */ diff --git a/psxhle.c b/psxhle.c new file mode 100644 index 0000000..9d1d052 --- /dev/null +++ b/psxhle.c @@ -0,0 +1,96 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Internal PSX HLE functions. +*/ + +#include "psxhle.h" + +static void hleDummy() { + psxRegs.pc = psxRegs.GPR.n.ra; + + psxBranchTest(); +} + +static void hleA0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosA0[call]) biosA0[call](); + + psxBranchTest(); +} + +static void hleB0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosB0[call]) biosB0[call](); + + psxBranchTest(); +} + +static void hleC0() { + u32 call = psxRegs.GPR.n.t1 & 0xff; + + if (biosC0[call]) biosC0[call](); + + psxBranchTest(); +} + +static void hleBootstrap() { // 0xbfc00000 + SysPrintf("hleBootstrap\n"); + CheckCdrom(); + LoadCdrom(); + SysPrintf("CdromLabel: \"%s\": PC = %8.8lx (SP = %8.8lx)\n", CdromLabel, psxRegs.pc, psxRegs.GPR.n.sp); +} + +typedef struct { + u32 _pc0; + u32 gp0; + u32 t_addr; + u32 t_size; + u32 d_addr; + u32 d_size; + u32 b_addr; + u32 b_size; + u32 S_addr; + u32 s_size; + u32 _sp,_fp,_gp,ret,base; +} EXEC; + +static void hleExecRet() { + EXEC *header = (EXEC*)PSXM(psxRegs.GPR.n.s0); + + SysPrintf("ExecRet %x: %x\n", psxRegs.GPR.n.s0, header->ret); + + psxRegs.GPR.n.ra = header->ret; + psxRegs.GPR.n.sp = header->_sp; + psxRegs.GPR.n.s8 = header->_fp; + psxRegs.GPR.n.gp = header->_gp; + psxRegs.GPR.n.s0 = header->base; + + psxRegs.GPR.n.v0 = 1; + psxRegs.pc = psxRegs.GPR.n.ra; +} + +void (*psxHLEt[256])() = { + hleDummy, hleA0, hleB0, hleC0, + hleBootstrap, hleExecRet, + hleDummy, hleDummy +}; diff --git a/psxhle.h b/psxhle.h new file mode 100644 index 0000000..98a1783 --- /dev/null +++ b/psxhle.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PSXHLE_H__ +#define __PSXHLE_H__ + +#include "psxcommon.h" +#include "r3000a.h" +#include "plugins.h" + +extern void (*psxHLEt[256])(); + +#endif /* __PSXHLE_H__ */ diff --git a/psxhw.c b/psxhw.c new file mode 100644 index 0000000..d4a5244 --- /dev/null +++ b/psxhw.c @@ -0,0 +1,722 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Functions for PSX hardware control. +*/ + +#include "psxhw.h" +#include "mdec.h" +#include "cdrom.h" + +void psxHwReset() { + if (Config.Sio) psxHu32ref(0x1070) |= SWAP32(0x80); + if (Config.SpuIrq) psxHu32ref(0x1070) |= SWAP32(0x200); + + memset(psxH, 0, 0x10000); + + mdecInit(); //intialize mdec decoder + cdrReset(); + psxRcntInit(); +} + +u8 psxHwRead8(u32 add) { + unsigned char hard; + + switch (add) { + case 0x1f801040: hard = sioRead8();break; + // case 0x1f801050: hard = serial_read8(); break;//for use of serial port ignore for now + case 0x1f801800: hard = cdrRead0(); break; + case 0x1f801801: hard = cdrRead1(); break; + case 0x1f801802: hard = cdrRead2(); break; + case 0x1f801803: hard = cdrRead3(); break; + default: + hard = psxHu8(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 8bit read at address %lx\n", add); +#endif + return hard; + } + +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit read at address %lx value %x\n", add, hard); +#endif + return hard; +} + +u16 psxHwRead16(u32 add) { + unsigned short hard; + + switch (add) { +#ifdef PSXHW_LOG + case 0x1f801070: PSXHW_LOG("IREG 16bit read %x\n", psxHu16(0x1070)); + return psxHu16(0x1070); +#endif +#ifdef PSXHW_LOG + case 0x1f801074: PSXHW_LOG("IMASK 16bit read %x\n", psxHu16(0x1074)); + return psxHu16(0x1074); +#endif + + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f801044: + hard = StatReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f801048: + hard = ModeReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f80104a: + hard = CtrlReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + case 0x1f80104e: + hard = BaudReg; +#ifdef PAD_LOG + PAD_LOG("sio read16 %lx; ret = %x\n", add&0xf, hard); +#endif + return hard; + + //Serial port stuff not support now ;P + // case 0x1f801050: hard = serial_read16(); break; + // case 0x1f801054: hard = serial_status_read(); break; + // case 0x1f80105a: hard = serial_control_read(); break; + // case 0x1f80105e: hard = serial_baud_read(); break; + + case 0x1f801100: + hard = psxRcntRcount(0); +#ifdef PSXHW_LOG + PSXHW_LOG("T0 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T0 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801108: + hard = psxCounters[0].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T0 target read16: %x\n", hard); +#endif + return hard; + case 0x1f801110: + hard = psxRcntRcount(1); +#ifdef PSXHW_LOG + PSXHW_LOG("T1 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T1 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801118: + hard = psxCounters[1].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T1 target read16: %x\n", hard); +#endif + return hard; + case 0x1f801120: + hard = psxRcntRcount(2); +#ifdef PSXHW_LOG + PSXHW_LOG("T2 count read16: %x\n", hard); +#endif + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T2 mode read16: %x\n", hard); +#endif + return hard; + case 0x1f801128: + hard = psxCounters[2].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T2 target read16: %x\n", hard); +#endif + return hard; + + //case 0x1f802030: hard = //int_2000???? + //case 0x1f802040: hard =//dip switches...?? + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + hard = SPU_readRegister(add); + } else { + hard = psxHu16(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 16bit read at address %lx\n", add); +#endif + } + return hard; + } + +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 16bit read at address %lx value %x\n", add, hard); +#endif + return hard; +} + +u32 psxHwRead32(u32 add) { + u32 hard; + + switch (add) { + case 0x1f801040: + hard = sioRead8(); + hard|= sioRead8() << 8; + hard|= sioRead8() << 16; + hard|= sioRead8() << 24; +#ifdef PAD_LOG + PAD_LOG("sio read32 ;ret = %lx\n", hard); +#endif + return hard; + + // case 0x1f801050: hard = serial_read32(); break;//serial port +#ifdef PSXHW_LOG + case 0x1f801060: + PSXHW_LOG("RAM size read %lx\n", psxHu32(0x1060)); + return psxHu32(0x1060); +#endif +#ifdef PSXHW_LOG + case 0x1f801070: PSXHW_LOG("IREG 32bit read %x\n", psxHu32(0x1070)); + return psxHu32(0x1070); +#endif +#ifdef PSXHW_LOG + case 0x1f801074: PSXHW_LOG("IMASK 32bit read %x\n", psxHu32(0x1074)); + return psxHu32(0x1074); +#endif + + case 0x1f801810: + hard = GPU_readData(); +#ifdef PSXHW_LOG + PSXHW_LOG("GPU DATA 32bit read %lx\n", hard); +#endif + return hard; + case 0x1f801814: + hard = GPU_readStatus(); +#ifdef PSXHW_LOG + PSXHW_LOG("GPU STATUS 32bit read %lx\n", hard); +#endif + return hard; + + case 0x1f801820: hard = mdecRead0(); break; + case 0x1f801824: hard = mdecRead1(); break; + +#ifdef PSXHW_LOG + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit read %lx\n", psxHu32(0x10a0)); + return SWAPu32(HW_DMA2_MADR); + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit read %lx\n", psxHu32(0x10a4)); + return SWAPu32(HW_DMA2_BCR); + case 0x1f8010a8: + PSXHW_LOG("DMA2 CHCR 32bit read %lx\n", psxHu32(0x10a8)); + return SWAPu32(HW_DMA2_CHCR); +#endif + +#ifdef PSXHW_LOG + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit read %lx\n", psxHu32(0x10b0)); + return SWAPu32(HW_DMA3_MADR); + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit read %lx\n", psxHu32(0x10b4)); + return SWAPu32(HW_DMA3_BCR); + case 0x1f8010b8: + PSXHW_LOG("DMA3 CHCR 32bit read %lx\n", psxHu32(0x10b8)); + return SWAPu32(HW_DMA3_CHCR); +#endif + +#ifdef PSXHW_LOG +/* case 0x1f8010f0: + PSXHW_LOG("DMA PCR 32bit read %x\n", psxHu32(0x10f0)); + return SWAPu32(HW_DMA_PCR); // dma rest channel + case 0x1f8010f4: + PSXHW_LOG("DMA ICR 32bit read %x\n", psxHu32(0x10f4)); + return SWAPu32(HW_DMA_ICR); // interrupt enabler?*/ +#endif + + // time for rootcounters :) + case 0x1f801100: + hard = psxRcntRcount(0); +#ifdef PSXHW_LOG + PSXHW_LOG("T0 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801104: + hard = psxCounters[0].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T0 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801108: + hard = psxCounters[0].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T0 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f801110: + hard = psxRcntRcount(1); +#ifdef PSXHW_LOG + PSXHW_LOG("T1 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801114: + hard = psxCounters[1].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T1 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801118: + hard = psxCounters[1].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T1 target read32: %lx\n", hard); +#endif + return hard; + case 0x1f801120: + hard = psxRcntRcount(2); +#ifdef PSXHW_LOG + PSXHW_LOG("T2 count read32: %lx\n", hard); +#endif + return hard; + case 0x1f801124: + hard = psxCounters[2].mode; +#ifdef PSXHW_LOG + PSXHW_LOG("T2 mode read32: %lx\n", hard); +#endif + return hard; + case 0x1f801128: + hard = psxCounters[2].target; +#ifdef PSXHW_LOG + PSXHW_LOG("T2 target read32: %lx\n", hard); +#endif + return hard; + + default: + hard = psxHu32(add); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unkwnown 32bit read at address %lx\n", add); +#endif + return hard; + } +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 32bit read at address %lx\n", add); +#endif + return hard; +} + +void psxHwWrite8(u32 add, u8 value) { + switch (add) { + case 0x1f801040: sioWrite8(value); break; + // case 0x1f801050: serial_write8(value); break;//serial port + case 0x1f801800: cdrWrite0(value); break; + case 0x1f801801: cdrWrite1(value); break; + case 0x1f801802: cdrWrite2(value); break; + case 0x1f801803: cdrWrite3(value); break; + + default: + psxHu8(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 8bit write at address %lx value %x\n", add, value); +#endif + return; + } + psxHu8(add) = value; +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 8bit write at address %lx value %x\n", add, value); +#endif +} + +void psxHwWrite16(u32 add, u16 value) { + switch (add) { + case 0x1f801040: + sioWrite8((unsigned char)value); + sioWrite8((unsigned char)(value>>8)); +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f801044: +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f801048: + ModeReg = value; +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f80104a: // control register + sioWriteCtrl16(value); +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + case 0x1f80104e: // baudrate register + BaudReg = value; +#ifdef PAD_LOG + PAD_LOG ("sio write16 %lx, %x\n", add&0xf, value); +#endif + return; + + //serial port ;P + // case 0x1f801050: serial_write16(value); break; + // case 0x1f80105a: serial_control_write(value);break; + // case 0x1f80105e: serial_baud_write(value); break; + // case 0x1f801054: serial_status_write(value); break; + + case 0x1f801070: +#ifdef PSXHW_LOG + PSXHW_LOG("IREG 16bit write %x\n", value); +#endif + if (Config.Sio) psxHu16ref(0x1070) |= SWAPu16(0x80); + if (Config.SpuIrq) psxHu16ref(0x1070) |= SWAPu16(0x200); + psxHu16ref(0x1070) &= SWAPu16((psxHu16(0x1074) & value)); + return; + + case 0x1f801074: +#ifdef PSXHW_LOG + PSXHW_LOG("IMASK 16bit write %x\n", value); +#endif + psxHu16ref(0x1074) = SWAPu16(value); + psxRegs.interrupt|= 0x80000000; + return; + + case 0x1f801100: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount(0, value); return; + case 0x1f801104: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 MODE 16bit write %x\n", value); +#endif + psxRcntWmode(0, value); return; + case 0x1f801108: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget(0, value); return; + + case 0x1f801110: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount(1, value); return; + case 0x1f801114: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 MODE 16bit write %x\n", value); +#endif + psxRcntWmode(1, value); return; + case 0x1f801118: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget(1, value); return; + + case 0x1f801120: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 COUNT 16bit write %x\n", value); +#endif + psxRcntWcount(2, value); return; + case 0x1f801124: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 MODE 16bit write %x\n", value); +#endif + psxRcntWmode(2, value); return; + case 0x1f801128: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 TARGET 16bit write %x\n", value); +#endif + psxRcntWtarget(2, value); return; + + default: + if (add>=0x1f801c00 && add<0x1f801e00) { + SPU_writeRegister(add, value); + return; + } + + psxHu16ref(add) = SWAPu16(value); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 16bit write at address %lx value %x\n", add, value); +#endif + return; + } + psxHu16ref(add) = SWAPu16(value); +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 16bit write at address %lx value %x\n", add, value); +#endif +} + +#define DmaExec(n) { \ + if (SWAPu32(HW_DMA##n##_CHCR) & 0x01000000) return; \ + HW_DMA##n##_CHCR = SWAPu32(value); \ + \ + if (SWAPu32(HW_DMA##n##_CHCR) & 0x01000000 && SWAPu32(HW_DMA_PCR) & (8 << (n * 4))) { \ + psxDma##n(SWAPu32(HW_DMA##n##_MADR), SWAPu32(HW_DMA##n##_BCR), SWAPu32(HW_DMA##n##_CHCR)); \ + } \ +} + +void psxHwWrite32(u32 add, u32 value) { + switch (add) { + case 0x1f801040: + sioWrite8((unsigned char)value); + sioWrite8((unsigned char)((value&0xff) >> 8)); + sioWrite8((unsigned char)((value&0xff) >> 16)); + sioWrite8((unsigned char)((value&0xff) >> 24)); +#ifdef PAD_LOG + PAD_LOG("sio write32 %lx\n", value); +#endif + return; + // case 0x1f801050: serial_write32(value); break;//serial port +#ifdef PSXHW_LOG + case 0x1f801060: + PSXHW_LOG("RAM size write %lx\n", value); + psxHu32ref(add) = SWAPu32(value); + return; // Ram size +#endif + + case 0x1f801070: +#ifdef PSXHW_LOG + PSXHW_LOG("IREG 32bit write %lx\n", value); +#endif + if (Config.Sio) psxHu32ref(0x1070) |= SWAPu32(0x80); + if (Config.SpuIrq) psxHu32ref(0x1070) |= SWAPu32(0x200); + psxHu32ref(0x1070) &= SWAPu32((psxHu32(0x1074) & value)); + return; + case 0x1f801074: +#ifdef PSXHW_LOG + PSXHW_LOG("IMASK 32bit write %lx\n", value); +#endif + psxHu32ref(0x1074) = SWAPu32(value); + psxRegs.interrupt|= 0x80000000; + return; + +#ifdef PSXHW_LOG + case 0x1f801080: + PSXHW_LOG("DMA0 MADR 32bit write %lx\n", value); + HW_DMA0_MADR = SWAPu32(value); return; // DMA0 madr + case 0x1f801084: + PSXHW_LOG("DMA0 BCR 32bit write %lx\n", value); + HW_DMA0_BCR = SWAPu32(value); return; // DMA0 bcr +#endif + case 0x1f801088: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA0 CHCR 32bit write %lx\n", value); +#endif + DmaExec(0); // DMA0 chcr (MDEC in DMA) + return; + +#ifdef PSXHW_LOG + case 0x1f801090: + PSXHW_LOG("DMA1 MADR 32bit write %lx\n", value); + HW_DMA1_MADR = SWAPu32(value); return; // DMA1 madr + case 0x1f801094: + PSXHW_LOG("DMA1 BCR 32bit write %lx\n", value); + HW_DMA1_BCR = SWAPu32(value); return; // DMA1 bcr +#endif + case 0x1f801098: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA1 CHCR 32bit write %lx\n", value); +#endif + DmaExec(1); // DMA1 chcr (MDEC out DMA) + return; + +#ifdef PSXHW_LOG + case 0x1f8010a0: + PSXHW_LOG("DMA2 MADR 32bit write %lx\n", value); + HW_DMA2_MADR = SWAPu32(value); return; // DMA2 madr + case 0x1f8010a4: + PSXHW_LOG("DMA2 BCR 32bit write %lx\n", value); + HW_DMA2_BCR = SWAPu32(value); return; // DMA2 bcr +#endif + case 0x1f8010a8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA2 CHCR 32bit write %lx\n", value); +#endif + DmaExec(2); // DMA2 chcr (GPU DMA) + return; + +#ifdef PSXHW_LOG + case 0x1f8010b0: + PSXHW_LOG("DMA3 MADR 32bit write %lx\n", value); + HW_DMA3_MADR = SWAPu32(value); return; // DMA3 madr + case 0x1f8010b4: + PSXHW_LOG("DMA3 BCR 32bit write %lx\n", value); + HW_DMA3_BCR = SWAPu32(value); return; // DMA3 bcr +#endif + case 0x1f8010b8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA3 CHCR 32bit write %lx\n", value); +#endif + DmaExec(3); // DMA3 chcr (CDROM DMA) + + return; + +#ifdef PSXHW_LOG + case 0x1f8010c0: + PSXHW_LOG("DMA4 MADR 32bit write %lx\n", value); + HW_DMA4_MADR = SWAPu32(value); return; // DMA4 madr + case 0x1f8010c4: + PSXHW_LOG("DMA4 BCR 32bit write %lx\n", value); + HW_DMA4_BCR = SWAPu32(value); return; // DMA4 bcr +#endif + case 0x1f8010c8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA4 CHCR 32bit write %lx\n", value); +#endif + DmaExec(4); // DMA4 chcr (SPU DMA) + return; + +#if 0 + case 0x1f8010d0: break; //DMA5write_madr(); + case 0x1f8010d4: break; //DMA5write_bcr(); + case 0x1f8010d8: break; //DMA5write_chcr(); // Not needed +#endif + +#ifdef PSXHW_LOG + case 0x1f8010e0: + PSXHW_LOG("DMA6 MADR 32bit write %lx\n", value); + HW_DMA6_MADR = SWAPu32(value); return; // DMA6 bcr + case 0x1f8010e4: + PSXHW_LOG("DMA6 BCR 32bit write %lx\n", value); + HW_DMA6_BCR = SWAPu32(value); return; // DMA6 bcr +#endif + case 0x1f8010e8: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA6 CHCR 32bit write %lx\n", value); +#endif + DmaExec(6); // DMA6 chcr (OT clear) + return; + +#ifdef PSXHW_LOG + case 0x1f8010f0: + PSXHW_LOG("DMA PCR 32bit write %lx\n", value); + HW_DMA_PCR = SWAPu32(value); + return; +#endif + + case 0x1f8010f4: +#ifdef PSXHW_LOG + PSXHW_LOG("DMA ICR 32bit write %lx\n", value); +#endif + { + u32 tmp = (~value) & SWAPu32(HW_DMA_ICR); + HW_DMA_ICR = SWAPu32(((tmp ^ value) & 0xffffff) ^ tmp); + return; + } + + case 0x1f801810: +#ifdef PSXHW_LOG + PSXHW_LOG("GPU DATA 32bit write %lx\n", value); +#endif + GPU_writeData(value); return; + case 0x1f801814: +#ifdef PSXHW_LOG + PSXHW_LOG("GPU STATUS 32bit write %lx\n", value); +#endif + GPU_writeStatus(value); return; + + case 0x1f801820: + mdecWrite0(value); break; + case 0x1f801824: + mdecWrite1(value); break; + + case 0x1f801100: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount(0, value & 0xffff); return; + case 0x1f801104: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 MODE 32bit write %lx\n", value); +#endif + psxRcntWmode(0, value); return; + case 0x1f801108: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 0 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget(0, value & 0xffff); return; // HW_DMA_ICR&= SWAP32((~value)&0xff000000); + + case 0x1f801110: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount(1, value & 0xffff); return; + case 0x1f801114: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 MODE 32bit write %lx\n", value); +#endif + psxRcntWmode(1, value); return; + case 0x1f801118: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 1 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget(1, value & 0xffff); return; + + case 0x1f801120: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 COUNT 32bit write %lx\n", value); +#endif + psxRcntWcount(2, value & 0xffff); return; + case 0x1f801124: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 MODE 32bit write %lx\n", value); +#endif + psxRcntWmode(2, value); return; + case 0x1f801128: +#ifdef PSXHW_LOG + PSXHW_LOG("COUNTER 2 TARGET 32bit write %lx\n", value); +#endif + psxRcntWtarget(2, value & 0xffff); return; + + default: + psxHu32ref(add) = SWAPu32(value); +#ifdef PSXHW_LOG + PSXHW_LOG("*Unknown 32bit write at address %lx value %lx\n", add, value); +#endif + return; + } + psxHu32ref(add) = SWAPu32(value); +#ifdef PSXHW_LOG + PSXHW_LOG("*Known 32bit write at address %lx value %lx\n", add, value); +#endif +} + +int psxHwFreeze(gzFile f, int Mode) { + char Unused[4096]; + + gzfreezel(Unused); + + return 0; +} diff --git a/psxhw.h b/psxhw.h new file mode 100644 index 0000000..37d97f1 --- /dev/null +++ b/psxhw.h @@ -0,0 +1,73 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PSXHW_H__ +#define __PSXHW_H__ + +#include "psxcommon.h" +#include "r3000a.h" +#include "psxmem.h" +#include "sio.h" +#include "psxcounters.h" + +#define HW_DMA0_MADR (psxHu32ref(0x1080)) // MDEC in DMA +#define HW_DMA0_BCR (psxHu32ref(0x1084)) +#define HW_DMA0_CHCR (psxHu32ref(0x1088)) + +#define HW_DMA1_MADR (psxHu32ref(0x1090)) // MDEC out DMA +#define HW_DMA1_BCR (psxHu32ref(0x1094)) +#define HW_DMA1_CHCR (psxHu32ref(0x1098)) + +#define HW_DMA2_MADR (psxHu32ref(0x10a0)) // GPU DMA +#define HW_DMA2_BCR (psxHu32ref(0x10a4)) +#define HW_DMA2_CHCR (psxHu32ref(0x10a8)) + +#define HW_DMA3_MADR (psxHu32ref(0x10b0)) // CDROM DMA +#define HW_DMA3_BCR (psxHu32ref(0x10b4)) +#define HW_DMA3_CHCR (psxHu32ref(0x10b8)) + +#define HW_DMA4_MADR (psxHu32ref(0x10c0)) // SPU DMA +#define HW_DMA4_BCR (psxHu32ref(0x10c4)) +#define HW_DMA4_CHCR (psxHu32ref(0x10c8)) + +#define HW_DMA6_MADR (psxHu32ref(0x10e0)) // GPU DMA (OT) +#define HW_DMA6_BCR (psxHu32ref(0x10e4)) +#define HW_DMA6_CHCR (psxHu32ref(0x10e8)) + +#define HW_DMA_PCR (psxHu32ref(0x10f0)) +#define HW_DMA_ICR (psxHu32ref(0x10f4)) + +#define DMA_INTERRUPT(n) \ + if (SWAPu32(HW_DMA_ICR) & (1 << (16 + n))) { \ + HW_DMA_ICR|= SWAP32(1 << (24 + n)); \ + psxHu32ref(0x1070) |= SWAP32(8); \ + psxRegs.interrupt|= 0x80000000; \ + } + + +void psxHwReset(); +u8 psxHwRead8 (u32 add); +u16 psxHwRead16(u32 add); +u32 psxHwRead32(u32 add); +void psxHwWrite8 (u32 add, u8 value); +void psxHwWrite16(u32 add, u16 value); +void psxHwWrite32(u32 add, u32 value); +int psxHwFreeze(gzFile f, int Mode); + +#endif /* __PSXHW_H__ */ diff --git a/psxinterpreter.c b/psxinterpreter.c new file mode 100644 index 0000000..88e7b6a --- /dev/null +++ b/psxinterpreter.c @@ -0,0 +1,851 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* PSX assembly interpreter. +*/ + +#include "psxcommon.h" +#include "r3000a.h" +#include "gte.h" +#include "psxhle.h" + +static int branch = 0; +static int branch2 = 0; +static u32 branchPC; + +extern int stop; + +// These macros are used to assemble the repassembler functions + +#ifdef PSXCPU_LOG +#define debugI() PSXCPU_LOG("%s\n", disR3000AF(psxRegs.code, psxRegs.pc)); +#else +#define debugI() +#endif + +inline void execI(); + +// Subsets +void (*psxBSC[64])(); +void (*psxSPC[64])(); +void (*psxREG[32])(); +void (*psxCP0[32])(); +void (*psxCP2[64])(); +void (*psxCP2BSC[32])(); + +static void delayRead(int reg, u32 bpc) { + u32 rold, rnew; + +// SysPrintf("delayRead at %x!\n", psxRegs.pc); + + rold = psxRegs.GPR.r[reg]; + psxBSC[psxRegs.code >> 26](); // branch delay load + rnew = psxRegs.GPR.r[reg]; + + psxRegs.pc = bpc; + + psxBranchTest(); + + psxRegs.GPR.r[reg] = rold; + execI(); // first branch opcode + psxRegs.GPR.r[reg] = rnew; + + branch = 0; +} + +static void delayWrite(int reg, u32 bpc) { + +/* SysPrintf("delayWrite at %x!\n", psxRegs.pc); + + SysPrintf("%s\n", disR3000AF(psxRegs.code, psxRegs.pc-4)); + SysPrintf("%s\n", disR3000AF(PSXMu32(bpc), bpc));*/ + + // no changes from normal behavior + + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +static void delayReadWrite(int reg, u32 bpc) { + +// SysPrintf("delayReadWrite at %x!\n", psxRegs.pc); + + // the branch delay load is skipped + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +// this defines shall be used with the tmp +// of the next func (instead of _Funct_...) +#define _tFunct_ ((tmp ) & 0x3F) // The funct part of the instruction register +#define _tRd_ ((tmp >> 11) & 0x1F) // The rd part of the instruction register +#define _tRt_ ((tmp >> 16) & 0x1F) // The rt part of the instruction register +#define _tRs_ ((tmp >> 21) & 0x1F) // The rs part of the instruction register +#define _tSa_ ((tmp >> 6) & 0x1F) // The sa part of the instruction register + +int psxTestLoadDelay(int reg, u32 tmp) { + if (tmp == 0) return 0; // NOP + switch (tmp >> 26) { + case 0x00: // SPECIAL + switch (_tFunct_) { + case 0x00: // SLL + case 0x02: case 0x03: // SRL/SRA + if (_tRd_ == reg && _tRt_ == reg) return 1; else + if (_tRt_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + case 0x08: // JR + if (_tRs_ == reg) return 2; + break; + case 0x09: // JALR + if (_tRd_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + // SYSCALL/BREAK just a break; + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x2a: case 0x2b: // ADD/ADDU... + case 0x04: case 0x06: case 0x07: // SLLV... + if (_tRd_ == reg && (_tRt_ == reg || _tRs_ == reg)) return 1; else + if (_tRt_ == reg || _tRs_ == reg) return 2; else + if (_tRd_ == reg) return 3; + break; + + case 0x10: case 0x12: // MFHI/MFLO + if (_tRd_ == reg) return 3; + break; + case 0x11: case 0x13: // MTHI/MTLO + if (_tRs_ == reg) return 2; + break; + + case 0x18: case 0x19: + case 0x1a: case 0x1b: // MULT/DIV... + if (_tRt_ == reg || _tRs_ == reg) return 2; + break; + } + break; + + case 0x01: // REGIMM + switch (_tRt_) { + case 0x00: case 0x02: + case 0x10: case 0x12: // BLTZ/BGEZ... + if (_tRs_ == reg) return 2; + break; + } + break; + + // J would be just a break; + case 0x03: // JAL + if (31 == reg) return 3; + break; + + case 0x04: case 0x05: // BEQ/BNE + if (_tRs_ == reg || _tRt_ == reg) return 2; + break; + + case 0x06: case 0x07: // BLEZ/BGTZ + if (_tRs_ == reg) return 2; + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: // ADDI/ADDIU... + if (_tRt_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRt_ == reg) return 3; + break; + + case 0x0f: // LUI + if (_tRt_ == reg) return 3; + break; + + case 0x10: // COP0 + switch (_tFunct_) { + case 0x00: // MFC0 + if (_tRt_ == reg) return 3; + break; + case 0x02: // CFC0 + if (_tRt_ == reg) return 3; + break; + case 0x04: // MTC0 + if (_tRt_ == reg) return 2; + break; + case 0x06: // CTC0 + if (_tRt_ == reg) return 2; + break; + // RFE just a break; + } + break; + + case 0x12: // COP2 + switch (_tFunct_) { + case 0x00: + switch (_tRs_) { + case 0x00: // MFC2 + if (_tRt_ == reg) return 3; + break; + case 0x02: // CFC2 + if (_tRt_ == reg) return 3; + break; + case 0x04: // MTC2 + if (_tRt_ == reg) return 2; + break; + case 0x06: // CTC2 + if (_tRt_ == reg) return 2; + break; + } + break; + // RTPS... break; + } + break; + + case 0x22: case 0x26: // LWL/LWR + if (_tRt_ == reg) return 3; else + if (_tRs_ == reg) return 2; + break; + + case 0x20: case 0x21: case 0x23: + case 0x24: case 0x25: // LB/LH/LW/LBU/LHU + if (_tRt_ == reg && _tRs_ == reg) return 1; else + if (_tRs_ == reg) return 2; else + if (_tRt_ == reg) return 3; + break; + + case 0x28: case 0x29: case 0x2a: + case 0x2b: case 0x2e: // SB/SH/SWL/SW/SWR + if (_tRt_ == reg || _tRs_ == reg) return 2; + break; + + case 0x32: case 0x3a: // LWC2/SWC2 + if (_tRs_ == reg) return 2; + break; + } + + return 0; +} + +void psxDelayTest(int reg, u32 bpc) { + u32 *code; + u32 tmp; + + code = (u32*)PSXM(bpc); + tmp = code == NULL ? 0 : SWAP32(*code); + branch = 1; + + switch (psxTestLoadDelay(reg, tmp)) { + case 1: + delayReadWrite(reg, bpc); return; + case 2: + delayRead(reg, bpc); return; + case 3: + delayWrite(reg, bpc); return; + } + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = bpc; + + psxBranchTest(); +} + +__inline void doBranch(u32 tar) { + u32 *code; + u32 tmp; + + branch2 = branch = 1; + branchPC = tar; + + code = (u32*)PSXM(psxRegs.pc); + psxRegs.code = code == NULL ? 0 : SWAP32(*code); + + debugI(); + + psxRegs.pc+= 4; psxRegs.cycle++; + + // check for load delay + tmp = psxRegs.code >> 26; + switch (tmp) { + case 0x10: // COP0 + switch (_Rs_) { + case 0x00: // MFC0 + case 0x02: // CFC0 + psxDelayTest(_Rt_, branchPC); + return; + } + break; + case 0x12: // COP2 + switch (_Funct_) { + case 0x00: + switch (_Rs_) { + case 0x00: // MFC2 + case 0x02: // CFC2 + psxDelayTest(_Rt_, branchPC); + return; + } + break; + } + break; + case 0x32: // LWC2 + psxDelayTest(_Rt_, branchPC); + return; + default: + if (tmp >= 0x20 && tmp <= 0x26) { // LB/LH/LWL/LW/LBU/LHU/LWR + psxDelayTest(_Rt_, branchPC); + return; + } + break; + } + + psxBSC[psxRegs.code >> 26](); + + branch = 0; + psxRegs.pc = branchPC; + + psxBranchTest(); +} + +/********************************************************* +* Arithmetic with immediate operand * +* Format: OP rt, rs, immediate * +*********************************************************/ +void psxADDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im (Exception on Integer Overflow) +void psxADDIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) + _Imm_ ; } // Rt = Rs + Im +void psxANDI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) & _ImmU_; } // Rt = Rs And Im +void psxORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) | _ImmU_; } // Rt = Rs Or Im +void psxXORI() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) ^ _ImmU_; } // Rt = Rs Xor Im +void psxSLTI() { if (!_Rt_) return; _rRt_ = _i32(_rRs_) < _Imm_ ; } // Rt = Rs < Im (Signed) +void psxSLTIU() { if (!_Rt_) return; _rRt_ = _u32(_rRs_) < ((u32)_Imm_); } // Rt = Rs < Im (Unsigned) + +/********************************************************* +* Register arithmetic * +* Format: OP rd, rs, rt * +*********************************************************/ +void psxADD() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt (Exception on Integer Overflow) +void psxADDU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) + _u32(_rRt_); } // Rd = Rs + Rt +void psxSUB() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt (Exception on Integer Overflow) +void psxSUBU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) - _u32(_rRt_); } // Rd = Rs - Rt +void psxAND() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) & _u32(_rRt_); } // Rd = Rs And Rt +void psxOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) | _u32(_rRt_); } // Rd = Rs Or Rt +void psxXOR() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) ^ _u32(_rRt_); } // Rd = Rs Xor Rt +void psxNOR() { if (!_Rd_) return; _rRd_ =~(_u32(_rRs_) | _u32(_rRt_)); }// Rd = Rs Nor Rt +void psxSLT() { if (!_Rd_) return; _rRd_ = _i32(_rRs_) < _i32(_rRt_); } // Rd = Rs < Rt (Signed) +void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd = Rs < Rt (Unsigned) + +/********************************************************* +* Register mult/div & Register trap logic * +* Format: OP rs, rt * +*********************************************************/ +void psxDIV() { + if (_i32(_rRt_) != 0) { + _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_); + _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_); + } +} + +void psxDIVU() { + if (_rRt_ != 0) { + _rLo_ = _rRs_ / _rRt_; + _rHi_ = _rRs_ % _rRt_; + } +} + +void psxMULT() { + u64 res = (s64)((s64)_i32(_rRs_) * (s64)_i32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +void psxMULTU() { + u64 res = (u64)((u64)_u32(_rRs_) * (u64)_u32(_rRt_)); + + psxRegs.GPR.n.lo = (u32)(res & 0xffffffff); + psxRegs.GPR.n.hi = (u32)((res >> 32) & 0xffffffff); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, offset * +*********************************************************/ +#define RepZBranchi32(op) if(_i32(_rRs_) op 0) doBranch(_BranchTarget_); +#define RepZBranchLinki32(op) if(_i32(_rRs_) op 0) { _SetLink(31); doBranch(_BranchTarget_); } + +void psxBGEZ() { RepZBranchi32(>=) } // Branch if Rs >= 0 +void psxBGEZAL() { RepZBranchLinki32(>=) } // Branch if Rs >= 0 and link +void psxBGTZ() { RepZBranchi32(>) } // Branch if Rs > 0 +void psxBLEZ() { RepZBranchi32(<=) } // Branch if Rs <= 0 +void psxBLTZ() { RepZBranchi32(<) } // Branch if Rs < 0 +void psxBLTZAL() { RepZBranchLinki32(<) } // Branch if Rs < 0 and link + +/********************************************************* +* Shift arithmetic with constant shift * +* Format: OP rd, rt, sa * +*********************************************************/ +void psxSLL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _Sa_; } // Rd = Rt << sa +void psxSRA() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (arithmetic) +void psxSRL() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _Sa_; } // Rd = Rt >> sa (logical) + +/********************************************************* +* Shift arithmetic with variant register shift * +* Format: OP rd, rt, rs * +*********************************************************/ +void psxSLLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) << _u32(_rRs_); } // Rd = Rt << rs +void psxSRAV() { if (!_Rd_) return; _i32(_rRd_) = _i32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (arithmetic) +void psxSRLV() { if (!_Rd_) return; _u32(_rRd_) = _u32(_rRt_) >> _u32(_rRs_); } // Rd = Rt >> rs (logical) + +/********************************************************* +* Load higher 16 bits of the first word in GPR with imm * +* Format: OP rt, immediate * +*********************************************************/ +void psxLUI() { if (!_Rt_) return; _u32(_rRt_) = psxRegs.code << 16; } // Upper halfword of Rt = Im + +/********************************************************* +* Move from HI/LO to GPR * +* Format: OP rd * +*********************************************************/ +void psxMFHI() { if (!_Rd_) return; _rRd_ = _rHi_; } // Rd = Hi +void psxMFLO() { if (!_Rd_) return; _rRd_ = _rLo_; } // Rd = Lo + +/********************************************************* +* Move to GPR to HI/LO & Register jump * +* Format: OP rs * +*********************************************************/ +void psxMTHI() { _rHi_ = _rRs_; } // Hi = Rs +void psxMTLO() { _rLo_ = _rRs_; } // Lo = Rs + +/********************************************************* +* Special purpose instructions * +* Format: OP * +*********************************************************/ +void psxBREAK() { + // Break exception - psx rom doens't handles this +} + +void psxSYSCALL() { + psxRegs.pc -= 4; + psxException(0x20, branch); +} + +void psxRFE() { +// SysPrintf("psxRFE\n"); + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status & 0xfffffff0) | + ((psxRegs.CP0.n.Status & 0x3c) >> 2); +} + +/********************************************************* +* Register branch logic * +* Format: OP rs, rt, offset * +*********************************************************/ +#define RepBranchi32(op) if(_i32(_rRs_) op _i32(_rRt_)) doBranch(_BranchTarget_); + +void psxBEQ() { RepBranchi32(==) } // Branch if Rs == Rt +void psxBNE() { RepBranchi32(!=) } // Branch if Rs != Rt + +/********************************************************* +* Jump to target * +* Format: OP target * +*********************************************************/ +void psxJ() { doBranch(_JumpTarget_); } +void psxJAL() { _SetLink(31); doBranch(_JumpTarget_); } + +/********************************************************* +* Register jump * +* Format: OP rs, rd * +*********************************************************/ +void psxJR() { + doBranch(_u32(_rRs_)); + psxJumpTest(); +} + +void psxJALR() { + u32 temp = _u32(_rRs_); + if (_Rd_) { _SetLink(_Rd_); } + doBranch(temp); +} + +/********************************************************* +* Load and store for GPR * +* Format: OP rt, offset(base) * +*********************************************************/ + +#define _oB_ (_u32(_rRs_) + _Imm_) + +void psxLB() { + if (_Rt_) { + _i32(_rRt_) = (signed char)psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLBU() { + if (_Rt_) { + _u32(_rRt_) = psxMemRead8(_oB_); + } else { + psxMemRead8(_oB_); + } +} + +void psxLH() { + if (_Rt_) { + _i32(_rRt_) = (short)psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLHU() { + if (_Rt_) { + _u32(_rRt_) = psxMemRead16(_oB_); + } else { + psxMemRead16(_oB_); + } +} + +void psxLW() { + if (_Rt_) { + _u32(_rRt_) = psxMemRead32(_oB_); + } else { + psxMemRead32(_oB_); + } +} + +u32 LWL_MASK[4] = { 0xffffff, 0xffff, 0xff, 0 }; +u32 LWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void psxLWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + if (!_Rt_) return; + _u32(_rRt_) = ( _u32(_rRt_) & LWL_MASK[shift]) | + ( mem << LWL_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 4bcd (mem << 24) | (reg & 0x00ffffff) + 1 34cd (mem << 16) | (reg & 0x0000ffff) + 2 234d (mem << 8) | (reg & 0x000000ff) + 3 1234 (mem ) | (reg & 0x00000000) + */ +} + +u32 LWR_MASK[4] = { 0, 0xff000000, 0xffff0000, 0xffffff00 }; +u32 LWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void psxLWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + if (!_Rt_) return; + _u32(_rRt_) = ( _u32(_rRt_) & LWR_MASK[shift]) | + ( mem >> LWR_SHIFT[shift]); + + /* + Mem = 1234. Reg = abcd + + 0 1234 (mem ) | (reg & 0x00000000) + 1 a123 (mem >> 8) | (reg & 0xff000000) + 2 ab12 (mem >> 16) | (reg & 0xffff0000) + 3 abc1 (mem >> 24) | (reg & 0xffffff00) + */ +} + +void psxSB() { psxMemWrite8 (_oB_, _u8 (_rRt_)); } +void psxSH() { psxMemWrite16(_oB_, _u16(_rRt_)); } +void psxSW() { psxMemWrite32(_oB_, _u32(_rRt_)); } + +u32 SWL_MASK[4] = { 0xffffff00, 0xffff0000, 0xff000000, 0 }; +u32 SWL_SHIFT[4] = { 24, 16, 8, 0 }; + +void psxSWL() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | + ( mem & SWL_MASK[shift]) ); + /* + Mem = 1234. Reg = abcd + + 0 123a (reg >> 24) | (mem & 0xffffff00) + 1 12ab (reg >> 16) | (mem & 0xffff0000) + 2 1abc (reg >> 8) | (mem & 0xff000000) + 3 abcd (reg ) | (mem & 0x00000000) + */ +} + +u32 SWR_MASK[4] = { 0, 0xff, 0xffff, 0xffffff }; +u32 SWR_SHIFT[4] = { 0, 8, 16, 24 }; + +void psxSWR() { + u32 addr = _oB_; + u32 shift = addr & 3; + u32 mem = psxMemRead32(addr & ~3); + + psxMemWrite32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | + ( mem & SWR_MASK[shift]) ); + + /* + Mem = 1234. Reg = abcd + + 0 abcd (reg ) | (mem & 0x00000000) + 1 bcd4 (reg << 8) | (mem & 0x000000ff) + 2 cd34 (reg << 16) | (mem & 0x0000ffff) + 3 d234 (reg << 24) | (mem & 0x00ffffff) + */ +} + +/********************************************************* +* Moves between GPR and COPx * +* Format: OP rt, fs * +*********************************************************/ +void psxMFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; } +void psxCFC0() { if (!_Rt_) return; _i32(_rRt_) = (int)_rFs_; } + +void psxTestSWInts() { + // the next code is untested, if u know please + // tell me if it works ok or not (linuzappz) + if (psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x0300 && + psxRegs.CP0.n.Status & 0x1) { + psxException(psxRegs.CP0.n.Cause, branch); + } +} + +__inline void MTC0(int reg, u32 val) { +// SysPrintf("MTC0 %d: %x\n", reg, val); + switch (reg) { + case 12: // Status + psxRegs.CP0.r[12] = val; + psxTestSWInts(); + psxRegs.interrupt|= 0x80000000; + break; + + case 13: // Cause + psxRegs.CP0.n.Cause = val & ~(0xfc00); + psxTestSWInts(); + break; + + default: + psxRegs.CP0.r[reg] = val; + break; + } +} + +void psxMTC0() { MTC0(_Rd_, _u32(_rRt_)); } +void psxCTC0() { MTC0(_Rd_, _u32(_rRt_)); } + +/********************************************************* +* Unknow instruction (would generate an exception) * +* Format: ? * +*********************************************************/ +void psxNULL() { +#ifdef PSXCPU_LOG + PSXCPU_LOG("psx: Unimplemented op %x\n", psxRegs.code); +#endif +} + +void psxSPECIAL() { + psxSPC[_Funct_](); +} + +void psxREGIMM() { + psxREG[_Rt_](); +} + +void psxCOP0() { + psxCP0[_Rs_](); +} + +void psxCOP2() { + psxCP2[_Funct_](); +} + +void psxBASIC() { + psxCP2BSC[_Rs_](); +} + +void psxHLE() { +// psxHLEt[psxRegs.code & 0xffff](); + psxHLEt[psxRegs.code & 0x07](); // HDHOSHY experimental patch +} + +void (*psxBSC[64])() = { + psxSPECIAL, psxREGIMM, psxJ , psxJAL , psxBEQ , psxBNE , psxBLEZ, psxBGTZ, + psxADDI , psxADDIU , psxSLTI, psxSLTIU, psxANDI, psxORI , psxXORI, psxLUI , + psxCOP0 , psxNULL , psxCOP2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxLB , psxLH , psxLWL , psxLW , psxLBU , psxLHU , psxLWR , psxNULL, + psxSB , psxSH , psxSWL , psxSW , psxNULL, psxNULL, psxSWR , psxNULL, + psxNULL , psxNULL , gteLWC2, psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , gteSWC2, psxHLE , psxNULL, psxNULL, psxNULL, psxNULL +}; + + +void (*psxSPC[64])() = { + psxSLL , psxNULL , psxSRL , psxSRA , psxSLLV , psxNULL , psxSRLV, psxSRAV, + psxJR , psxJALR , psxNULL, psxNULL, psxSYSCALL, psxBREAK, psxNULL, psxNULL, + psxMFHI, psxMTHI , psxMFLO, psxMTLO, psxNULL , psxNULL , psxNULL, psxNULL, + psxMULT, psxMULTU, psxDIV , psxDIVU, psxNULL , psxNULL , psxNULL, psxNULL, + psxADD , psxADDU , psxSUB , psxSUBU, psxAND , psxOR , psxXOR , psxNOR , + psxNULL, psxNULL , psxSLT , psxSLTU, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL, + psxNULL, psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, psxNULL +}; + +void (*psxREG[32])() = { + psxBLTZ , psxBGEZ , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxBLTZAL, psxBGEZAL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL , psxNULL , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP0[32])() = { + psxMFC0, psxNULL, psxCFC0, psxNULL, psxMTC0, psxNULL, psxCTC0, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxRFE , psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + +void (*psxCP2[64])() = { + psxBASIC, gteRTPS , psxNULL , psxNULL, psxNULL, psxNULL , gteNCLIP, psxNULL, // 00 + psxNULL , psxNULL , psxNULL , psxNULL, gteOP , psxNULL , psxNULL , psxNULL, // 08 + gteDPCS , gteINTPL, gteMVMVA, gteNCDS, gteCDP , psxNULL , gteNCDT , psxNULL, // 10 + psxNULL , psxNULL , psxNULL , gteNCCS, gteCC , psxNULL , gteNCS , psxNULL, // 18 + gteNCT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 20 + gteSQR , gteDCPL , gteDPCT , psxNULL, psxNULL, gteAVSZ3, gteAVSZ4, psxNULL, // 28 + gteRTPT , psxNULL , psxNULL , psxNULL, psxNULL, psxNULL , psxNULL , psxNULL, // 30 + psxNULL , psxNULL , psxNULL , psxNULL, psxNULL, gteGPF , gteGPL , gteNCCT // 38 +}; + +void (*psxCP2BSC[32])() = { + gteMFC2, psxNULL, gteCFC2, psxNULL, gteMTC2, psxNULL, gteCTC2, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, + psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL, psxNULL +}; + + +/////////////////////////////////////////// + +static int intInit() { + return 0; +} + +static void intReset() { +} + +static void intExecute() { + while(!stop) + execI(); +} + +static void intExecuteDbg() { + /*for (;;) + execIDbg();*/ +} + +static void intExecuteBlock() { + branch2 = 0; + while (!branch2) execI(); +} + +static void intExecuteBlockDbg() { + /*branch2 = 0; + while (!branch2) execIDbg();*/ +} + +static void intClear(u32 Addr, u32 Size) { +} + +static void intShutdown() { +} + +// interpreter execution +inline void execI() { + u32 *code = (u32*)PSXM(psxRegs.pc); + psxRegs.code = code == NULL ? 0 : SWAP32(*code); + + debugI(); + + psxRegs.pc+= 4; psxRegs.cycle++; + psxBSC[psxRegs.code >> 26](); + +} + +/* debugger version */ +inline void execIDbg() { +/* u32 *code = PSXM(psxRegs.pc); + psxRegs.code = code == NULL ? 0 : SWAP32(*code); + + // dump opcode when LOG_CPU is enabled + debugI(); + + // normal execution + if(!hdb_pause) { + psxRegs.pc+= 4; psxRegs.cycle++; + psxBSC[psxRegs.code >> 26](); + } + + // trace one instruction + if(hdb_pause == 2) { + psxRegs.pc+= 4; psxRegs.cycle++; + psxBSC[psxRegs.code >> 26](); + hdb_pause = 1; + } + + // wait for breakpoint + if(hdb_pause == 3) { + psxRegs.pc+= 4; psxRegs.cycle++; + psxBSC[psxRegs.code >> 26](); + if(psxRegs.pc == hdb_break) hdb_pause = 1; + }*/ +} + +R3000Acpu psxInt = { + intInit, + intReset, + intExecute, + intExecuteBlock, + intClear, + intShutdown +}; + +R3000Acpu psxIntDbg = { + intInit, + intReset, + intExecuteDbg, + intExecuteBlockDbg, + intClear, + intShutdown +}; diff --git a/psxmem.c b/psxmem.c new file mode 100644 index 0000000..045ad43 --- /dev/null +++ b/psxmem.c @@ -0,0 +1,326 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* Playstation Memory Map (from Playstation doc by Joshua Walker) +0x0000_0000-0x0000_ffff Kernel (64K) +0x0001_0000-0x001f_ffff User Memory (1.9 Meg) + +0x1f00_0000-0x1f00_ffff Parallel Port (64K) + +0x1f80_0000-0x1f80_03ff Scratch Pad (1024 bytes) + +0x1f80_1000-0x1f80_2fff Hardware Registers (8K) + +0x8000_0000-0x801f_ffff Kernel and User Memory Mirror (2 Meg) Cached + +0xa000_0000-0xa01f_ffff Kernel and User Memory Mirror (2 Meg) Uncached + +0xbfc0_0000-0xbfc7_ffff BIOS (512K) +*/ + +/* +* PSX memory functions. +*/ + +/* Ryan TODO: I'd rather not use GLib in here */ + +#include +#include +#include +#include "psxmem.h" +#include "r3000a.h" +#include "psxhw.h" +#include "Gamecube/fileBrowser/fileBrowser.h" +#include "Gamecube/fileBrowser/fileBrowser-libfat.h" +#include "Gamecube/fileBrowser/fileBrowser-CARD.h" +#include "Gamecube/fileBrowser/fileBrowser-DVD.h" +#include "Gamecube/wiiSXconfig.h" + +extern void SysMessage(char *fmt, ...); + +s8 psxM[0x00220000] __attribute__((aligned(32))); +s8 psxR[0x00080000] __attribute__((aligned(32))); +u8* psxMemWLUT[0x10000] __attribute__((aligned(32))); +u8* psxMemRLUT[0x10000] __attribute__((aligned(32))); + +int psxMemInit() { + int i; + + //psxMemRLUT = (u8**)memalign(32,0x10000 * sizeof(void*)); + //psxMemWLUT = (u8**)memalign(32,0x10000 * sizeof(void*)); + memset(psxMemRLUT, 0, 0x10000 * sizeof(void*)); + memset(psxMemWLUT, 0, 0x10000 * sizeof(void*)); + //psxM = memalign(32,0x00220000); + psxP = &psxM[0x200000]; + psxH = &psxM[0x210000]; + //psxR = (s8*)memalign(32,0x00080000); + /*if (psxMemRLUT == NULL || psxMemWLUT == NULL || + psxM == NULL || psxP == NULL || psxH == NULL) { + SysMessage(_("Error allocating memory!")); return -1; + }*/ + +// MemR + for (i=0; i<0x80; i++) psxMemRLUT[i + 0x0000] = (u8*)&psxM[(i & 0x1f) << 16]; + + memcpy(psxMemRLUT + 0x8000, psxMemRLUT, 0x80 * sizeof(void*)); + memcpy(psxMemRLUT + 0xa000, psxMemRLUT, 0x80 * sizeof(void*)); + + for (i=0; i<0x01; i++) psxMemRLUT[i + 0x1f00] = (u8*)&psxP[i << 16]; + + for (i=0; i<0x01; i++) psxMemRLUT[i + 0x1f80] = (u8*)&psxH[i << 16]; + + for (i=0; i<0x08; i++) psxMemRLUT[i + 0xbfc0] = (u8*)&psxR[i << 16]; + +// MemW + for (i=0; i<0x80; i++) psxMemWLUT[i + 0x0000] = (u8*)&psxM[(i & 0x1f) << 16]; + memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void*)); + memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void*)); + + for (i=0; i<0x01; i++) psxMemWLUT[i + 0x1f00] = (u8*)&psxP[i << 16]; + + for (i=0; i<0x01; i++) psxMemWLUT[i + 0x1f80] = (u8*)&psxH[i << 16]; + + return 0; +} + +void psxMemReset() { + //printf("BIOS file %s\n",biosFile->name); + int temp; + memset(psxM, 0, 0x00200000); + memset(psxP, 0, 0x00010000); + memset(psxR, 0, 0x80000); + if(!biosFile || (biosDevice == BIOSDEVICE_HLE)) { + Config.HLE = BIOS_HLE; + return; + } + else { + biosFile->offset = 0; //must reset otherwise the if statement will fail! + if(biosFile_readFile(biosFile, &temp, 4) == 4) { //bios file exists + biosFile->offset = 0; + if(biosFile_readFile(biosFile, psxR, 0x80000) != 0x80000) { //failed size + //printf("Using HLE\n"); + Config.HLE = BIOS_HLE; + } + else { + //printf("Using BIOS file %s\n",biosFile->name); + Config.HLE = BIOS_USER_DEFINED; + } + } + else { //bios fails to open + Config.HLE = BIOS_HLE; + } + } +} + +void psxMemShutdown() { +/* free(psxM); + free(psxR); + free(psxMemRLUT); + free(psxMemWLUT);*/ +} + +static int writeok=1; + +u8 psxMemRead8(u32 mem) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return psxHu8(mem); + else + return psxHwRead8(mem); + } else { + char *p = (char *)(psxMemRLUT[t]); + if (p != NULL) { + return *(u8 *)(p + (mem & 0xffff)); + } else { +#ifdef PSXMEM_LOG + PSXMEM_LOG("err lb %8.8lx\n", mem); +#endif + return 0; + } + } +} + +u16 psxMemRead16(u32 mem) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return psxHu16(mem); + else + return psxHwRead16(mem); + } else { + char *p = (char *)(psxMemRLUT[t]); + if (p != NULL) { + return SWAPu16(*(u16 *)(p + (mem & 0xffff))); + } else { +#ifdef PSXMEM_LOG + PSXMEM_LOG("err lh %8.8lx\n", mem); +#endif + return 0; + } + } +} + +u32 psxMemRead32(u32 mem) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return psxHu32(mem); + else + return psxHwRead32(mem); + } else { + char *p = (char *)(psxMemRLUT[t]); + if (p != NULL) { + return SWAPu32(*(u32 *)(p + (mem & 0xffff))); + } else { +#ifdef PSXMEM_LOG + if (writeok) { PSXMEM_LOG("err lw %8.8lx\n", mem); } +#endif + return 0; + } + } +} + +void psxMemWrite8(u32 mem, u8 value) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu8(mem) = value; + else + psxHwWrite8(mem, value); + } else { + char *p = (char *)(psxMemWLUT[t]); + if (p != NULL) { + *(u8 *)(p + (mem & 0xffff)) = value; +#ifdef PSXREC + psxCpu->Clear((mem&(~3)), 1); +#endif + } else { +#ifdef PSXMEM_LOG + PSXMEM_LOG("err sb %8.8lx\n", mem); +#endif + } + } +} + +void psxMemWrite16(u32 mem, u16 value) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu16ref(mem) = SWAPu16(value); + else + psxHwWrite16(mem, value); + } else { + char *p = (char *)(psxMemWLUT[t]); + if (p != NULL) { + *(u16 *)(p + (mem & 0xffff)) = SWAPu16(value); +#ifdef PSXREC + psxCpu->Clear((mem&(~1)), 1); +#endif + } else { +#ifdef PSXMEM_LOG + PSXMEM_LOG("err sh %8.8lx\n", mem); +#endif + } + } +} + +void psxMemWrite32(u32 mem, u32 value) { + u32 t; + +// if ((mem&0x1fffff) == 0x71E18 || value == 0x48088800) SysPrintf("t2fix!!\n"); + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + psxHu32ref(mem) = SWAPu32(value); + else + psxHwWrite32(mem, value); + } else { + char *p = (char *)(psxMemWLUT[t]); + if (p != NULL) { + *(u32 *)(p + (mem & 0xffff)) = SWAPu32(value); +#ifdef PSXREC + psxCpu->Clear(mem, 1); +#endif + } else { + if (mem != 0xfffe0130) { +#ifdef PSXREC + if (!writeok) + psxCpu->Clear(mem, 1); +#endif + +#ifdef PSXMEM_LOG + if (writeok) { PSXMEM_LOG("err sw %8.8lx\n", mem); } +#endif + } else { + int i; + + switch (value) { + case 0x800: case 0x804: + if (writeok == 0) break; + writeok = 0; + memset(psxMemWLUT + 0x0000, 0, 0x80 * sizeof(void*)); + memset(psxMemWLUT + 0x8000, 0, 0x80 * sizeof(void*)); + memset(psxMemWLUT + 0xa000, 0, 0x80 * sizeof(void*)); + break; + case 0x1e988: + if (writeok == 1) break; + writeok = 1; + for (i=0; i<0x80; i++) psxMemWLUT[i + 0x0000] = (void*)&psxM[(i & 0x1f) << 16]; + memcpy(psxMemWLUT + 0x8000, psxMemWLUT, 0x80 * sizeof(void*)); + memcpy(psxMemWLUT + 0xa000, psxMemWLUT, 0x80 * sizeof(void*)); + break; + default: +#ifdef PSXMEM_LOG + PSXMEM_LOG("unk %8.8lx = %x\n", mem, value); +#endif + break; + } + } + } + } +} + +void *psxMemPointer(u32 mem) { + u32 t; + + t = mem >> 16; + if (t == 0x1f80) { + if (mem < 0x1f801000) + return (void *)&psxH[mem]; + else + return NULL; + } else { + char *p = (char *)(psxMemWLUT[t]); + if (p != NULL) { + return (void *)(p + (mem & 0xffff)); + } + return NULL; + } +} diff --git a/psxmem.h b/psxmem.h new file mode 100644 index 0000000..1931caf --- /dev/null +++ b/psxmem.h @@ -0,0 +1,143 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __PSXMEMORY_H__ +#define __PSXMEMORY_H__ + +#include "psxcommon.h" + +#if defined(HW_RVL) || defined(HW_DOL) || defined(BIG_ENDIAN) + +#define _SWAP16(b) ((((unsigned char*)&(b))[0]&0xff) | (((unsigned char*)&(b))[1]&0xff)<<8) +#define _SWAP32(b) ((((unsigned char*)&(b))[0]&0xff) | ((((unsigned char*)&(b))[1]&0xff)<<8) | ((((unsigned char*)&(b))[2]&0xff)<<16) | (((unsigned char*)&(b))[3]<<24)) + +#define SWAP16(v) ((((v)&0xff00)>>8) | (((v)&0xff)<<8)) +#define SWAP32(v) ((((v)&0xff000000ul)>>24) | (((v)&0xff0000ul)>>8) | (((v)&0xff00ul)<<8) | (((v)&0xfful)<<24)) +#define SWAPu32(v) SWAP32((u32)(v)) +#define SWAPs32(v) SWAP32((s32)(v)) + +#define SWAPu16(v) SWAP16((u16)(v)) +#define SWAPs16(v) SWAP16((s16)(v)) + +#define SWAP16p(ptr) ({u16 __ret, *__ptr=(ptr); __asm__ ("lhbrx %0, 0, %1" : "=r" (__ret) : "r" (__ptr)); __ret;}) +#define SWAP32p(ptr) ({u32 __ret, *__ptr=(ptr); __asm__ ("lwbrx %0, 0, %1" : "=r" (__ret) : "r" (__ptr)); __ret;}) +#define SWAP32wp(ptr,val) ({u32 __val=(val), *__ptr=(ptr); __asm__ ("stwbrx %0, 0, %1" : : "r" (__val), "r" (__ptr) : "memory");}) + +#else + +#define SWAP16(b) (b) +#define SWAP32(b) (b) + +#define SWAPu16(b) (b) +#define SWAPu32(b) (b) + +#endif + +extern s8 psxM[0x00220000] __attribute__((aligned(32))); +#define psxMs8(mem) psxM[(mem) & 0x1fffff] +#define psxMs16(mem) (SWAP16(*(s16*)&psxM[(mem) & 0x1fffff])) +#define psxMs32(mem) (SWAP32(*(s32*)&psxM[(mem) & 0x1fffff])) +#define psxMu8(mem) (*(u8*)&psxM[(mem) & 0x1fffff])) +#define psxMu16(mem) (SWAP16(*(u16*)&psxM[(mem) & 0x1fffff])) +#define psxMu32(mem) (SWAP32(*(u32*)&psxM[(mem) & 0x1fffff])) + +#define psxMs8ref(mem) psxM[(mem) & 0x1fffff] +#define psxMs16ref(mem) (*(s16*)&psxM[(mem) & 0x1fffff]) +#define psxMs32ref(mem) (*(s32*)&psxM[(mem) & 0x1fffff]) +#define psxMu8ref(mem) (*(u8*) &psxM[(mem) & 0x1fffff]) +#define psxMu16ref(mem) (*(u16*)&psxM[(mem) & 0x1fffff]) +#define psxMu32ref(mem) (*(u32*)&psxM[(mem) & 0x1fffff]) + +s8 *psxP; +#define psxPs8(mem) psxP[(mem) & 0xffff] +#define psxPs16(mem) (SWAP16(*(s16*)&psxP[(mem) & 0xffff])) +#define psxPs32(mem) (SWAP32(*(s32*)&psxP[(mem) & 0xffff])) +#define psxPu8(mem) (*(u8*) &psxP[(mem) & 0xffff]) +#define psxPu16(mem) (SWAP16(*(u16*)&psxP[(mem) & 0xffff])) +#define psxPu32(mem) (SWAP32(*(u32*)&psxP[(mem) & 0xffff])) + +#define psxPs8ref(mem) psxP[(mem) & 0xffff] +#define psxPs16ref(mem) (*(s16*)&psxP[(mem) & 0xffff]) +#define psxPs32ref(mem) (*(s32*)&psxP[(mem) & 0xffff]) +#define psxPu8ref(mem) (*(u8*) &psxP[(mem) & 0xffff]) +#define psxPu16ref(mem) (*(u16*)&psxP[(mem) & 0xffff]) +#define psxPu32ref(mem) (*(u32*)&psxP[(mem) & 0xffff]) + +extern s8 psxR[0x00080000] __attribute__((aligned(32))); +#define psxRs8(mem) psxR[(mem) & 0x7ffff] +#define psxRs16(mem) (SWAP16(*(s16*)&psxR[(mem) & 0x7ffff])) +#define psxRs32(mem) (SWAP32(*(s32*)&psxR[(mem) & 0x7ffff])) +#define psxRu8(mem) (*(u8* )&psxR[(mem) & 0x7ffff]) +#define psxRu16(mem) (SWAP16(*(u16*)&psxR[(mem) & 0x7ffff])) +#define psxRu32(mem) (SWAP32(*(u32*)&psxR[(mem) & 0x7ffff])) + +#define psxRs8ref(mem) psxR[(mem) & 0x7ffff] +#define psxRs16ref(mem) (*(s16*)&psxR[(mem) & 0x7ffff]) +#define psxRs32ref(mem) (*(s32*)&psxR[(mem) & 0x7ffff]) +#define psxRu8ref(mem) (*(u8* )&psxR[(mem) & 0x7ffff]) +#define psxRu16ref(mem) (*(u16*)&psxR[(mem) & 0x7ffff]) +#define psxRu32ref(mem) (*(u32*)&psxR[(mem) & 0x7ffff]) + +s8 *psxH; +#define psxHs8(mem) psxH[(mem) & 0xffff] +#define psxHs16(mem) (SWAP16(*(s16*)&psxH[(mem) & 0xffff])) +#define psxHs32(mem) (SWAP32(*(s32*)&psxH[(mem) & 0xffff])) +#define psxHu8(mem) (*(u8*) &psxH[(mem) & 0xffff]) +#define psxHu16(mem) (SWAP16(*(u16*)&psxH[(mem) & 0xffff])) +#define psxHu32(mem) (SWAP32(*(u32*)&psxH[(mem) & 0xffff])) + +#define psxHs8ref(mem) psxH[(mem) & 0xffff] +#define psxHs16ref(mem) (*(s16*)&psxH[(mem) & 0xffff]) +#define psxHs32ref(mem) (*(s32*)&psxH[(mem) & 0xffff]) +#define psxHu8ref(mem) (*(u8*) &psxH[(mem) & 0xffff]) +#define psxHu16ref(mem) (*(u16*)&psxH[(mem) & 0xffff]) +#define psxHu32ref(mem) (*(u32*)&psxH[(mem) & 0xffff]) + +extern u8* psxMemWLUT[0x10000] __attribute__((aligned(32))); +extern u8* psxMemRLUT[0x10000] __attribute__((aligned(32))); + +#define PSXM(mem) (psxMemRLUT[(mem) >> 16] == 0 ? NULL : (u8*)(psxMemRLUT[(mem) >> 16] + ((mem) & 0xffff))) +#define PSXMs8(mem) (*(s8 *)PSXM(mem)) +#define PSXMs16(mem) (SWAP16(*(s16*)PSXM(mem))) +#define PSXMs32(mem) (SWAP32(*(s32*)PSXM(mem))) +#define PSXMu8(mem) (*(u8 *)PSXM(mem)) +#define PSXMu16(mem) (SWAP16(*(u16*)PSXM(mem))) +#define PSXMu32(mem) (SWAP32(*(u32*)PSXM(mem))) + +#define PSXMu32ref(mem) (*(u32*)PSXM(mem)) + + +#if !defined PSXREC && (defined(__x86_64__) || defined(__i386__) || defined(__sh__) || defined(__ppc__) || defined(HW_RVL)) || defined(HW_DOL) +#define PSXREC +#endif + +int psxMemInit(); +void psxMemReset(); +void psxMemShutdown(); + +u8 psxMemRead8 (u32 mem); +u16 psxMemRead16(u32 mem); +u32 psxMemRead32(u32 mem); +void psxMemWrite8 (u32 mem, u8 value); +void psxMemWrite16(u32 mem, u16 value); +void psxMemWrite32(u32 mem, u32 value); +void *psxMemPointer(u32 mem); + +#endif /* __PSXMEMORY_H__ */ + diff --git a/r3000a.c b/r3000a.c new file mode 100644 index 0000000..55c4dd9 --- /dev/null +++ b/r3000a.c @@ -0,0 +1,202 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* R3000A CPU functions. +*/ + +#include "r3000a.h" +#include "psxhw.h" +#include "psxdma.h" +#include "cdrom.h" +#include "mdec.h" + +R3000Acpu *psxCpu; +psxRegisters psxRegs; + +int psxInit() { + + if(Config.Cpu) { + if(Config.Dbg) psxCpu = &psxIntDbg; + else psxCpu = &psxInt; + } +#if defined(__x86_64__) || defined(__i386__) || defined(__sh__) || defined(__ppc__) || defined(HW_RVL) || defined(HW_DOL) + if (!Config.Cpu) psxCpu = &psxRec; +#endif + Log=0; + + if (psxMemInit() == -1) return -1; + + return psxCpu->Init(); +} + +void psxReset() { + psxCpu->Reset(); + + psxMemReset(); + + memset(&psxRegs, 0, sizeof(psxRegs)); + + psxRegs.pc = 0xbfc00000; // Start in bootstrap + + psxRegs.CP0.r[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1 + psxRegs.CP0.r[15] = 0x00000002; // PRevID = Revision ID, same as R3000A + + psxHwReset(); + psxBiosInit(); + + if (!Config.HLE) psxExecuteBios(); + +#ifdef EMU_LOG + EMU_LOG("*BIOS END*\n"); +#endif + Log=0; +} + +void psxShutdown() { + psxMemShutdown(); + psxBiosShutdown(); + + psxCpu->Shutdown(); +} + +void psxException(u32 code, u32 bd) { + // Set the Cause + psxRegs.CP0.n.Cause = code; + + // Set the EPC & PC + if (bd) { +#ifdef PSXCPU_LOG + PSXCPU_LOG("bd set!!!\n"); +#endif + SysPrintf("bd set!!!\n"); + psxRegs.CP0.n.Cause|= 0x80000000; + psxRegs.CP0.n.EPC = (psxRegs.pc - 4); + } else + psxRegs.CP0.n.EPC = (psxRegs.pc); + + if (psxRegs.CP0.n.Status & 0x400000) + psxRegs.pc = 0xbfc00180; + else + psxRegs.pc = 0x80000080; + + // Set the Status + psxRegs.CP0.n.Status = (psxRegs.CP0.n.Status &~0x3f) | + ((psxRegs.CP0.n.Status & 0xf) << 2); + + if (!Config.HLE && (((PSXMu32(psxRegs.CP0.n.EPC) >> 24) & 0xfe) == 0x4a)) { + // "hokuto no ken" / "Crash Bandicot 2" ... fix + PSXMu32ref(psxRegs.CP0.n.EPC)&= SWAPu32(~0x02000000); + } + + if (Config.HLE) psxBiosException(); +} + +void psxBranchTest() { + if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter) + psxRcntUpdate(); + + if (psxRegs.interrupt) { + if ((psxRegs.interrupt & 0x80) && (!Config.Sio)) { // sio + if ((psxRegs.cycle - psxRegs.intCycle[7]) >= psxRegs.intCycle[7+1]) { + psxRegs.interrupt&=~0x80; + sioInterrupt(); + } + } + if (psxRegs.interrupt & 0x04) { // cdr + if ((psxRegs.cycle - psxRegs.intCycle[2]) >= psxRegs.intCycle[2+1]) { + psxRegs.interrupt&=~0x04; + cdrInterrupt(); + } + } + if (psxRegs.interrupt & 0x040000) { // cdr read + if ((psxRegs.cycle - psxRegs.intCycle[2+16]) >= psxRegs.intCycle[2+16+1]) { + psxRegs.interrupt&=~0x040000; + cdrReadInterrupt(); + } + } + if (psxRegs.interrupt & 0x01000000) { // gpu dma + if ((psxRegs.cycle - psxRegs.intCycle[3+24]) >= psxRegs.intCycle[3+24+1]) { + psxRegs.interrupt&=~0x01000000; + gpuInterrupt(); + } + } + if (psxRegs.interrupt & 0x02000000) { // mdec out dma + if ((psxRegs.cycle - psxRegs.intCycle[5+24]) >= psxRegs.intCycle[5+24+1]) { + psxRegs.interrupt&=~0x02000000; + mdec1Interrupt(); + } + } + + if (psxRegs.interrupt & 0x80000000) { + psxRegs.interrupt&=~0x80000000; + psxTestHWInts(); + } + } +// if (psxRegs.cycle > 0xd29c6500) Log=1; +} + +void psxTestHWInts() { + if (psxHu32(0x1070) & psxHu32(0x1074)) { + if ((psxRegs.CP0.n.Status & 0x401) == 0x401) { +#ifdef PSXCPU_LOG + PSXCPU_LOG("Interrupt: %x %x\n", psxHu32(0x1070), psxHu32(0x1074)); +#endif +// SysPrintf("Interrupt (%x): %x %x\n", psxRegs.cycle, psxHu32(0x1070), psxHu32(0x1074)); + psxException(0x400, 0); + } + } +} + +void psxJumpTest() { + if (!Config.HLE && Config.PsxOut) { + u32 call = psxRegs.GPR.n.t1 & 0xff; + switch (psxRegs.pc & 0x1fffff) { + case 0xa0: +#ifdef PSXBIOS_LOG + if (call != 0x28 && call != 0xe) { + PSXBIOS_LOG("Bios call a0: %s (%x) %x,%x,%x,%x\n", biosA0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); } +#endif + if (biosA0[call]) + biosA0[call](); + break; + case 0xb0: +#ifdef PSXBIOS_LOG + if (call != 0x17 && call != 0xb) { + PSXBIOS_LOG("Bios call b0: %s (%x) %x,%x,%x,%x\n", biosB0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); } +#endif + if (biosB0[call]) + biosB0[call](); + break; + case 0xc0: +#ifdef PSXBIOS_LOG + PSXBIOS_LOG("Bios call c0: %s (%x) %x,%x,%x,%x\n", biosC0n[call], call, psxRegs.GPR.n.a0, psxRegs.GPR.n.a1, psxRegs.GPR.n.a2, psxRegs.GPR.n.a3); +#endif + if (biosC0[call]) + biosC0[call](); + break; + } + } +} + +void psxExecuteBios() { + while (psxRegs.pc != 0x80030000) + psxCpu->ExecuteBlock(); +} + diff --git a/r3000a.h b/r3000a.h new file mode 100644 index 0000000..112ffb8 --- /dev/null +++ b/r3000a.h @@ -0,0 +1,223 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __R3000A_H__ +#define __R3000A_H__ + +#include "psxcommon.h" +#include "psxmem.h" +#include "psxcounters.h" +#include "psxbios.h" + +typedef struct { + int (*Init)(); + void (*Reset)(); + void (*Execute)(); /* executes up to a break */ + void (*ExecuteBlock)(); /* executes up to a jump */ + void (*Clear)(u32 Addr, u32 Size); + void (*Shutdown)(); +} R3000Acpu; + +extern R3000Acpu *psxCpu; +extern R3000Acpu psxInt; +extern R3000Acpu psxIntDbg; +#if defined(__x86_64__) || defined(__i386__) || defined(__sh__) || defined(__ppc__) || defined(HW_RVL) || defined(HW_DOL) +extern R3000Acpu psxRec; +#define PSXREC +#endif + +typedef union { + struct { + u32 r0, at, v0, v1, a0, a1, a2, a3, + t0, t1, t2, t3, t4, t5, t6, t7, + s0, s1, s2, s3, s4, s5, s6, s7, + t8, t9, k0, k1, gp, sp, s8, ra, lo, hi; + } n; + u32 r[34]; /* Lo, Hi in r[33] and r[34] */ +} psxGPRRegs; + +typedef union { + struct { + u32 Index, Random, EntryLo0, EntryLo1, + Context, PageMask, Wired, Reserved0, + BadVAddr, Count, EntryHi, Compare, + Status, Cause, EPC, PRid, + Config, LLAddr, WatchLO, WatchHI, + XContext, Reserved1, Reserved2, Reserved3, + Reserved4, Reserved5, ECC, CacheErr, + TagLo, TagHi, ErrorEPC, Reserved6; + } n; + u32 r[32]; +} psxCP0Regs; + +typedef struct { + short x, y; +} SVector2D; + +typedef struct { + short z, pad; +} SVector2Dz; + +typedef struct { + short x, y, z, pad; +} SVector3D; + +typedef struct { + short x, y, z, pad; +} LVector3D; + +typedef struct { + unsigned char r, g, b, c; +} CBGR; + +typedef struct { + short m11, m12, m13, m21, m22, m23, m31, m32, m33, pad; +} SMatrix3D; + +typedef union { + struct { + SVector3D v0, v1, v2; + CBGR rgb; + s32 otz; + s32 ir0, ir1, ir2, ir3; + SVector2D sxy0, sxy1, sxy2, sxyp; + SVector2Dz sz0, sz1, sz2, sz3; + CBGR rgb0, rgb1, rgb2; + s32 reserved; + s32 mac0, mac1, mac2, mac3; + u32 irgb, orgb; + s32 lzcs, lzcr; + } n; + u32 r[32]; +} psxCP2Data; + +typedef union { + struct { + SMatrix3D rMatrix; + s32 trX, trY, trZ; + SMatrix3D lMatrix; + s32 rbk, gbk, bbk; + SMatrix3D cMatrix; + s32 rfc, gfc, bfc; + s32 ofx, ofy; + s32 h; + s32 dqa, dqb; + s32 zsf3, zsf4; + s32 flag; + } n; + u32 r[32]; +} psxCP2Ctrl; + +typedef struct { + psxGPRRegs GPR; /* General Purpose Registers */ + psxCP0Regs CP0; /* Coprocessor0 Registers */ + psxCP2Data CP2D; /* Cop2 data registers */ + psxCP2Ctrl CP2C; /* Cop2 control registers */ + u32 pc; /* Program counter */ + u32 code; /* The instruction */ + u32 cycle; + u32 interrupt; + u32 intCycle[32]; +} psxRegisters; + +extern psxRegisters psxRegs; + +#if defined(HW_RVL) || defined(HW_DOL) || defined(BIG_ENDIAN) + +#define _i32(x) *(s32 *)&x +#define _u32(x) x + +#define _i16(x) (((short *)&x)[1]) +#define _u16(x) (((unsigned short *)&x)[1]) + +#define _i8(x) (((char *)&x)[3]) +#define _u8(x) (((unsigned char *)&x)[3]) + +#else + +#define _i32(x) *(s32 *)&x +#define _u32(x) x + +#define _i16(x) *(short *)&x +#define _u16(x) *(unsigned short *)&x + +#define _i8(x) *(char *)&x +#define _u8(x) *(unsigned char *)&x + +#endif + +/**** R3000A Instruction Macros ****/ +#define _PC_ psxRegs.pc // The next PC to be executed + +#define _fOp_(code) ((code >> 26) ) // The opcode part of the instruction register +#define _fFunct_(code) ((code ) & 0x3F) // The funct part of the instruction register +#define _fRd_(code) ((code >> 11) & 0x1F) // The rd part of the instruction register +#define _fRt_(code) ((code >> 16) & 0x1F) // The rt part of the instruction register +#define _fRs_(code) ((code >> 21) & 0x1F) // The rs part of the instruction register +#define _fSa_(code) ((code >> 6) & 0x1F) // The sa part of the instruction register +#define _fIm_(code) ((u16)code) // The immediate part of the instruction register +#define _fTarget_(code) (code & 0x03ffffff) // The target part of the instruction register + +#define _fImm_(code) ((s16)code) // sign-extended immediate +#define _fImmU_(code) (code&0xffff) // zero-extended immediate + +#define _Op_ _fOp_(psxRegs.code) +#define _Funct_ _fFunct_(psxRegs.code) +#define _Rd_ _fRd_(psxRegs.code) +#define _Rt_ _fRt_(psxRegs.code) +#define _Rs_ _fRs_(psxRegs.code) +#define _Sa_ _fSa_(psxRegs.code) +#define _Im_ _fIm_(psxRegs.code) +#define _Target_ _fTarget_(psxRegs.code) + +#define _Imm_ _fImm_(psxRegs.code) +#define _ImmU_ _fImmU_(psxRegs.code) + +#define _rRs_ psxRegs.GPR.r[_Rs_] // Rs register +#define _rRt_ psxRegs.GPR.r[_Rt_] // Rt register +#define _rRd_ psxRegs.GPR.r[_Rd_] // Rd register +#define _rSa_ psxRegs.GPR.r[_Sa_] // Sa register +#define _rFs_ psxRegs.CP0.r[_Rd_] // Fs register + +#define _c2dRs_ psxRegs.CP2D.r[_Rs_] // Rs cop2 data register +#define _c2dRt_ psxRegs.CP2D.r[_Rt_] // Rt cop2 data register +#define _c2dRd_ psxRegs.CP2D.r[_Rd_] // Rd cop2 data register +#define _c2dSa_ psxRegs.CP2D.r[_Sa_] // Sa cop2 data register + +#define _rHi_ psxRegs.GPR.n.hi // The HI register +#define _rLo_ psxRegs.GPR.n.lo // The LO register + +#define _JumpTarget_ ((_Target_ * 4) + (_PC_ & 0xf0000000)) // Calculates the target during a jump instruction +#define _BranchTarget_ ((s16)_Im_ * 4 + _PC_) // Calculates the target during a branch instruction + +#define _SetLink(x) psxRegs.GPR.r[x] = _PC_ + 4; // Sets the return address in the link register + +int psxInit(); +void psxReset(); +void psxShutdown(); +void psxException(u32 code, u32 bd); +void psxBranchTest(); +void psxExecuteBios(); +int psxTestLoadDelay(int reg, u32 tmp); +void psxDelayTest(int reg, u32 bpc); +void psxTestSWInts(); +void psxTestHWInts(); +void psxJumpTest(); + +#endif /* __R3000A_H__ */ diff --git a/sio.c b/sio.c new file mode 100644 index 0000000..8ec6fe0 --- /dev/null +++ b/sio.c @@ -0,0 +1,592 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* SIO functions. +*/ + +#include "sio.h" +#include "Gamecube/fileBrowser/fileBrowser.h" +#include "Gamecube/fileBrowser/fileBrowser-libfat.h" +#include + +// *** FOR WORKS ON PADS AND MEMORY CARDS ***** + +static unsigned char buf[256]; +unsigned char cardh[4] = { 0x00, 0x00, 0x5a, 0x5d }; + +//static unsigned short StatReg = 0x002b; +// Transfer Ready and the Buffer is Empty +unsigned short StatReg = TX_RDY | TX_EMPTY; +unsigned short ModeReg; +unsigned short CtrlReg; +unsigned short BaudReg; + +static unsigned int bufcount; +static unsigned int parp; +static unsigned int mcdst,rdwr; +static unsigned char adrH,adrL; +static unsigned int padst; + +char mcd1Written = 0; +char mcd2Written = 0; + +PadDataS pad; + +#ifdef HW_RVL +#include "Gamecube/MEM2.h" +char *Mcd1Data = (char*)MCD1_LO; +char *Mcd2Data = (char*)MCD2_LO; +#else +char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE]; +#endif + +// clk cycle byte +// 4us * 8bits = ((PSXCLK / 1000000) * 32) / BIAS; (linuzappz) +#define SIO_INT() { \ + if (!Config.Sio) { \ + psxRegs.interrupt|= 0x80; \ + psxRegs.intCycle[7+1] = 200; /*270;*/ \ + psxRegs.intCycle[7] = psxRegs.cycle; \ + } \ +} + +unsigned char sioRead8() { + unsigned char ret = 0; + + if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) { +// StatReg &= ~RX_OVERRUN; + ret = buf[parp]; + if (parp == bufcount) { + StatReg &= ~RX_RDY; // Receive is not Ready now + if (mcdst == 5) { + mcdst = 0; + if (rdwr == 2) { + switch (CtrlReg&0x2002) { + case 0x0002: + memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128); + mcd1Written = 1; + break; + case 0x2002: + memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128); + mcd2Written = 1; + break; + } + } + } + if (padst == 2) padst = 0; + if (mcdst == 1) { + mcdst = 2; + StatReg|= RX_RDY; + } + } + } + +#ifdef PAD_LOG + PAD_LOG("sio read8 ;ret = %x\n", ret); +#endif + return ret; +} + +void netError() { + ClosePlugins(); + SysMessage(_("Connection closed!\n")); + SysRunGui(); +} + +void sioWrite8(unsigned char value) { +#ifdef PAD_LOG + PAD_LOG("sio write8 %x\n", value); +#endif + switch (padst) { + case 1: SIO_INT(); + if ((value&0x40) == 0x40) { + padst = 2; parp = 1; + if (!Config.UseNet) { + switch (CtrlReg&0x2002) { + case 0x0002: + buf[parp] = PAD1_poll(value); + break; + case 0x2002: + buf[parp] = PAD2_poll(value); + break; + } + }/* else { +// SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]); + }*/ + + if (!(buf[parp] & 0x0f)) { + bufcount = 2 + 32; + } else { + bufcount = 2 + (buf[parp] & 0x0f) * 2; + } + if (buf[parp] == 0x41) { + switch (value) { + case 0x43: + buf[1] = 0x43; + break; + case 0x45: + buf[1] = 0xf3; + break; + } + } + } + else padst = 0; + return; + case 2: + parp++; +/* if (buf[1] == 0x45) { + buf[parp] = 0; + SIO_INT(); + return; + }*/ + if (!Config.UseNet) { + switch (CtrlReg&0x2002) { + case 0x0002: buf[parp] = PAD1_poll(value); break; + case 0x2002: buf[parp] = PAD2_poll(value); break; + } + } + + if (parp == bufcount) { padst = 0; return; } + SIO_INT(); + return; + } + + switch (mcdst) { + case 1: + SIO_INT(); + if (rdwr) { parp++; return; } + parp = 1; + switch (value) { + case 0x52: rdwr = 1; break; + case 0x57: rdwr = 2; break; + default: mcdst = 0; + } + return; + case 2: // address H + SIO_INT(); + adrH = value; + *buf = 0; + parp = 0; + bufcount = 1; + mcdst = 3; + return; + case 3: // address L + SIO_INT(); + adrL = value; + *buf = adrH; + parp = 0; + bufcount = 1; + mcdst = 4; + return; + case 4: + SIO_INT(); + parp = 0; + switch (rdwr) { + case 1: // read + buf[0] = 0x5c; + buf[1] = 0x5d; + buf[2] = adrH; + buf[3] = adrL; + switch (CtrlReg&0x2002) { + case 0x0002: + memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128); + mcd1Written = 1; + break; + case 0x2002: + memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128); + mcd2Written = 1; + break; + } + { + char xor = 0; + int i; + for (i=2;i<128+4;i++) + xor^=buf[i]; + buf[132] = xor; + } + buf[133] = 0x47; + bufcount = 133; + break; + case 2: // write + buf[0] = adrL; + buf[1] = value; + buf[129] = 0x5c; + buf[130] = 0x5d; + buf[131] = 0x47; + bufcount = 131; + break; + } + mcdst = 5; + return; + case 5: + parp++; + if (rdwr == 2) { + if (parp < 128) buf[parp+1] = value; + } + SIO_INT(); + return; + } + + switch (value) { + case 0x01: // start pad + StatReg |= RX_RDY; // Transfer is Ready + + if (!Config.UseNet) { + switch (CtrlReg&0x2002) { + case 0x0002: buf[0] = PAD1_startPoll(1); break; + case 0x2002: buf[0] = PAD2_startPoll(2); break; + } + } else { + if ((CtrlReg & 0x2002) == 0x0002) { + int i, j; + + PAD1_startPoll(1); + buf[0] = 0; + buf[1] = PAD1_poll(0x42); + if (!(buf[1] & 0x0f)) { + bufcount = 32; + } else { + bufcount = (buf[1] & 0x0f) * 2; + } + buf[2] = PAD1_poll(0); + i = 3; + j = bufcount; + while (j--) { + buf[i++] = PAD1_poll(0); + } + bufcount+= 3; + + if (NET_sendPadData(buf, bufcount) == -1) + netError(); + + if (NET_recvPadData(buf, 1) == -1) + netError(); + if (NET_recvPadData(buf+128, 2) == -1) + netError(); + } else { + memcpy(buf, buf+128, 32); + } + } + + bufcount = 2; + parp = 0; + padst = 1; + SIO_INT(); + return; + case 0x81: // start memcard + StatReg |= RX_RDY; + memcpy(buf, cardh, 4); + parp = 0; + bufcount = 3; + mcdst = 1; + rdwr = 0; + SIO_INT(); + return; + } +} + +void sioWriteCtrl16(unsigned short value) { + CtrlReg = value & ~RESET_ERR; + if (value & RESET_ERR) StatReg &= ~IRQ; + if ((CtrlReg & SIO_RESET) || (!CtrlReg)) { + padst = 0; mcdst = 0; parp = 0; + StatReg = TX_RDY | TX_EMPTY; + psxRegs.interrupt&=~0x80; + } +} + +void sioInterrupt() { +#ifdef PAD_LOG + PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status); +#endif +// SysPrintf("Sio Interrupt\n"); + StatReg|= IRQ; + psxHu32ref(0x1070)|= SWAPu32(0x80); + psxRegs.interrupt|= 0x80000000; +} + +//call me from menu, takes slot and save path as args +int LoadMcd(int mcd, fileBrowser_file *savepath) { + int temp = 0; + bool ret = 0; + char *data = NULL; + fileBrowser_file saveFile; + memcpy(&saveFile, savepath, sizeof(fileBrowser_file)); + memset(&saveFile.name[0],0,FILE_BROWSER_MAX_PATH_LEN); + + if(mcd == 1) { + sprintf((char*)saveFile.name,"%s/%s.mcd",savepath->name,CdromId); + data = &Mcd1Data[0]; + } + if (mcd == 2) { + sprintf((char*)saveFile.name,"%s/slot2.mcd",savepath->name); + data = &Mcd2Data[0]; + } + + if(saveFile_readFile(&saveFile, &temp, 4) == 4) { //file exists + saveFile.offset = 0; + if(saveFile_readFile(&saveFile, data, MCD_SIZE)==MCD_SIZE) + ret = 1; + } + else { + if(CreateMcd(mcd, &saveFile)) { //created ok + saveFile.offset = 0; + if(saveFile_readFile(&saveFile, data, MCD_SIZE)==MCD_SIZE) + ret = 1; + } + } + return ret; +} + +//we need to get rid of this joint function and start using the individual versions +int LoadMcds(fileBrowser_file *mcd1, fileBrowser_file *mcd2) { + if((LoadMcd(1, mcd1)) && (LoadMcd(2, mcd2))) + return 1; + return 0; +} + +//call me from menu, takes slot and save path as args +int SaveMcd(int mcd, fileBrowser_file *savepath) { + bool ret = 0; + char *data = NULL; + fileBrowser_file saveFile; + + memcpy(&saveFile, savepath, sizeof(fileBrowser_file)); + memset(&saveFile.name[0],0,FILE_BROWSER_MAX_PATH_LEN); + + if(mcd == 1) { + sprintf((char*)saveFile.name,"%s/%s.mcd",savepath->name,CdromId); + data = &Mcd1Data[0]; + } + if (mcd == 2) { + sprintf((char*)saveFile.name,"%s/slot2.mcd",savepath->name); + data = &Mcd2Data[0]; + } + + if(saveFile_writeFile(&saveFile, data, MCD_SIZE)==MCD_SIZE) + ret = 1; + + return ret; +} + +//we need to get rid of this joint function and start using the individual versions +int SaveMcds(fileBrowser_file *mcd1, fileBrowser_file *mcd2) { + if((SaveMcd(1, mcd1)) && (SaveMcd(2, mcd2))) + return 1; + return 0; +} + +bool CreateMcd(int slot, fileBrowser_file *mcd) { + char *cardData; + if (slot == 1) cardData = Mcd1Data; + else /*(slot == 2)*/ cardData = Mcd2Data; + + int i=0, j=0, curPos =0; + + // setup header + cardData[curPos++] = 'M'; + cardData[curPos++] = 'C'; + for(i=0; i<125; i++) + cardData[curPos++] = 0; + cardData[curPos++] = 0x0E; + + // 15 blocks + for(i=0;i<15;i++) { + cardData[curPos++] = 0xA0; + for(j=0;j<126;j++) { + cardData[curPos++] = 0; + } + cardData[curPos++] = 0xA0; + } + + //blank out the rest + for(i = curPos; i < MCD_SIZE; i++) + cardData[i] = 0; + if(saveFile_writeFile(mcd, cardData, MCD_SIZE)==MCD_SIZE) + return 1; + return 0; +} + +void ConvertMcd(char *mcd, char *data) { + /*FILE *f; + int i=0; + int s = MCD_SIZE; + + if (strstr(mcd, ".gme")) { + f = fopen(mcd, "wb"); + if (f != NULL) { + fwrite(data-3904, 1, MCD_SIZE+3904, f); + fclose(f); + } + f = fopen(mcd, "r+"); + s = s + 3904; + fputc('1', f); s--; + fputc('2', f); s--; + fputc('3', f); s--; + fputc('-', f); s--; + fputc('4', f); s--; + fputc('5', f); s--; + fputc('6', f); s--; + fputc('-', f); s--; + fputc('S', f); s--; + fputc('T', f); s--; + fputc('D', f); s--; + for(i=0;i<7;i++) { + fputc(0, f); s--; + } + fputc(1, f); s--; + fputc(0, f); s--; + fputc(1, f); s--; + fputc('M', f); s--; + fputc('Q', f); s--; + for(i=0;i<14;i++) { + fputc(0xa0, f); s--; + } + fputc(0, f); s--; + fputc(0xff, f); + while (s-- > (MCD_SIZE+1)) fputc(0, f); + fclose(f); + } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) { + f = fopen(mcd, "wb"); + if (f != NULL) { + fwrite(data-64, 1, MCD_SIZE+64, f); + fclose(f); + } + f = fopen(mcd, "r+"); + s = s + 64; + fputc('V', f); s--; + fputc('g', f); s--; + fputc('s', f); s--; + fputc('M', f); s--; + for(i=0;i<3;i++) { + fputc(1, f); s--; + fputc(0, f); s--; + fputc(0, f); s--; + fputc(0, f); s--; + } + fputc(0, f); s--; + fputc(2, f); + while (s-- > (MCD_SIZE+1)) fputc(0, f); + fclose(f); + } else { + f = fopen(mcd, "wb"); + if (f != NULL) { + fwrite(data, 1, MCD_SIZE, f); + fclose(f); + } + }*/ +} + +void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) { + char *data = NULL, *ptr, *str; + unsigned short clut[16]; + int i, x; + + memset(Info, 0, sizeof(McdBlock)); + + str = Info->Title; + + if (mcd == 1) data = Mcd1Data; + if (mcd == 2) data = Mcd2Data; + + ptr = data + block * 8192 + 2; + + Info->IconCount = *ptr & 0x3; + + ptr+= 2; + + i=0; + memcpy(Info->sTitle, ptr, 48*2); + + for (i=0; i < 48; i++) { + unsigned short c = *(ptr) << 8; + c|= *(ptr+1); + if (!c) break; + + if (c >= 0x8281 && c <= 0x8298) + c = (c - 0x8281) + 'a'; + else if (c >= 0x824F && c <= 0x827A) + c = (c - 0x824F) + '0'; + else if (c == 0x8144) c = '.'; + else if (c == 0x8146) c = ':'; + else if (c == 0x8168) c = '"'; + else if (c == 0x8169) c = '('; + else if (c == 0x816A) c = ')'; + else if (c == 0x816D) c = '['; + else if (c == 0x816E) c = ']'; + else if (c == 0x817C) c = '-'; + else { + c = ' '; + } + + str[i] = c; + ptr+=2; + } + str[i] = 0; + + ptr = data + block * 8192 + 0x60; // icon palete data + + for (i=0; i<16; i++) { + clut[i] = *((unsigned short*)ptr); + ptr+=2; + } + + for (i=0; iIconCount; i++) { + short *icon = &Info->Icon[i*16*16]; + + ptr = data + block * 8192 + 128 + 128 * i; // icon data + + for (x=0; x<16*16; x++) { + icon[x++] = clut[*ptr & 0xf]; + icon[x] = clut[*ptr >> 4]; + ptr++; + } + } + + ptr = data + block * 128; + + Info->Flags = *ptr; + + ptr+= 0xa; + strncpy(Info->ID, ptr, 12); + Info->ID[12] = 0; + ptr+= 12; + strncpy(Info->Name, ptr, 16); +} + +int sioFreeze(gzFile f, int Mode) { + char Unused[4096]; + + gzfreezel(buf); + gzfreezel(&StatReg); + gzfreezel(&ModeReg); + gzfreezel(&CtrlReg); + gzfreezel(&BaudReg); + gzfreezel(&bufcount); + gzfreezel(&parp); + gzfreezel(&mcdst); + gzfreezel(&rdwr); + gzfreezel(&adrH); + gzfreezel(&adrL); + gzfreezel(&padst); + gzfreezel(Unused); + + return 0; +} diff --git a/sio.h b/sio.h new file mode 100644 index 0000000..654aa12 --- /dev/null +++ b/sio.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + + +#ifndef _SIO_H_ +#define _SIO_H_ + +#include "psxcommon.h" +#include "r3000a.h" +#include "psxmem.h" +#include "plugins.h" +#include "psemu_plugin_defs.h" +#include "Gamecube/fileBrowser/fileBrowser.h" + +#define MCD_SIZE (1024 * 8 * 16) + +// Status Flags +#define TX_RDY 0x0001 +#define RX_RDY 0x0002 +#define TX_EMPTY 0x0004 +#define PARITY_ERR 0x0008 +#define RX_OVERRUN 0x0010 +#define FRAMING_ERR 0x0020 +#define SYNC_DETECT 0x0040 +#define DSR 0x0080 +#define CTS 0x0100 +#define IRQ 0x0200 + +// Control Flags +#define TX_PERM 0x0001 +#define DTR 0x0002 +#define RX_PERM 0x0004 +#define BREAK 0x0008 +#define RESET_ERR 0x0010 +#define RTS 0x0020 +#define SIO_RESET 0x0040 + +extern unsigned short StatReg; +extern unsigned short ModeReg; +extern unsigned short CtrlReg; +extern unsigned short BaudReg; + +#ifdef HW_RVL +#include "Gamecube/MEM2.h" +extern char *Mcd1Data; +extern char *Mcd2Data; +#else +extern char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE]; +#endif + +extern unsigned char sioRead8(); +extern void sioWrite8(unsigned char value); +extern void sioWriteCtrl16(unsigned short value); +extern void sioInterrupt(); +extern int sioFreeze(gzFile f, int Mode); + +extern int LoadMcd(int mcd, fileBrowser_file *savepath); +extern int LoadMcds(fileBrowser_file *mcd1, fileBrowser_file *mcd2); +extern int SaveMcd(int mcd, fileBrowser_file *savepath); +extern int SaveMcds(fileBrowser_file *mcd1, fileBrowser_file *mcd2); +extern bool CreateMcd(int slot, fileBrowser_file *mcd); +extern void ConvertMcd(char *mcd, char *data); + +typedef struct { + char Title[48]; + short sTitle[48]; + char ID[14]; + char Name[16]; + int IconCount; + short Icon[16*16*3]; + unsigned char Flags; +} McdBlock; + +extern void GetMcdBlockInfo(int mcd, int block, McdBlock *info); + +#endif diff --git a/spu.c b/spu.c new file mode 100644 index 0000000..aa5ee1f --- /dev/null +++ b/spu.c @@ -0,0 +1,29 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +/* +* Sound (SPU) functions. +*/ + +#include "spu.h" + +void CALLBACK SPUirq(void) { + psxHu32ref(0x1070)|= SWAPu32(0x200); + psxRegs.interrupt|= 0x80000000; +} diff --git a/spu.h b/spu.h new file mode 100644 index 0000000..1b41f57 --- /dev/null +++ b/spu.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __SPU_H__ +#define __SPU_H__ + +#include "psxcommon.h" +#include "plugins.h" +#include "r3000a.h" +#include "psxmem.h" + +#define CALLBACK + +#define H_SPUirqAddr 0x0da4 +#define H_SPUaddr 0x0da6 +#define H_SPUdata 0x0da8 +#define H_SPUctrl 0x0daa +#define H_SPUstat 0x0dae +#define H_SPUon1 0x0d88 +#define H_SPUon2 0x0d8a +#define H_SPUoff1 0x0d8c +#define H_SPUoff2 0x0d8e + +void CALLBACK SPUirq(void); + +#endif /* __SPU_H__ */ diff --git a/system.h b/system.h new file mode 100644 index 0000000..830630e --- /dev/null +++ b/system.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ + +int SysInit(); // Init mem and plugins +void SysReset(); // Resets mem +void SysPrintf(char *fmt, ...); // Printf used by bios syscalls +void SysMessage(char *fmt, ...); // Message used to print msg to users +void *SysLoadLibrary(char *lib); // Loads Library +void *SysLoadSym(void *lib, char *sym); // Loads Symbol from Library +const char *SysLibError(); // Gets previous error loading sysbols +void SysCloseLibrary(void *lib); // Closes Library +void SysUpdate(); // Called on VBlank (to update i.e. pads) +void SysRunGui(); // Returns to the Gui +void SysClose(); // Close mem and plugins + +#endif /* __SYSTEM_H__ */