diff --git a/hidtopad.cbp b/hidtopad.cbp new file mode 100644 index 0000000..e317104 --- /dev/null +++ b/hidtopad.cbp @@ -0,0 +1,29 @@ + + + + + + diff --git a/src/common/common.h b/src/common/common.h new file mode 100644 index 0000000..04326ac --- /dev/null +++ b/src/common/common.h @@ -0,0 +1,71 @@ +#ifndef COMMON_H +#define COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "os_defs.h" + +#define CAFE_OS_SD_PATH "/vol/external01" +#define SD_PATH "sd:" +#define WIIU_PATH "/wiiu" + +/* Macros for libs */ +#define LIB_CORE_INIT 0 +#define LIB_NSYSNET 1 +#define LIB_GX2 2 +#define LIB_AOC 3 +#define LIB_AX 4 +#define LIB_FS 5 +#define LIB_OS 6 +#define LIB_PADSCORE 7 +#define LIB_SOCKET 8 +#define LIB_SYS 9 +#define LIB_VPAD 10 +#define LIB_NN_ACP 11 +#define LIB_SYSHID 12 +#define LIB_VPADBASE 13 + +// functions types +#define STATIC_FUNCTION 0 +#define DYNAMIC_FUNCTION 1 + +// none dynamic libs +#define LIB_LOADER 0x1001 + +#ifndef MEM_BASE +#define MEM_BASE (0x00800000) +#endif + +#define ELF_DATA_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x00)) +#define ELF_DATA_SIZE (*(volatile unsigned int*)(MEM_BASE + 0x1300 + 0x04)) +#define MAIN_ENTRY_ADDR (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x00)) +#define OS_FIRMWARE (*(volatile unsigned int*)(MEM_BASE + 0x1400 + 0x04)) + +#define OS_SPECIFICS ((OsSpecifics*)(MEM_BASE + 0x1500)) + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif +#define EXIT_HBL_EXIT 0xFFFFFFFE +#define EXIT_RELAUNCH_ON_LOAD 0xFFFFFFFD + +#define RESTORE_INSTR_MAGIC 0xC001C0DE +#define RESTORE_INSTR_ADDR ((restore_instructions_t*)(MEM_BASE + 0x1600)) + +typedef struct _restore_instructions_t { + unsigned int magic; + unsigned int instr_count; + struct { + unsigned int addr; + unsigned int instr; + } data[0]; +} restore_instructions_t; + +#ifdef __cplusplus +} +#endif + +#endif /* COMMON_H */ + diff --git a/src/common/fs_defs.h b/src/common/fs_defs.h new file mode 100644 index 0000000..c41e77e --- /dev/null +++ b/src/common/fs_defs.h @@ -0,0 +1,67 @@ +#ifndef FS_DEFS_H +#define FS_DEFS_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* FS defines and types */ +#define FS_MAX_LOCALPATH_SIZE 511 +#define FS_MAX_MOUNTPATH_SIZE 128 +#define FS_MAX_FULLPATH_SIZE (FS_MAX_LOCALPATH_SIZE + FS_MAX_MOUNTPATH_SIZE) +#define FS_MAX_ARGPATH_SIZE FS_MAX_FULLPATH_SIZE + +#define FS_STATUS_OK 0 +#define FS_RET_UNSUPPORTED_CMD 0x0400 +#define FS_RET_NO_ERROR 0x0000 +#define FS_RET_ALL_ERROR (unsigned int)(-1) + +#define FS_STAT_FLAG_IS_DIRECTORY 0x80000000 + +/* max length of file/dir name */ +#define FS_MAX_ENTNAME_SIZE 256 + +#define FS_SOURCETYPE_EXTERNAL 0 +#define FS_SOURCETYPE_HFIO 1 +#define FS_SOURCETYPE_HFIO 1 + +#define FS_STATUS_OK 0 +#define FS_STATUS_EXISTS -5 +#define FS_STATUS_STORAGE_FULL -12 +#define FS_STATUS_JOURNAL_FULL -13 + +#define FS_MOUNT_SOURCE_SIZE 0x300 +#define FS_CLIENT_SIZE 0x1700 +#define FS_CMD_BLOCK_SIZE 0xA80 + +typedef struct +{ + uint32_t flag; + uint32_t permission; + uint32_t owner_id; + uint32_t group_id; + uint32_t size; + uint32_t alloc_size; + uint64_t quota_size; + uint32_t ent_id; + uint64_t ctime; + uint64_t mtime; + uint8_t attributes[48]; +} __attribute__((packed)) FSStat; + +typedef struct +{ + FSStat stat; + char name[FS_MAX_ENTNAME_SIZE]; +} FSDirEntry; + + +#ifdef __cplusplus +} +#endif + +#endif /* FS_DEFS_H */ + diff --git a/src/common/kernel_defs.h b/src/common/kernel_defs.h new file mode 100644 index 0000000..564b2df --- /dev/null +++ b/src/common/kernel_defs.h @@ -0,0 +1,135 @@ +#ifndef __KERNEL_DEFS_H_ +#define __KERNEL_DEFS_H_ + +#include "types.h" +#include "fs_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// original structure in the kernel that is originally 0x1270 long +typedef struct +{ + uint32_t version_cos_xml; // version tag from cos.xml + uint64_t os_version; // os_version from app.xml + uint64_t title_id; // title_id tag from app.xml + uint32_t app_type; // app_type tag from app.xml + uint32_t cmdFlags; // unknown tag as it is always 0 (might be cmdFlags from cos.xml but i am not sure) + char rpx_name[0x1000]; // rpx name from cos.xml + uint32_t unknown2; // 0x050B8304 in mii maker and system menu (looks a bit like permissions complex that got masked!?) + uint32_t unknown3[63]; // those were all zeros, but its probably connected with unknown2 + uint32_t max_size; // max_size in cos.xml which defines the maximum amount of memory reserved for the app + uint32_t avail_size; // avail_size or codegen_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_size; // codegen_size or avail_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_core; // codegen_core in cos.xml (seems to mostly be 1?) + uint32_t max_codesize; // max_codesize in cos.xml + uint32_t overlay_arena; // overlay_arena in cos.xml + uint32_t unknown4[59]; // all zeros it seems + uint32_t default_stack0_size; // not sure because always 0 but very likely + uint32_t default_stack1_size; // not sure because always 0 but very likely + uint32_t default_stack2_size; // not sure because always 0 but very likely + uint32_t default_redzone0_size; // not sure because always 0 but very likely + uint32_t default_redzone1_size; // not sure because always 0 but very likely + uint32_t default_redzone2_size; // not sure because always 0 but very likely + uint32_t exception_stack0_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack1_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack2_size; // from cos.xml, 0x1000 on mii maker + uint32_t sdk_version; // from app.xml, 20909 (0x51AD) on mii maker + uint32_t title_version; // from app.xml, 0x32 on mii maker + /* + // --------------------------------------------------------------------------------------------------------------------------------------------- + // the next part might be changing from title to title?! I don't think its important but nice to know maybe.... + // --------------------------------------------------------------------------------------------------------------------------------------------- + char mlc[4]; // string "mlc" on mii maker and sysmenu + uint32_t unknown5[7]; // all zeros on mii maker and sysmenu + uint32_t unknown6_one; // 0x01 on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char ACP[4]; // string "ACP" on mii maker and sysmenu + uint32_t unknown7[15]; // all zeros on mii maker and sysmenu + uint32_t unknown8_5; // 0x05 on mii maker and sysmenu + uint32_t unknown9_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown10_ptr; // 0xFF23DD0C pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char UVD[4]; // string "UVD" on mii maker and sysmenu + uint32_t unknown11[15]; // all zeros on mii maker and sysmenu + uint32_t unknown12_5; // 0x05 on mii maker and sysmenu + uint32_t unknown13_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown14_ptr; // 0xFF23EFC8 pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + char SND[4]; // string "SND" on mii maker and sysmenu + uint32_t unknown15[15]; // all zeros on mii maker and sysmenu + uint32_t unknown16_5; // 0x05 on mii maker and sysmenu + uint32_t unknown17_zero; // 0x00 on mii maker and sysmenu + uint32_t unknown18_ptr; // 0xFF23F014 pointer on mii maker and sysmenu + // --------------------------------------------------------------------------------------------------------------------------------------------- + uint32_t unknown19; // 0x02 on miimaker, 0x0F on system menu + */ + // after that only zeros follow +} __attribute__((packed)) CosAppXmlInfo; + + +// original structure in the kernel that is originally 0x1270 long +typedef struct +{ + uint64_t title_id; // title_id tag from app.xml + uint64_t unknown1; + uint64_t osversion; + uint64_t unknown2; + uint64_t common_save_size; + uint64_t account_save_size; + uint64_t unknown4; + uint64_t unknown5; + uint64_t unknown6; // companycode? + uint64_t unknown7; + char unknown8[6]; + char product_code[22]; + char unknown9[44]; + char content_platform[3]; +} __attribute__((packed)) MetaXmlInfo; + +// Our own cos/app.xml struct which uses only uses as much memory as really needed, since many things are just zeros in the above structure +// This structure is only 0x64 bytes long + RPX name length (dynamic up to 0x1000 theoretically) +typedef struct +{ + uint32_t version_cos_xml; // version tag from cos.xml + uint64_t os_version; // os_version from app.xml + uint64_t title_id; // title_id tag from app.xml + uint32_t app_type; // app_type tag from app.xml + uint32_t cmdFlags; // unknown tag as it is always 0 (might be cmdFlags from cos.xml but i am not sure) + uint32_t max_size; // max_size in cos.xml which defines the maximum amount of memory reserved for the app + uint32_t avail_size; // avail_size or codegen_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_size; // codegen_size or avail_size in cos.xml (seems to mostly be 0?) + uint32_t codegen_core; // codegen_core in cos.xml (seems to mostly be 1?) + uint32_t max_codesize; // max_codesize in cos.xml + uint32_t overlay_arena; // overlay_arena in cos.xml + uint32_t default_stack0_size; // not sure because always 0 but very likely + uint32_t default_stack1_size; // not sure because always 0 but very likely + uint32_t default_stack2_size; // not sure because always 0 but very likely + uint32_t default_redzone0_size; // not sure because always 0 but very likely + uint32_t default_redzone1_size; // not sure because always 0 but very likely + uint32_t default_redzone2_size; // not sure because always 0 but very likely + uint32_t exception_stack0_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack1_size; // from cos.xml, 0x1000 on mii maker + uint32_t exception_stack2_size; // from cos.xml, 0x1000 on mii maker + uint32_t sdk_version; // from app.xml, 20909 (0x51AD) on mii maker + uint32_t title_version; // from app.xml, 0x32 on mii maker + char rpx_name[FS_MAX_ENTNAME_SIZE]; // rpx name from cos.xml, length 256 as it can't get bigger from FS anyway +} __attribute__((packed)) ReducedCosAppXmlInfo; + +typedef struct _bat_t +{ + u32 h; + u32 l; +} bat_t; + +typedef struct _bat_table_t +{ + bat_t bat[8]; +} bat_table_t; + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_DEFS_H_ diff --git a/src/common/loader_defs.h b/src/common/loader_defs.h new file mode 100644 index 0000000..97c237c --- /dev/null +++ b/src/common/loader_defs.h @@ -0,0 +1,40 @@ +#ifndef __LOADER_DEFS_H_ +#define __LOADER_DEFS_H_ + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// struct holding the globals of the loader (there are actually more but we don't need others) +typedef struct _loader_globals_t +{ + int sgIsLoadingBuffer; + int sgFileType; + int sgProcId; + int sgGotBytes; + int sgFileOffset; + int sgBufferNumber; + int sgBounceError; + char sgLoadName[0x1000]; +} __attribute__((packed)) loader_globals_t; + +typedef struct _loader_globals_550_t +{ + int sgFinishedLoadingBuffer; + int sgFileType; + int sgProcId; + int sgGotBytes; + int sgTotalBytes; + int sgFileOffset; + int sgBufferNumber; + int sgBounceError; + char sgLoadName[0x1000]; +} __attribute__((packed)) loader_globals_550_t; + +#ifdef __cplusplus +} +#endif + +#endif // __LOADER_DEFS_H_ diff --git a/src/common/os_defs.h b/src/common/os_defs.h new file mode 100644 index 0000000..48a4c8f --- /dev/null +++ b/src/common/os_defs.h @@ -0,0 +1,25 @@ +#ifndef __OS_DEFS_H_ +#define __OS_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _OsSpecifics +{ + unsigned int addr_OSDynLoad_Acquire; + unsigned int addr_OSDynLoad_FindExport; + unsigned int addr_OSTitle_main_entry; + + unsigned int addr_KernSyscallTbl1; + unsigned int addr_KernSyscallTbl2; + unsigned int addr_KernSyscallTbl3; + unsigned int addr_KernSyscallTbl4; + unsigned int addr_KernSyscallTbl5; +} OsSpecifics; + +#ifdef __cplusplus +} +#endif + +#endif // __OS_DEFS_H_ diff --git a/src/common/types.h b/src/common/types.h new file mode 100644 index 0000000..3435e56 --- /dev/null +++ b/src/common/types.h @@ -0,0 +1,7 @@ +#ifndef TYPES_H +#define TYPES_H + +#include + +#endif /* TYPES_H */ + diff --git a/src/controller_patcher b/src/controller_patcher new file mode 160000 index 0000000..c1a02aa --- /dev/null +++ b/src/controller_patcher @@ -0,0 +1 @@ +Subproject commit c1a02aa7c7a3a9031f9170ac284e15c9dd8df603 diff --git a/src/dynamic_libs b/src/dynamic_libs new file mode 160000 index 0000000..1fcfb43 --- /dev/null +++ b/src/dynamic_libs @@ -0,0 +1 @@ +Subproject commit 1fcfb43f395c248aa45bb909012fbecbbbb2df2a diff --git a/src/entry.c b/src/entry.c new file mode 100644 index 0000000..759cee0 --- /dev/null +++ b/src/entry.c @@ -0,0 +1,14 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "common/common.h" +#include "utils/utils.h" +#include "main.h" + +int __entry_menu(int argc, char **argv) +{ + //! ******************************************************************* + //! * Jump to our application * + //! ******************************************************************* + return Menu_Main(); +} diff --git a/src/fs/fs_utils.c b/src/fs/fs_utils.c new file mode 100644 index 0000000..efa2e55 --- /dev/null +++ b/src/fs/fs_utils.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include "common/fs_defs.h" +#include "dynamic_libs/fs_functions.h" + + +int MountFS(void *pClient, void *pCmd, char **mount_path) +{ + int result = -1; + + void *mountSrc = malloc(FS_MOUNT_SOURCE_SIZE); + if(!mountSrc) + return -3; + + char* mountPath = (char*) malloc(FS_MAX_MOUNTPATH_SIZE); + if(!mountPath) { + free(mountSrc); + return -4; + } + + memset(mountSrc, 0, FS_MOUNT_SOURCE_SIZE); + memset(mountPath, 0, FS_MAX_MOUNTPATH_SIZE); + + // Mount sdcard + if (FSGetMountSource(pClient, pCmd, FS_SOURCETYPE_EXTERNAL, mountSrc, -1) == 0) + { + result = FSMount(pClient, pCmd, mountSrc, mountPath, FS_MAX_MOUNTPATH_SIZE, -1); + if((result == 0) && mount_path) { + *mount_path = (char*)malloc(strlen(mountPath) + 1); + if(*mount_path) + strcpy(*mount_path, mountPath); + } + } + + free(mountPath); + free(mountSrc); + return result; +} + +int UmountFS(void *pClient, void *pCmd, const char *mountPath) +{ + int result = -1; + result = FSUnmount(pClient, pCmd, mountPath, -1); + + return result; +} + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size) +{ + //! always initialze input + *inbuffer = NULL; + if(size) + *size = 0; + + int iFd = open(filepath, O_RDONLY); + if (iFd < 0) + return -1; + + u32 filesize = lseek(iFd, 0, SEEK_END); + lseek(iFd, 0, SEEK_SET); + + u8 *buffer = (u8 *) malloc(filesize); + if (buffer == NULL) + { + close(iFd); + return -2; + } + + u32 blocksize = 0x4000; + u32 done = 0; + int readBytes = 0; + + while(done < filesize) + { + if(done + blocksize > filesize) { + blocksize = filesize - done; + } + readBytes = read(iFd, buffer + done, blocksize); + if(readBytes <= 0) + break; + done += readBytes; + } + + close(iFd); + + if (done != filesize) + { + free(buffer); + return -3; + } + + *inbuffer = buffer; + + //! sign is optional input + if(size) + *size = filesize; + + return filesize; +} + +int CheckFile(const char * filepath) +{ + if(!filepath) + return 0; + + struct stat filestat; + + char dirnoslash[strlen(filepath)+2]; + snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath); + + while(dirnoslash[strlen(dirnoslash)-1] == '/') + dirnoslash[strlen(dirnoslash)-1] = '\0'; + + char * notRoot = strrchr(dirnoslash, '/'); + if(!notRoot) + { + strcat(dirnoslash, "/"); + } + + if (stat(dirnoslash, &filestat) == 0) + return 1; + + return 0; +} + +int CreateSubfolder(const char * fullpath) +{ + if(!fullpath) + return 0; + + int result = 0; + + char dirnoslash[strlen(fullpath)+1]; + strcpy(dirnoslash, fullpath); + + int pos = strlen(dirnoslash)-1; + while(dirnoslash[pos] == '/') + { + dirnoslash[pos] = '\0'; + pos--; + } + + if(CheckFile(dirnoslash)) + { + return 1; + } + else + { + char parentpath[strlen(dirnoslash)+2]; + strcpy(parentpath, dirnoslash); + char * ptr = strrchr(parentpath, '/'); + + if(!ptr) + { + //!Device root directory (must be with '/') + strcat(parentpath, "/"); + struct stat filestat; + if (stat(parentpath, &filestat) == 0) + return 1; + + return 0; + } + + ptr++; + ptr[0] = '\0'; + + result = CreateSubfolder(parentpath); + } + + if(!result) + return 0; + + if (mkdir(dirnoslash, 0777) == -1) + { + return 0; + } + + return 1; +} diff --git a/src/fs/fs_utils.h b/src/fs/fs_utils.h new file mode 100644 index 0000000..7022695 --- /dev/null +++ b/src/fs/fs_utils.h @@ -0,0 +1,23 @@ +#ifndef __FS_UTILS_H_ +#define __FS_UTILS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +int MountFS(void *pClient, void *pCmd, char **mount_path); +int UmountFS(void *pClient, void *pCmd, const char *mountPath); + +int LoadFileToMem(const char *filepath, u8 **inbuffer, u32 *size); + +//! todo: C++ class +int CreateSubfolder(const char * fullpath); +int CheckFile(const char * filepath); + +#ifdef __cplusplus +} +#endif + +#endif // __FS_UTILS_H_ diff --git a/src/fs/sd_fat_devoptab.c b/src/fs/sd_fat_devoptab.c new file mode 100644 index 0000000..f5b278b --- /dev/null +++ b/src/fs/sd_fat_devoptab.c @@ -0,0 +1,1019 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/os_functions.h" +#include "fs_utils.h" + +#define FS_ALIGNMENT 0x40 +#define FS_ALIGN(x) (((x) + FS_ALIGNMENT - 1) & ~(FS_ALIGNMENT - 1)) + +typedef struct _sd_fat_private_t { + char *mount_path; + void *pClient; + void *pCmd; + void *pMutex; +} sd_fat_private_t; + +typedef struct _sd_fat_file_state_t { + sd_fat_private_t *dev; + int fd; /* File descriptor */ + int flags; /* Opening flags */ + bool read; /* True if allowed to read from file */ + bool write; /* True if allowed to write to file */ + bool append; /* True if allowed to append to file */ + u64 pos; /* Current position within the file (in bytes) */ + u64 len; /* Total length of the file (in bytes) */ + struct _sd_fat_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ + struct _sd_fat_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ +} sd_fat_file_state_t; + +typedef struct _sd_fat_dir_entry_t { + sd_fat_private_t *dev; + int dirHandle; +} sd_fat_dir_entry_t; + +static sd_fat_private_t *sd_fat_get_device_data(const char *path) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Search the devoptab table for the specified device name + // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + return (sd_fat_private_t *)devoptab->deviceData; + } + } + } + + return NULL; +} + +static char *sd_fat_real_path (const char *path, sd_fat_private_t *dev) +{ + // Sanity check + if (!path) + return NULL; + + // Move the path pointer to the start of the actual path + if (strchr(path, ':') != NULL) { + path = strchr(path, ':') + 1; + } + + int mount_len = strlen(dev->mount_path); + + char *new_name = (char*)malloc(mount_len + strlen(path) + 1); + if(new_name) { + strcpy(new_name, dev->mount_path); + strcpy(new_name + mount_len, path); + return new_name; + } + return new_name; +} + +static int sd_fat_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fileStruct; + + file->dev = dev; + // Determine which mode the file is opened for + file->flags = flags; + + const char *mode_str; + + if ((flags & 0x03) == O_RDONLY) { + file->read = true; + file->write = false; + file->append = false; + mode_str = "r"; + } else if ((flags & 0x03) == O_WRONLY) { + file->read = false; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a" : "w"; + } else if ((flags & 0x03) == O_RDWR) { + file->read = true; + file->write = true; + file->append = (flags & O_APPEND); + mode_str = file->append ? "a+" : "r+"; + } else { + r->_errno = EACCES; + return -1; + } + + int fd = -1; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSOpenFile(dev->pClient, dev->pCmd, real_path, mode_str, &fd, -1); + + free(real_path); + + if(result == 0) + { + FSStat stats; + result = FSGetStatFile(dev->pClient, dev->pCmd, fd, &stats, -1); + if(result != 0) { + FSCloseFile(dev->pClient, dev->pCmd, fd, -1); + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + file->fd = fd; + file->pos = 0; + file->len = stats.size; + OSUnlockMutex(dev->pMutex); + return (int)file; + } + + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; +} + + +static int sd_fat_close_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSCloseFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static off_t sd_fat_seek_r (struct _reent *r, int fd, off_t pos, int dir) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + switch(dir) + { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->len + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + + int result = FSSetPosFile(file->dev->pClient, file->dev->pCmd, file->fd, file->pos, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result == 0) + { + return file->pos; + } + + return result; +} + +static ssize_t sd_fat_write_r (struct _reent *r, int fd, const char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->write) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + memcpy(tmpBuf, ptr + done, write_size); + + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + break; + } + else if(result == 0) + { + if(write_size > 0) + done = 0; + break; + } + else + { + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + +static ssize_t sd_fat_read_r (struct _reent *r, int fd, char *ptr, size_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->read) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + size_t done = 0; + + while(done < len) + { + size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + done = 0; + break; + } + else if(result == 0) + { + //! TODO: error on read_size > 0 + break; + } + else + { + memcpy(ptr + done, tmpBuf, read_size); + done += result; + file->pos += result; + } + } + + free(tmpBuf); + OSUnlockMutex(file->dev->pMutex); + return done; +} + + +static int sd_fat_fstat_r (struct _reent *r, int fd, struct stat *st) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + FSStat stats; + int result = FSGetStatFile(file->dev->pClient, file->dev->pCmd, file->fd, &stats, -1); + if(result != 0) { + r->_errno = result; + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + st->st_mode = S_IFREG; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + st->st_nlink = 1; + + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int sd_fat_ftruncate_r (struct _reent *r, int fd, off_t len) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSTruncateFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_fsync_r (struct _reent *r, int fd) +{ + sd_fat_file_state_t *file = (sd_fat_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = FSFlushFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_stat_r (struct _reent *r, const char *path, struct stat *st) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + FSStat stats; + + int result = FSGetStat(dev->pClient, dev->pCmd, real_path, &stats, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // mark root also as directory + st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + // Fill in the generic entry stats + st->st_dev = stats.ent_id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.ent_id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static int sd_fat_link_r (struct _reent *r, const char *existing, const char *newLink) +{ + r->_errno = ENOTSUP; + return -1; +} + +static int sd_fat_unlink_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + + int result = FSRemove(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_chdir_r (struct _reent *r, const char *name) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSChangeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_rename_r (struct _reent *r, const char *oldName, const char *newName) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(oldName); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_oldpath = sd_fat_real_path(oldName, dev); + if(!real_oldpath) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + char *real_newpath = sd_fat_real_path(newName, dev); + if(!real_newpath) { + r->_errno = ENOMEM; + free(real_oldpath); + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSRename(dev->pClient, dev->pCmd, real_oldpath, real_newpath, -1); + + free(real_oldpath); + free(real_newpath); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; + +} + +static int sd_fat_mkdir_r (struct _reent *r, const char *path, int mode) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = FSMakeDir(dev->pClient, dev->pCmd, real_path, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int sd_fat_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(buf, 0, sizeof(struct statvfs)); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + u64 size; + + int result = FSGetFreeSpaceSize(dev->pClient, dev->pCmd, real_path, &size, -1); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // File system block size + buf->f_bsize = 512; + + // Fundamental file system block size + buf->f_frsize = 512; + + // Total number of blocks on file system in units of f_frsize + buf->f_blocks = size >> 9; // this is unknown + + // Free blocks available for all and for non-privileged processes + buf->f_bfree = buf->f_bavail = size >> 9; + + // Number of inodes at this point in time + buf->f_files = 0xffffffff; + + // Free inodes available for all and for non-privileged processes + buf->f_ffree = 0xffffffff; + + // File system id + buf->f_fsid = (int)dev; + + // Bit mask of f_flag values. + buf->f_flag = 0; + + // Maximum length of filenames + buf->f_namemax = 255; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static DIR_ITER *sd_fat_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) +{ + sd_fat_private_t *dev = sd_fat_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return NULL; + } + + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + + OSLockMutex(dev->pMutex); + + char *real_path = sd_fat_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return NULL; + } + + int dirHandle; + + int result = FSOpenDir(dev->pClient, dev->pCmd, real_path, &dirHandle, -1); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return NULL; + } + + dirIter->dev = dev; + dirIter->dirHandle = dirHandle; + + return dirState; +} + +static int sd_fat_dirclose_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSCloseDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirreset_r (struct _reent *r, DIR_ITER *dirState) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = FSRewindDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, -1); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int sd_fat_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) +{ + sd_fat_dir_entry_t *dirIter = (sd_fat_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + FSDirEntry * dir_entry = malloc(sizeof(FSDirEntry)); + + int result = FSReadDir(dirIter->dev->pClient, dirIter->dev->pCmd, dirIter->dirHandle, dir_entry, -1); + if(result < 0) + { + free(dir_entry); + r->_errno = result; + OSUnlockMutex(dirIter->dev->pMutex); + return -1; + } + + // Fetch the current entry + strcpy(filename, dir_entry->name); + + if(st) + { + memset(st, 0, sizeof(struct stat)); + st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = dir_entry->stat.size; + st->st_blocks = (dir_entry->stat.size + 511) >> 9; + st->st_dev = dir_entry->stat.ent_id; + st->st_uid = dir_entry->stat.owner_id; + st->st_gid = dir_entry->stat.group_id; + st->st_ino = dir_entry->stat.ent_id; + st->st_atime = dir_entry->stat.mtime; + st->st_ctime = dir_entry->stat.ctime; + st->st_mtime = dir_entry->stat.mtime; + } + + free(dir_entry); + OSUnlockMutex(dirIter->dev->pMutex); + return 0; +} + +// NTFS device driver devoptab +static const devoptab_t devops_sd_fat = { + NULL, /* Device name */ + sizeof (sd_fat_file_state_t), + sd_fat_open_r, + sd_fat_close_r, + sd_fat_write_r, + sd_fat_read_r, + sd_fat_seek_r, + sd_fat_fstat_r, + sd_fat_stat_r, + sd_fat_link_r, + sd_fat_unlink_r, + sd_fat_chdir_r, + sd_fat_rename_r, + sd_fat_mkdir_r, + sizeof (sd_fat_dir_entry_t), + sd_fat_diropen_r, + sd_fat_dirreset_r, + sd_fat_dirnext_r, + sd_fat_dirclose_r, + sd_fat_statvfs_r, + sd_fat_ftruncate_r, + sd_fat_fsync_r, + NULL, /* sd_fat_chmod_r */ + NULL, /* sd_fat_fchmod_r */ + NULL /* Device data */ +}; + +static int sd_fat_add_device (const char *name, const char *mount_path, void *pClient, void *pCmd) +{ + devoptab_t *dev = NULL; + char *devname = NULL; + char *devpath = NULL; + int i; + + // Sanity check + if (!name) { + errno = EINVAL; + return -1; + } + + // Allocate a devoptab for this device + dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); + if (!dev) { + errno = ENOMEM; + return -1; + } + + // Use the space allocated at the end of the devoptab for storing the device name + devname = (char*)(dev + 1); + strcpy(devname, name); + + // create private data + sd_fat_private_t *priv = (sd_fat_private_t *)malloc(sizeof(sd_fat_private_t) + strlen(mount_path) + 1); + if(!priv) { + free(dev); + errno = ENOMEM; + return -1; + } + + devpath = (char*)(priv+1); + strcpy(devpath, mount_path); + + // setup private data + priv->mount_path = devpath; + priv->pClient = pClient; + priv->pCmd = pCmd; + priv->pMutex = malloc(OS_MUTEX_SIZE); + + if(!priv->pMutex) { + free(dev); + free(priv); + errno = ENOMEM; + return -1; + } + + OSInitMutex(priv->pMutex); + + // Setup the devoptab + memcpy(dev, &devops_sd_fat, sizeof(devoptab_t)); + dev->name = devname; + dev->deviceData = priv; + + // Add the device to the devoptab table (if there is a free slot) + for (i = 3; i < STD_MAX; i++) { + if (devoptab_list[i] == devoptab_list[0]) { + devoptab_list[i] = dev; + return 0; + } + } + + // failure, free all memory + free(priv); + free(dev); + + // If we reach here then there are no free slots in the devoptab table for this device + errno = EADDRNOTAVAIL; + return -1; +} + +static int sd_fat_remove_device (const char *path, void **pClient, void **pCmd, char **mountPath) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Find and remove the specified device from the devoptab table + // NOTE: We do this manually due to a 'bug' in RemoveDevice + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + devoptab_list[i] = devoptab_list[0]; + + if(devoptab->deviceData) + { + sd_fat_private_t *priv = (sd_fat_private_t *)devoptab->deviceData; + *pClient = priv->pClient; + *pCmd = priv->pCmd; + *mountPath = (char*) malloc(strlen(priv->mount_path)+1); + if(*mountPath) + strcpy(*mountPath, priv->mount_path); + if(priv->pMutex) + free(priv->pMutex); + free(devoptab->deviceData); + } + + free((devoptab_t*)devoptab); + return 0; + } + } + } + + return -1; +} + +int mount_sd_fat(const char *path) +{ + int result = -1; + + // get command and client + void* pClient = malloc(FS_CLIENT_SIZE); + void* pCmd = malloc(FS_CMD_BLOCK_SIZE); + + if(!pClient || !pCmd) { + // just in case free if not 0 + if(pClient) + free(pClient); + if(pCmd) + free(pCmd); + return -2; + } + + FSInit(); + FSInitCmdBlock(pCmd); + FSAddClientEx(pClient, 0, -1); + + char *mountPath = NULL; + + if(MountFS(pClient, pCmd, &mountPath) == 0) { + result = sd_fat_add_device(path, mountPath, pClient, pCmd); + free(mountPath); + } + + return result; +} + +int unmount_sd_fat(const char *path) +{ + void *pClient = 0; + void *pCmd = 0; + char *mountPath = 0; + + int result = sd_fat_remove_device(path, &pClient, &pCmd, &mountPath); + if(result == 0) + { + UmountFS(pClient, pCmd, mountPath); + FSDelClient(pClient); + free(pClient); + free(pCmd); + free(mountPath); + //FSShutdown(); + } + return result; +} diff --git a/src/fs/sd_fat_devoptab.h b/src/fs/sd_fat_devoptab.h new file mode 100644 index 0000000..8df487a --- /dev/null +++ b/src/fs/sd_fat_devoptab.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __SD_FAT_DEVOPTAB_H_ +#define __SD_FAT_DEVOPTAB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int mount_sd_fat(const char *path); +int unmount_sd_fat(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif // __SD_FAT_DEVOPTAB_H_ diff --git a/src/game/memory_area_table.c b/src/game/memory_area_table.c new file mode 100644 index 0000000..20ea351 --- /dev/null +++ b/src/game/memory_area_table.c @@ -0,0 +1,1729 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include +#include "common/common.h" +#include "memory_area_table.h" + +typedef struct _memory_values_t +{ + unsigned int start_address; + unsigned int end_address; +} memory_values_t; + +static const memory_values_t mem_vals_500[] = +{ + // TODO: Check which of those areas are usable +// { 0xB801308C, 0xB801701C } // size 16276 (15 kB) (0 MB) +// { 0xB80170B8, 0xB801B00C } // size 16216 (15 kB) (0 MB) +// { 0xB801B0B8, 0xB801F01C } // size 16232 (15 kB) (0 MB) +// { 0xB801F0C4, 0xB8023014 } // size 16212 (15 kB) (0 MB) +// { 0xB80230C4, 0xB8026EFC } // size 15932 (15 kB) (0 MB) +// { 0xB80270C4, 0xB802B014 } // size 16212 (15 kB) (0 MB) +// { 0xB802B0C4, 0xB802F014 } // size 16212 (15 kB) (0 MB) +// { 0xB802F0C4, 0xB8032E14 } // size 15700 (15 kB) (0 MB) +// { 0xB80330C4, 0xB8037014 } // size 16212 (15 kB) (0 MB) +// { 0xB803B068, 0xB803BC68 } // size 3076 (3 kB) (0 MB) +// { 0xB8043168, 0xB8044364 } // size 4608 (4 kB) (0 MB) +// { 0xB8045AF0, 0xB804E09C } // size 34224 (33 kB) (0 MB) +// { 0xB804E3D4, 0xB8050B24 } // size 10068 (9 kB) (0 MB) +// { 0xB8051940, 0xB805287C } // size 3904 (3 kB) (0 MB) +// { 0xB8052930, 0xB80538D4 } // size 4008 (3 kB) (0 MB) +// { 0xB8053934, 0xB805487C } // size 3916 (3 kB) (0 MB) +// { 0xB80566EC, 0xB8058664 } // size 8060 (7 kB) (0 MB) +// { 0xB80586EC, 0xB805A664 } // size 8060 (7 kB) (0 MB) +// { 0xB805A6EC, 0xB805C664 } // size 8060 (7 kB) (0 MB) +// { 0xB805CB90, 0xB805DC78 } // size 4332 (4 kB) (0 MB) +// { 0xB805E40C, 0xB805ECF0 } // size 2280 (2 kB) (0 MB) +// { 0xB8060044, 0xB8060F8C } // size 3916 (3 kB) (0 MB) +// { 0xB8061040, 0xB806203C } // size 4096 (4 kB) (0 MB) +// { 0xB8062DB4, 0xB806EE3C } // size 49292 (48 kB) (0 MB) +// { 0xB806EE84, 0xB8070DC4 } // size 8004 (7 kB) (0 MB) +// { 0xB8070E84, 0xB8072CFC } // size 7804 (7 kB) (0 MB) +// { 0xB8072E84, 0xB8074DC4 } // size 8004 (7 kB) (0 MB) +// { 0xB8076A30, 0xB807745C } // size 2608 (2 kB) (0 MB) +// { 0xB807FAF8, 0xB8081350 } // size 6236 (6 kB) (0 MB) +// { 0xB8081358, 0xB808228C } // size 3896 (3 kB) (0 MB) +// { 0xB8082358, 0xB808328C } // size 3896 (3 kB) (0 MB) +// { 0xB8083358, 0xB808428C } // size 3896 (3 kB) (0 MB) +// { 0xB80858E4, 0xB808787C } // size 8092 (7 kB) (0 MB) +// { 0xB80878F8, 0xB808B8A4 } // size 16304 (15 kB) (0 MB) +// { 0xB808C240, 0xB80901BC } // size 16256 (15 kB) (0 MB) +// { 0xB8090278, 0xB8092888 } // size 9748 (9 kB) (0 MB) +// { 0xB8092890, 0xB8097744 } // size 20152 (19 kB) (0 MB) +// { 0xB8097888, 0xB80A37E4 } // size 48992 (47 kB) (0 MB) +// { 0xB80A3818, 0xB80AF848 } // size 49204 (48 kB) (0 MB) +// { 0xB80AFAA0, 0xB80B0310 } // size 2164 (2 kB) (0 MB) +// { 0xB80B0320, 0xB80B16BC } // size 5024 (4 kB) (0 MB) +// { 0xB80B16C4, 0xB80B262C } // size 3948 (3 kB) (0 MB) +// { 0xB80B26C0, 0xB80B3B3C } // size 5248 (5 kB) (0 MB) +// { 0xB80B4200, 0xB80B5900 } // size 5892 (5 kB) (0 MB) +// { 0xB80B5934, 0xB80B713C } // size 6156 (6 kB) (0 MB) +// { 0xB80B8910, 0xB80BC074 } // size 14184 (13 kB) (0 MB) +// { 0xB80BC138, 0xB80BD13C } // size 4104 (4 kB) (0 MB) +// { 0xB80BD144, 0xB80C1084 } // size 16196 (15 kB) (0 MB) +// { 0xB80C1144, 0xB80C4E84 } // size 15684 (15 kB) (0 MB) +// { 0xB80C5144, 0xB80C9084 } // size 16196 (15 kB) (0 MB) +// { 0xB80CC780, 0xB80CCFA4 } // size 2088 (2 kB) (0 MB) +// { 0xB80CDEE4, 0xB80CE6E4 } // size 2052 (2 kB) (0 MB) +// { 0xB80CF600, 0xB80D707C } // size 31360 (30 kB) (0 MB) +// { 0xB80D719C, 0xB80DC3FC } // size 21092 (20 kB) (0 MB) +// { 0xB80DC61C, 0xB81748FC } // size 623332 (608 kB) (0 MB) +// { 0xB817552C, 0xB817B534 } // size 24588 (24 kB) (0 MB) +// { 0xB817BD38, 0xB818037C } // size 17992 (17 kB) (0 MB) +// { 0xB81804E0, 0xB81C037C } // size 261792 (255 kB) (0 MB) +// { 0xB81C14E8, 0xB81C85FC } // size 28952 (28 kB) (0 MB) +// { 0xB81C881C, 0xB81C97C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81C981C, 0xB81CA7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81CA81C, 0xB81CB7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81CB81C, 0xB81CC7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81CC81C, 0xB81CD7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81CD9C0, 0xB81CE7C0 } // size 3588 (3 kB) (0 MB) +// { 0xB81CE870, 0xB81CF7C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81CF870, 0xB81D07C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81D0870, 0xB81D17C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81D1870, 0xB81D27C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81D296C, 0xB81D37C0 } // size 3672 (3 kB) (0 MB) +// { 0xB81D3ABC, 0xB81D47C0 } // size 3336 (3 kB) (0 MB) +// { 0xB81D481C, 0xB81D57C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81D581C, 0xB81D67C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81D6A68, 0xB81D77C0 } // size 3420 (3 kB) (0 MB) +// { 0xB81D796C, 0xB81D87C0 } // size 3672 (3 kB) (0 MB) +// { 0xB81D89C0, 0xB81D97C0 } // size 3588 (3 kB) (0 MB) +// { 0xB81D9870, 0xB81DA7C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81DA81C, 0xB81DB7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81DB96C, 0xB81DC7C0 } // size 3672 (3 kB) (0 MB) +// { 0xB81DC9C0, 0xB81DD7C0 } // size 3588 (3 kB) (0 MB) +// { 0xB81DD870, 0xB81DE7C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81DE81C, 0xB81DF7C0 } // size 4008 (3 kB) (0 MB) +// { 0xB81DF96C, 0xB81E07C0 } // size 3672 (3 kB) (0 MB) +// { 0xB81E09C0, 0xB81E17C0 } // size 3588 (3 kB) (0 MB) +// { 0xB81E1870, 0xB81E27C0 } // size 3924 (3 kB) (0 MB) +// { 0xB81E281C, 0xB820863C } // size 155172 (151 kB) (0 MB) +// { 0xB820B7C4, 0xB821063C } // size 20092 (19 kB) (0 MB) +// { 0xB8229490, 0xB822A4EC } // size 4192 (4 kB) (0 MB) +// { 0xB822F48C, 0xB823153C } // size 8372 (8 kB) (0 MB) +// { 0xB82327E4, 0xB8233060 } // size 2176 (2 kB) (0 MB) +// { 0xB8234080, 0xB824B340 } // size 94916 (92 kB) (0 MB) +// { 0xB824D8C0, 0xB828D880 } // size 262084 (255 kB) (0 MB) +// { 0xB82A8DE0, 0xB82B64FC } // size 55072 (53 kB) (0 MB) +// { 0xB82BC624, 0xB82C63FC } // size 40412 (39 kB) (0 MB) +// { 0xB82C642C, 0xB82CA42C } // size 16388 (16 kB) (0 MB) +// { 0xB82CBB6C, 0xB82CDB80 } // size 8216 (8 kB) (0 MB) +// { 0xB82CF708, 0xB82D0790 } // size 4236 (4 kB) (0 MB) +// { 0xB82D38FC, 0xB82D4A0C } // size 4372 (4 kB) (0 MB) +// { 0xB82EDF80, 0xB82EF77C } // size 6144 (6 kB) (0 MB) +// { 0xB82F6CA4, 0xB82F7820 } // size 2944 (2 kB) (0 MB) +// { 0xB82F79B0, 0xB82F861C } // size 3184 (3 kB) (0 MB) +// { 0xB82F8FB0, 0xB82FA080 } // size 4308 (4 kB) (0 MB) +// { 0xB8302A78, 0xB830428C } // size 6168 (6 kB) (0 MB) +// { 0xB8333434, 0xB8337D0C } // size 18652 (18 kB) (0 MB) +// { 0xB8338ED0, 0xB83396DC } // size 2064 (2 kB) (0 MB) +// { 0xB833C5E0, 0xB8340EAC } // size 18640 (18 kB) (0 MB) +// { 0xB834DB34, 0xB834EB40 } // size 4112 (4 kB) (0 MB) +// { 0xB83542F0, 0xB8356344 } // size 8280 (8 kB) (0 MB) +// { 0xB83574B0, 0xB83583FC } // size 3920 (3 kB) (0 MB) +// { 0xB8358A80, 0xB835A430 } // size 6580 (6 kB) (0 MB) +// { 0xB835AA08, 0xB8366884 } // size 48768 (47 kB) (0 MB) +// { 0xB8366B04, 0xB836DEE8 } // size 29672 (28 kB) (0 MB) +// { 0xB836E0DC, 0xB8378E3C } // size 44388 (43 kB) (0 MB) +// { 0xB8378E44, 0xB837CC6C } // size 15916 (15 kB) (0 MB) +// { 0xB837D5E4, 0xB8381524 } // size 16196 (15 kB) (0 MB) +// { 0xB83A3AE4, 0xB83A5308 } // size 6184 (6 kB) (0 MB) +// { 0xB83A73DC, 0xB84D2AE4 } // size 1226508 (1197 kB) (1 MB) +// { 0xB84D2F80, 0xB84D393C } // size 2496 (2 kB) (0 MB) +// { 0xB84D43C0, 0xB84D513C } // size 3456 (3 kB) (0 MB) +// { 0xB84D604C, 0xB84D6F68 } // size 3872 (3 kB) (0 MB) +// { 0xB84D7730, 0xB85021FC } // size 174800 (170 kB) (0 MB) +// { 0xB8583B7C, 0xB8584538 } // size 2496 (2 kB) (0 MB) +// { 0xB8585F34, 0xB858937C } // size 13388 (13 kB) (0 MB) +// { 0xB8589A88, 0xB858DC3C } // size 16824 (16 kB) (0 MB) +// { 0xB858DC64, 0xB859B40C } // size 55212 (53 kB) (0 MB) +// { 0xB85A8728, 0xB85A90A4 } // size 2432 (2 kB) (0 MB) +// { 0xB85A90BC, 0xB85B3448 } // size 41872 (40 kB) (0 MB) +// { 0xB85B3488, 0xB85C626C } // size 77288 (75 kB) (0 MB) +// { 0xB85C6314, 0xB85C7874 } // size 5476 (5 kB) (0 MB) +// { 0xB85CF8DC, 0xB85D147C } // size 7076 (6 kB) (0 MB) +// { 0xB85D1484, 0xB85E1284 } // size 65028 (63 kB) (0 MB) +// { 0xB85E1484, 0xB85ED094 } // size 48148 (47 kB) (0 MB) +// { 0xB85ED1E4, 0xB85EECFC } // size 6940 (6 kB) (0 MB) +// { 0xB85EF1C8, 0xB85F02DC } // size 4376 (4 kB) (0 MB) +// { 0xB85F1484, 0xB8601284 } // size 65028 (63 kB) (0 MB) +// { 0xB8601480, 0xB8604FFC } // size 15232 (14 kB) (0 MB) +// { 0xB8608F18, 0xB86147F8 } // size 47332 (46 kB) (0 MB) +// { 0xB8615000, 0xB8615FFC } // size 4096 (4 kB) (0 MB) +// { 0xB861CA00, 0xB861DF40 } // size 5444 (5 kB) (0 MB) +// { 0xB861F3E4, 0xB8632B00 } // size 79648 (77 kB) (0 MB) +// { 0xB8639790, 0xB8649BC0 } // size 66612 (65 kB) (0 MB) +// { 0xB86502E0, 0xB865EE00 } // size 60196 (58 kB) (0 MB) +// { 0xB86601FC, 0xB8667EE0 } // size 31976 (31 kB) (0 MB) +// { 0xB866A894, 0xB866B6C0 } // size 3632 (3 kB) (0 MB) +// { 0xB866BF58, 0xB86745A0 } // size 34380 (33 kB) (0 MB) +// { 0xB86807B4, 0xB868D680 } // size 52944 (51 kB) (0 MB) +// { 0xB8690D2C, 0xB86B3CA0 } // size 143224 (139 kB) (0 MB) +// { 0xB86C45F8, 0xB86D2900 } // size 58124 (56 kB) (0 MB) +// { 0xB86D7AA4, 0xB86EEB80 } // size 94432 (92 kB) (0 MB) +// { 0xB86F0700, 0xB86F1FC0 } // size 6340 (6 kB) (0 MB) +// { 0xB86F21A0, 0xB86F2BB8 } // size 2588 (2 kB) (0 MB) +// { 0xB86F3290, 0xB86F73A0 } // size 16660 (16 kB) (0 MB) +// { 0xB86F740C, 0xB8702DC0 } // size 47544 (46 kB) (0 MB) +// { 0xB8704880, 0xB871E3C0 } // size 105284 (102 kB) (0 MB) +// { 0xB87202F0, 0xB8720D80 } // size 2708 (2 kB) (0 MB) +// { 0xB8721978, 0xB872AD80 } // size 37900 (37 kB) (0 MB) +// { 0xB873B684, 0xB874C180 } // size 68352 (66 kB) (0 MB) +// { 0xB8751354, 0xB8769780 } // size 99376 (97 kB) (0 MB) +// { 0xB876CC88, 0xB876D5C8 } // size 2372 (2 kB) (0 MB) +// { 0xB87768AC, 0xB877BF7C } // size 22228 (21 kB) (0 MB) +// { 0xB877C238, 0xB8788B40 } // size 51468 (50 kB) (0 MB) +// { 0xB8789618, 0xB878A67C } // size 4200 (4 kB) (0 MB) +// { 0xB878A684, 0xB878B6FC } // size 4220 (4 kB) (0 MB) +// { 0xB878B798, 0xB878C7FC } // size 4200 (4 kB) (0 MB) +// { 0xB878C804, 0xB878D87C } // size 4220 (4 kB) (0 MB) +// { 0xB878D918, 0xB878E97C } // size 4200 (4 kB) (0 MB) +// { 0xB878E984, 0xB878F9FC } // size 4220 (4 kB) (0 MB) +// { 0xB878FA98, 0xB8790AFC } // size 4200 (4 kB) (0 MB) +// { 0xB8790B04, 0xB8791B7C } // size 4220 (4 kB) (0 MB) +// { 0xB8791C18, 0xB8792C7C } // size 4200 (4 kB) (0 MB) +// { 0xB8792C84, 0xB8793CFC } // size 4220 (4 kB) (0 MB) +// { 0xB8793D98, 0xB8794DFC } // size 4200 (4 kB) (0 MB) +// { 0xB8794E04, 0xB8795E7C } // size 4220 (4 kB) (0 MB) +// { 0xB8795F18, 0xB8796F7C } // size 4200 (4 kB) (0 MB) +// { 0xB8796F84, 0xB8797FFC } // size 4220 (4 kB) (0 MB) +// { 0xB8798098, 0xB87990FC } // size 4200 (4 kB) (0 MB) +// { 0xB8799104, 0xB879A17C } // size 4220 (4 kB) (0 MB) +// { 0xB879A218, 0xB879B27C } // size 4200 (4 kB) (0 MB) +// { 0xB879B284, 0xB879C2FC } // size 4220 (4 kB) (0 MB) +// { 0xB879C398, 0xB879D3FC } // size 4200 (4 kB) (0 MB) +// { 0xB879D404, 0xB879E47C } // size 4220 (4 kB) (0 MB) +// { 0xB879E518, 0xB879F57C } // size 4200 (4 kB) (0 MB) +// { 0xB879F584, 0xB87A05FC } // size 4220 (4 kB) (0 MB) +// { 0xB87A0698, 0xB87A16FC } // size 4200 (4 kB) (0 MB) +// { 0xB87A1704, 0xB87A277C } // size 4220 (4 kB) (0 MB) +// { 0xB87A2818, 0xB87A387C } // size 4200 (4 kB) (0 MB) +// { 0xB87A3884, 0xB87A48FC } // size 4220 (4 kB) (0 MB) +// { 0xB87A4998, 0xB87A59FC } // size 4200 (4 kB) (0 MB) +// { 0xB87A5A04, 0xB87A6A7C } // size 4220 (4 kB) (0 MB) +// { 0xB87A6B18, 0xB87A7B7C } // size 4200 (4 kB) (0 MB) +// { 0xB87A7B84, 0xB87A8BFC } // size 4220 (4 kB) (0 MB) +// { 0xB87A8C98, 0xB87A9CFC } // size 4200 (4 kB) (0 MB) +// { 0xB87A9D04, 0xB87AAD7C } // size 4220 (4 kB) (0 MB) +// { 0xB87AAE18, 0xB87ABE7C } // size 4200 (4 kB) (0 MB) +// { 0xB87ABE84, 0xB87ACEFC } // size 4220 (4 kB) (0 MB) +// { 0xB87AD004, 0xB87ADFFC } // size 4092 (3 kB) (0 MB) +// { 0xB87AE004, 0xB87AF07C } // size 4220 (4 kB) (0 MB) +// { 0xB87AF118, 0xB87B017C } // size 4200 (4 kB) (0 MB) +// { 0xB87B0184, 0xB87B11FC } // size 4220 (4 kB) (0 MB) +// { 0xB87B1298, 0xB87B22FC } // size 4200 (4 kB) (0 MB) +// { 0xB87B2304, 0xB87B337C } // size 4220 (4 kB) (0 MB) +// { 0xB87B3418, 0xB87B447C } // size 4200 (4 kB) (0 MB) +// { 0xB87B474C, 0xB87B54FC } // size 3508 (3 kB) (0 MB) +// { 0xB87B5598, 0xB87B65FC } // size 4200 (4 kB) (0 MB) +// { 0xB87B6684, 0xB87B767C } // size 4092 (3 kB) (0 MB) +// { 0xB87B7718, 0xB87B877C } // size 4200 (4 kB) (0 MB) +// { 0xB87B8784, 0xB87B97FC } // size 4220 (4 kB) (0 MB) +// { 0xB87B9898, 0xB87BA8FC } // size 4200 (4 kB) (0 MB) +// { 0xB87BA904, 0xB87BB97C } // size 4220 (4 kB) (0 MB) +// { 0xB87BBA18, 0xB87BCA7C } // size 4200 (4 kB) (0 MB) +// { 0xB87BCA84, 0xB87BDAFC } // size 4220 (4 kB) (0 MB) +// { 0xB87BDB98, 0xB87BEBFC } // size 4200 (4 kB) (0 MB) +// { 0xB87BEC04, 0xB87BFC7C } // size 4220 (4 kB) (0 MB) +// { 0xB87BFD18, 0xB87C0D7C } // size 4200 (4 kB) (0 MB) +// { 0xB87C0D84, 0xB87C1DFC } // size 4220 (4 kB) (0 MB) +// { 0xB87C1E98, 0xB87C2EFC } // size 4200 (4 kB) (0 MB) +// { 0xB87C2F04, 0xB87C3F7C } // size 4220 (4 kB) (0 MB) +// { 0xB87C4018, 0xB87C507C } // size 4200 (4 kB) (0 MB) +// { 0xB87C5084, 0xB87C60FC } // size 4220 (4 kB) (0 MB) +// { 0xB87C6198, 0xB87C71FC } // size 4200 (4 kB) (0 MB) +// { 0xB87C7204, 0xB87C827C } // size 4220 (4 kB) (0 MB) +// { 0xB87C8318, 0xB87C937C } // size 4200 (4 kB) (0 MB) +// { 0xB87C9384, 0xB87CA3FC } // size 4220 (4 kB) (0 MB) +// { 0xB87CA498, 0xB87CB4FC } // size 4200 (4 kB) (0 MB) +// { 0xB87CB504, 0xB87CC57C } // size 4220 (4 kB) (0 MB) +// { 0xB87CC618, 0xB87CD67C } // size 4200 (4 kB) (0 MB) +// { 0xB87CD684, 0xB87CE6FC } // size 4220 (4 kB) (0 MB) +// { 0xB87CE798, 0xB87CF7FC } // size 4200 (4 kB) (0 MB) +// { 0xB87CF804, 0xB87D087C } // size 4220 (4 kB) (0 MB) +// { 0xB87D0918, 0xB87D197C } // size 4200 (4 kB) (0 MB) +// { 0xB87D1984, 0xB87D29FC } // size 4220 (4 kB) (0 MB) +// { 0xB87D2A98, 0xB87D3AFC } // size 4200 (4 kB) (0 MB) +// { 0xB87D3B04, 0xB87D4B7C } // size 4220 (4 kB) (0 MB) +// { 0xB87D4C18, 0xB87D5C7C } // size 4200 (4 kB) (0 MB) +// { 0xB87D5C84, 0xB87D6CFC } // size 4220 (4 kB) (0 MB) +// { 0xB87D6D98, 0xB87D7DFC } // size 4200 (4 kB) (0 MB) +// { 0xB87D7E04, 0xB87D8EFC } // size 4348 (4 kB) (0 MB) +// { 0xB87D8F18, 0xB87D9F7C } // size 4200 (4 kB) (0 MB) +// { 0xB87D9F84, 0xB87DB07C } // size 4348 (4 kB) (0 MB) +// { 0xB87DB098, 0xB87DC0FC } // size 4200 (4 kB) (0 MB) +// { 0xB87DC104, 0xB87DD17C } // size 4220 (4 kB) (0 MB) +// { 0xB87DD284, 0xB87DE27C } // size 4092 (3 kB) (0 MB) +// { 0xB87DE284, 0xB87DF37C } // size 4348 (4 kB) (0 MB) +// { 0xB87DF398, 0xB87E03FC } // size 4200 (4 kB) (0 MB) +// { 0xB87E06CC, 0xB87E147C } // size 3508 (3 kB) (0 MB) +// { 0xB87E1518, 0xB87E257C } // size 4200 (4 kB) (0 MB) +// { 0xB87E2604, 0xB87E35FC } // size 4092 (3 kB) (0 MB) +// { 0xB87E3698, 0xB87E46FC } // size 4200 (4 kB) (0 MB) +// { 0xB87E4704, 0xB87E577C } // size 4220 (4 kB) (0 MB) +// { 0xB87E5818, 0xB87E687C } // size 4200 (4 kB) (0 MB) +// { 0xB87E6884, 0xB87E78FC } // size 4220 (4 kB) (0 MB) +// { 0xB87E7998, 0xB87E89FC } // size 4200 (4 kB) (0 MB) +// { 0xB87E8A04, 0xB87E9A7C } // size 4220 (4 kB) (0 MB) +// { 0xB87E9B18, 0xB87EAB7C } // size 4200 (4 kB) (0 MB) +// { 0xB87EAB84, 0xB87EBBFC } // size 4220 (4 kB) (0 MB) +// { 0xB87EBC98, 0xB87ECCFC } // size 4200 (4 kB) (0 MB) +// { 0xB87ECD04, 0xB87EDD7C } // size 4220 (4 kB) (0 MB) +// { 0xB87EDE18, 0xB87EEE7C } // size 4200 (4 kB) (0 MB) +// { 0xB87EEE84, 0xB87EFEFC } // size 4220 (4 kB) (0 MB) +// { 0xB87EFF98, 0xB87F0FFC } // size 4200 (4 kB) (0 MB) +// { 0xB87F1004, 0xB87F207C } // size 4220 (4 kB) (0 MB) +// { 0xB87F2118, 0xB87F317C } // size 4200 (4 kB) (0 MB) +// { 0xB87F3184, 0xB87F41FC } // size 4220 (4 kB) (0 MB) +// { 0xB87F4298, 0xB87F52FC } // size 4200 (4 kB) (0 MB) +// { 0xB87F5304, 0xB87F637C } // size 4220 (4 kB) (0 MB) +// { 0xB87F6418, 0xB87F747C } // size 4200 (4 kB) (0 MB) +// { 0xB87F7484, 0xB87F84FC } // size 4220 (4 kB) (0 MB) +// { 0xB87F8598, 0xB87F95FC } // size 4200 (4 kB) (0 MB) +// { 0xB87F9604, 0xB87FA67C } // size 4220 (4 kB) (0 MB) +// { 0xB87FA718, 0xB87FB77C } // size 4200 (4 kB) (0 MB) +// { 0xB87FB784, 0xB87FC7FC } // size 4220 (4 kB) (0 MB) +// { 0xB87FC898, 0xB87FD8FC } // size 4200 (4 kB) (0 MB) +// { 0xB87FD904, 0xB87FE97C } // size 4220 (4 kB) (0 MB) +// { 0xB87FEA18, 0xB87FFA7C } // size 4200 (4 kB) (0 MB) +// { 0xB87FFA84, 0xB8800AFC } // size 4220 (4 kB) (0 MB) +// { 0xB8800B98, 0xB8801BFC } // size 4200 (4 kB) (0 MB) +// { 0xB8801C04, 0xB8802C7C } // size 4220 (4 kB) (0 MB) +// { 0xB8802D18, 0xB8803D7C } // size 4200 (4 kB) (0 MB) +// { 0xB8803D84, 0xB8804E7C } // size 4348 (4 kB) (0 MB) +// { 0xB8804E98, 0xB8805EFC } // size 4200 (4 kB) (0 MB) +// { 0xB8805F04, 0xB8806FFC } // size 4348 (4 kB) (0 MB) +// { 0xB8807018, 0xB880807C } // size 4200 (4 kB) (0 MB) +// { 0xB8808084, 0xB88090FC } // size 4220 (4 kB) (0 MB) +// { 0xB8809204, 0xB880A1FC } // size 4092 (3 kB) (0 MB) +// { 0xB880A204, 0xB880B2FC } // size 4348 (4 kB) (0 MB) +// { 0xB880B318, 0xB880C37C } // size 4200 (4 kB) (0 MB) +// { 0xB880C64C, 0xB880D3FC } // size 3508 (3 kB) (0 MB) +// { 0xB880D498, 0xB880E4FC } // size 4200 (4 kB) (0 MB) +// { 0xB880E584, 0xB880F57C } // size 4092 (3 kB) (0 MB) +// { 0xB880F584, 0xB881183C } // size 8892 (8 kB) (0 MB) +// { 0xB8811844, 0xB881B680 } // size 40512 (39 kB) (0 MB) +// { 0xB882058C, 0xB882F6E0 } // size 61784 (60 kB) (0 MB) +// { 0xB8832638, 0xB883AA40 } // size 33804 (33 kB) (0 MB) +// { 0xB883ECDC, 0xB883F900 } // size 3112 (3 kB) (0 MB) +// { 0xB8840298, 0xB8847BC0 } // size 31020 (30 kB) (0 MB) +// { 0xB88485D0, 0xB88565BC } // size 57328 (55 kB) (0 MB) +// { 0xB88565D8, 0xB88626D4 } // size 49408 (48 kB) (0 MB) +// { 0xB88627DC, 0xB8872900 } // size 65832 (64 kB) (0 MB) +// { 0xB8875AE0, 0xB8883100 } // size 54820 (53 kB) (0 MB) +// { 0xB888482C, 0xB8885EBC } // size 5780 (5 kB) (0 MB) +// { 0xB8885ED8, 0xB888B100 } // size 21036 (20 kB) (0 MB) +// { 0xB888D590, 0xB8891F40 } // size 18868 (18 kB) (0 MB) +// { 0xB88954F8, 0xB8895CF8 } // size 2052 (2 kB) (0 MB) +// { 0xB8897854, 0xB8898054 } // size 2052 (2 kB) (0 MB) +// { 0xB88998F4, 0xB889C350 } // size 10848 (10 kB) (0 MB) +// { 0xB889C35C, 0xB889D780 } // size 5160 (5 kB) (0 MB) +// { 0xB889DA80, 0xB88A9A80 } // size 49156 (48 kB) (0 MB) +// { 0xB88A9A88, 0xB88B5C88 } // size 49668 (48 kB) (0 MB) +// { 0xB88B5C90, 0xB88C1E90 } // size 49668 (48 kB) (0 MB) +// { 0xB88C1E98, 0xB88EB09C } // size 168456 (164 kB) (0 MB) +// { 0xB88EB0A4, 0xB88EEC10 } // size 15216 (14 kB) (0 MB) +// { 0xB88EEC30, 0xB8B06E94 } // size 2196072 (2144 kB) (2 MB) +// { 0xB8B06EC4, 0xB8B930C0 } // size 573952 (560 kB) (0 MB) +// { 0xB8BA1868, 0xB8BC22A0 } // size 133692 (130 kB) (0 MB) +// { 0xB8BC47F0, 0xB8BDEC80 } // size 107668 (105 kB) (0 MB) +// { 0xB8BDFBF4, 0xB8BE2640 } // size 10832 (10 kB) (0 MB) +// { 0xB8BE2C7C, 0xB8BE3D8C } // size 4372 (4 kB) (0 MB) +// { 0xB8BE3DC0, 0xB8C02280 } // size 124100 (121 kB) (0 MB) +// { 0xB8C02FC8, 0xB8C19920 } // size 92508 (90 kB) (0 MB) +// { 0xB8C2D35C, 0xB8C3DDC0 } // size 68200 (66 kB) (0 MB) +// { 0xB8C48654, 0xB8C6E2E0 } // size 154768 (151 kB) (0 MB) +// { 0xB8C80608, 0xB8C87040 } // size 27196 (26 kB) (0 MB) +// { 0xB8C8C694, 0xB8C8F3C0 } // size 11568 (11 kB) (0 MB) +// { 0xB8C90734, 0xB8C94904 } // size 16852 (16 kB) (0 MB) +// { 0xB8C94970, 0xB8CA1500 } // size 52116 (50 kB) (0 MB) +// { 0xB8CA28B8, 0xB8CA5080 } // size 10188 (9 kB) (0 MB) +// { 0xB8CA50C4, 0xB8CA6E94 } // size 7636 (7 kB) (0 MB) +// { 0xB8CA7104, 0xB8CA88AC } // size 6060 (5 kB) (0 MB) +// { 0xB8CA9144, 0xB8CAAF14 } // size 7636 (7 kB) (0 MB) +// { 0xB8CAB180, 0xB8CAD180 } // size 8196 (8 kB) (0 MB) +// { 0xB8CADB7C, 0xB8CAEFC0 } // size 5192 (5 kB) (0 MB) +// { 0xB8CF81C0, 0xB8CF8F3C } // size 3456 (3 kB) (0 MB) +// { 0xB8CF8F44, 0xB8CF9E8C } // size 3916 (3 kB) (0 MB) +// { 0xB8CFA100, 0xB8CFA9C4 } // size 2248 (2 kB) (0 MB) +// { 0xB8CFB940, 0xB8CFCD30 } // size 5108 (4 kB) (0 MB) +// { 0xB8CFDD40, 0xB8CFECFC } // size 4032 (3 kB) (0 MB) +// { 0xB8CFEEE0, 0xB8CFFEFC } // size 4128 (4 kB) (0 MB) +// { 0xB8CFFF38, 0xB8D021FC } // size 8904 (8 kB) (0 MB) +// { 0xB8D0221C, 0xB8D035FC } // size 5092 (4 kB) (0 MB) +// { 0xB8D04E04, 0xB8D36934 } // size 203572 (198 kB) (0 MB) +// { 0xB8D3C194, 0xB8D3CE30 } // size 3232 (3 kB) (0 MB) +// { 0xB8D3CF44, 0xB8D3DBE0 } // size 3232 (3 kB) (0 MB) +// { 0xB8D3DCF4, 0xB8D3E990 } // size 3232 (3 kB) (0 MB) +// { 0xB8D3EAA4, 0xB8D3F740 } // size 3232 (3 kB) (0 MB) +// { 0xB8D3F850, 0xB8D404F0 } // size 3236 (3 kB) (0 MB) +// { 0xB8D40600, 0xB8D412A0 } // size 3236 (3 kB) (0 MB) +// { 0xB8D413B0, 0xB8D42050 } // size 3236 (3 kB) (0 MB) +// { 0xB8D47148, 0xB8D485C0 } // size 5244 (5 kB) (0 MB) +// { 0xB8D488D4, 0xB8D49D40 } // size 5232 (5 kB) (0 MB) +// { 0xB8D49FE4, 0xB8D4B440 } // size 5216 (5 kB) (0 MB) +// { 0xB8D4B7EC, 0xB8D4CC40 } // size 5208 (5 kB) (0 MB) +// { 0xB8D81D64, 0xB8D8FF8C } // size 57900 (56 kB) (0 MB) +// { 0xB8D954E0, 0xB8D9634C } // size 3696 (3 kB) (0 MB) +// { 0xB8D9A238, 0xB8D9C1CC } // size 8088 (7 kB) (0 MB) +// { 0xB8D9D258, 0xB8D9F1EC } // size 8088 (7 kB) (0 MB) +// { 0xB8D9FF20, 0xB8DA1EB4 } // size 8088 (7 kB) (0 MB) +// { 0xB8DB58E0, 0xB8DB74C0 } // size 7140 (6 kB) (0 MB) +// { 0xB8DB7E4C, 0xB8DB8C1C } // size 3540 (3 kB) (0 MB) +// { 0xB8DB95A8, 0xB8DBAA3C } // size 5272 (5 kB) (0 MB) +// { 0xB8DC6A0C, 0xB8E14284 } // size 317564 (310 kB) (0 MB) +// { 0xB8E142B0, 0xB8E152B0 } // size 4100 (4 kB) (0 MB) +// { 0xB8E15554, 0xB8E16360 } // size 3600 (3 kB) (0 MB) +// { 0xB8E18548, 0xB8E19544 } // size 4096 (4 kB) (0 MB) +// { 0xB8E1A1E0, 0xB8E1C1DC } // size 8192 (8 kB) (0 MB) +// { 0xB8E1D200, 0xB8E1F1FC } // size 8192 (8 kB) (0 MB) +// { 0xB8E1FEC8, 0xB8E21EC4 } // size 8192 (8 kB) (0 MB) +// { 0xB8E21ED4, 0xB8EC8294 } // size 680900 (664 kB) (0 MB) +// { 0xB8EC82C0, 0xB8EC92C0 } // size 4100 (4 kB) (0 MB) +// { 0xB8EC9380, 0xB8ECA370 } // size 4084 (3 kB) (0 MB) +// { 0xB8ECE1F0, 0xB8ED01EC } // size 8192 (8 kB) (0 MB) +// { 0xB8ED1210, 0xB8ED320C } // size 8192 (8 kB) (0 MB) +// { 0xB8ED3ED8, 0xB8ED5ED4 } // size 8192 (8 kB) (0 MB) +// { 0xB8ED9AE8, 0xB8EDC63C } // size 11096 (10 kB) (0 MB) +// { 0xB8EDC678, 0xB8EDCF34 } // size 2240 (2 kB) (0 MB) +// { 0xB8EDDC7C, 0xB8F7C2A4 } // size 648748 (633 kB) (0 MB) +// { 0xB8F7C2D0, 0xB8F7D2D0 } // size 4100 (4 kB) (0 MB) +// { 0xB8F7D574, 0xB8F7E380 } // size 3600 (3 kB) (0 MB) +// { 0xB8F80568, 0xB8F81564 } // size 4096 (4 kB) (0 MB) +// { 0xB8F82200, 0xB8F841FC } // size 8192 (8 kB) (0 MB) +// { 0xB8F85220, 0xB8F8721C } // size 8192 (8 kB) (0 MB) +// { 0xB8F87EE8, 0xB8F89EE4 } // size 8192 (8 kB) (0 MB) +// { 0xB8F89EF4, 0xB90302B4 } // size 680900 (664 kB) (0 MB) +// { 0xB9030800, 0xB93F69FC } // size 3957248 (3864 kB) (3 MB) +// { 0xB94128D4, 0xB94179C0 } // size 20720 (20 kB) (0 MB) +// { 0xB942587C, 0xB94307FC } // size 44932 (43 kB) (0 MB) +// { 0xB96CE000, 0xB96E0A9C } // size 76448 (74 kB) (0 MB) +// { 0xB970200C, 0xB98B9C54 } // size 1801292 (1759 kB) (1 MB) +// { 0xB98E9794, 0xB98F1794 } // size 32772 (32 kB) (0 MB) +// { 0xB9F13600, 0xB9F175FC } // size 16384 (16 kB) (0 MB) +// { 0xB9F17658, 0xB9F67658 } // size 327684 (320 kB) (0 MB) +// { 0xB9F6779C, 0xB9FB779C } // size 327684 (320 kB) (0 MB) +// { 0xB9FB78E0, 0xBA0078E0 } // size 327684 (320 kB) (0 MB) +// { 0xBA007A24, 0xBA057A24 } // size 327684 (320 kB) (0 MB) +// { 0xBA057B68, 0xBA1B9578 } // size 1448468 (1414 kB) (1 MB) +// { 0xBA1BA20C, 0xBA1BBFF8 } // size 7664 (7 kB) (0 MB) +// { 0xBA1BC04C, 0xBA1BDFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA1BE0DC, 0xBA1BFFFC } // size 7972 (7 kB) (0 MB) +// { 0xBA1C7028, 0xBA1C7FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA1CA23C, 0xBA1CBFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBA1CC044, 0xBA1CDFFC } // size 8124 (7 kB) (0 MB) +// { 0xBA1CE2E4, 0xBA1CFFFC } // size 7452 (7 kB) (0 MB) +// { 0xBA1D4028, 0xBA1D5FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA1DA698, 0xBA1DBFFC } // size 6504 (6 kB) (0 MB) +// { 0xBA1E02D0, 0xBA1E1FFC } // size 7472 (7 kB) (0 MB) +// { 0xBA1E6028, 0xBA1E7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA1EC028, 0xBA1EDFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA1F2028, 0xBA1F3FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA1F8028, 0xBA1F9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA1FE028, 0xBA1FFFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA204674, 0xBA205FFC } // size 6540 (6 kB) (0 MB) +// { 0xBA20A028, 0xBA20BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA210028, 0xBA211FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA234050, 0xBA235FFC } // size 8112 (7 kB) (0 MB) +// { 0xBA2360AC, 0xBA236FFC } // size 3924 (3 kB) (0 MB) +// { 0xBA2587BC, 0xBA259FF8 } // size 6208 (6 kB) (0 MB) +// { 0xBA25A04C, 0xBA25BFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA25C07C, 0xBA25CFFC } // size 3972 (3 kB) (0 MB) +// { 0xBA26109C, 0xBA261FF8 } // size 3936 (3 kB) (0 MB) +// { 0xBA262054, 0xBA263FFC } // size 8108 (7 kB) (0 MB) +// { 0xBA2643C8, 0xBA265FFC } // size 7224 (7 kB) (0 MB) +// { 0xBA26E028, 0xBA26EFFC } // size 4056 (3 kB) (0 MB) +// { 0xBA271028, 0xBA271FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA274028, 0xBA2751FC } // size 4568 (4 kB) (0 MB) +// { 0xBA2752C0, 0xBA275FFC } // size 3392 (3 kB) (0 MB) +// { 0xBA276028, 0xBA277FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA27C028, 0xBA27E1FC } // size 8664 (8 kB) (0 MB) +// { 0xBA282028, 0xBA282FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA285028, 0xBA285FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA2A0154, 0xBA2A1FFC } // size 7852 (7 kB) (0 MB) +// { 0xBA2A6504, 0xBA2A81FC } // size 7420 (7 kB) (0 MB) +// { 0xBA2AC028, 0xBA2ADFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA2B249C, 0xBA2B3FF8 } // size 7008 (6 kB) (0 MB) +// { 0xBA2B4044, 0xBA2B5FFC } // size 8124 (7 kB) (0 MB) +// { 0xBA2F0AFC, 0xBA2F1FF8 } // size 5376 (5 kB) (0 MB) +// { 0xBA2F2068, 0xBA2F3FFC } // size 8088 (7 kB) (0 MB) +// { 0xBA2F412C, 0xBA2F5FFC } // size 7892 (7 kB) (0 MB) +// { 0xBA2F67FC, 0xBA2F7FF8 } // size 6144 (6 kB) (0 MB) +// { 0xBA2F804C, 0xBA2F9FFC } // size 8116 (7 kB) (0 MB) +// { 0xBA2FA2C8, 0xBA2FBFFC } // size 7480 (7 kB) (0 MB) +// { 0xBA2FC294, 0xBA2FE1FC } // size 8044 (7 kB) (0 MB) +// { 0xBA302028, 0xBA3041FC } // size 8664 (8 kB) (0 MB) +// { 0xBA318828, 0xBA319FFC } // size 6104 (5 kB) (0 MB) +// { 0xBA31E1A0, 0xBA31FFFC } // size 7776 (7 kB) (0 MB) +// { 0xBA3227F0, 0xBA323FFC } // size 6160 (6 kB) (0 MB) +// { 0xBA334828, 0xBA335FFC } // size 6104 (5 kB) (0 MB) +// { 0xBA33E048, 0xBA33FFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA342F80, 0xBA3437FC } // size 2176 (2 kB) (0 MB) +// { 0xBA343828, 0xBA344044 } // size 2080 (2 kB) (0 MB) +// { 0xBA346028, 0xBA346954 } // size 2352 (2 kB) (0 MB) +// { 0xBA348828, 0xBA349124 } // size 2304 (2 kB) (0 MB) +// { 0xBA355828, 0xBA356574 } // size 3408 (3 kB) (0 MB) +// { 0xBA35E04C, 0xBA35FFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA360080, 0xBA360FFC } // size 3968 (3 kB) (0 MB) +// { 0xBA361444, 0xBA361FFC } // size 3004 (2 kB) (0 MB) +// { 0xBA36423C, 0xBA365FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBA3E2048, 0xBA3E3FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA3E4B3C, 0xBA3E5FF8 } // size 5312 (5 kB) (0 MB) +// { 0xBA3E6054, 0xBA3E7FFC } // size 8108 (7 kB) (0 MB) +// { 0xBA3E895C, 0xBA3E9FF8 } // size 5792 (5 kB) (0 MB) +// { 0xBA3EA050, 0xBA3EBFFC } // size 8112 (7 kB) (0 MB) +// { 0xBA3EC10C, 0xBA3EDFFC } // size 7924 (7 kB) (0 MB) +// { 0xBA3F2028, 0xBA3F2FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA3FF028, 0xBA3FFFFC } // size 4056 (3 kB) (0 MB) +// { 0xBA402028, 0xBA402FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA406048, 0xBA407FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA40B5BC, 0xBA40BFF8 } // size 2624 (2 kB) (0 MB) +// { 0xBA40C04C, 0xBA40DFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA40E07C, 0xBA40EFFC } // size 3972 (3 kB) (0 MB) +// { 0xBA41521C, 0xBA415FF8 } // size 3552 (3 kB) (0 MB) +// { 0xBA416048, 0xBA417FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA41807C, 0xBA418FFC } // size 3972 (3 kB) (0 MB) +// { 0xBA419300, 0xBA419FFC } // size 3328 (3 kB) (0 MB) +// { 0xBA45C89C, 0xBA45DFF8 } // size 5984 (5 kB) (0 MB) +// { 0xBA45E044, 0xBA45FFFC } // size 8124 (7 kB) (0 MB) +// { 0xBA4602E4, 0xBA461FFC } // size 7452 (7 kB) (0 MB) +// { 0xBA464DFC, 0xBA465FFC } // size 4612 (4 kB) (0 MB) +// { 0xBA466028, 0xBA4681FC } // size 8664 (8 kB) (0 MB) +// { 0xBA46AEFC, 0xBA46BFFC } // size 4356 (4 kB) (0 MB) +// { 0xBA46C028, 0xBA46E1FC } // size 8664 (8 kB) (0 MB) +// { 0xBA470EFC, 0xBA471FFC } // size 4356 (4 kB) (0 MB) +// { 0xBA472028, 0xBA472908 } // size 2276 (2 kB) (0 MB) +// { 0xBA477028, 0xBA4781FC } // size 4568 (4 kB) (0 MB) +// { 0xBA47AFFC, 0xBA47BFFC } // size 4100 (4 kB) (0 MB) +// { 0xBA47C028, 0xBA47D01C } // size 4088 (3 kB) (0 MB) +// { 0xBA47D840, 0xBA47E0A8 } // size 2156 (2 kB) (0 MB) +// { 0xBA47F028, 0xBA47FFFC } // size 4056 (3 kB) (0 MB) +// { 0xBA482CFC, 0xBA483FFC } // size 4868 (4 kB) (0 MB) +// { 0xBA484028, 0xBA485120 } // size 4348 (4 kB) (0 MB) +// { 0xBA485A40, 0xBA4862A8 } // size 2156 (2 kB) (0 MB) +// { 0xBA487598, 0xBA487FFC } // size 2664 (2 kB) (0 MB) +// { 0xBA48AFFC, 0xBA48BFFC } // size 4100 (4 kB) (0 MB) +// { 0xBA48C028, 0xBA48DFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA490DFC, 0xBA491FFC } // size 4612 (4 kB) (0 MB) +// { 0xBA492B5C, 0xBA493FF8 } // size 5280 (5 kB) (0 MB) +// { 0xBA494044, 0xBA495FFC } // size 8124 (7 kB) (0 MB) +// { 0xBA49609C, 0xBA497FFC } // size 8036 (7 kB) (0 MB) +// { 0xBA49C24C, 0xBA49CFFC } // size 3508 (3 kB) (0 MB) +// { 0xBA49F23C, 0xBA49FFF8 } // size 3520 (3 kB) (0 MB) +// { 0xBA4A004C, 0xBA4A1FFC } // size 8116 (7 kB) (0 MB) +// { 0xBA4B223C, 0xBA4B3FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBA4B4048, 0xBA4B5FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA4DA9FC, 0xBA4DBFF8 } // size 5632 (5 kB) (0 MB) +// { 0xBA4DC04C, 0xBA4DDFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA4FC19C, 0xBA4FDFF8 } // size 7776 (7 kB) (0 MB) +// { 0xBA4FE068, 0xBA4FFFFC } // size 8088 (7 kB) (0 MB) +// { 0xBA500054, 0xBA501FFC } // size 8108 (7 kB) (0 MB) +// { 0xBA5220A8, 0xBA523FFC } // size 8024 (7 kB) (0 MB) +// { 0xBA524054, 0xBA525FFC } // size 8108 (7 kB) (0 MB) +// { 0xBA5362F8, 0xBA5371E8 } // size 3828 (3 kB) (0 MB) +// { 0xBA55C91C, 0xBA55DFF8 } // size 5856 (5 kB) (0 MB) +// { 0xBA55E044, 0xBA55FFFC } // size 8124 (7 kB) (0 MB) +// { 0xBA560158, 0xBA561FFC } // size 7848 (7 kB) (0 MB) +// { 0xBA5639C0, 0xBA5644FC } // size 2880 (2 kB) (0 MB) +// { 0xBA5645BC, 0xBA565FFC } // size 6724 (6 kB) (0 MB) +// { 0xBA566028, 0xBA566FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA567B98, 0xBA5683FC } // size 2152 (2 kB) (0 MB) +// { 0xBA568718, 0xBA568FFC } // size 2280 (2 kB) (0 MB) +// { 0xBA569688, 0xBA569FFC } // size 2424 (2 kB) (0 MB) +// { 0xBA56B1D0, 0xBA56C1FC } // size 4144 (4 kB) (0 MB) +// { 0xBA56C2C0, 0xBA56CFFC } // size 3392 (3 kB) (0 MB) +// { 0xBA56D23C, 0xBA56DFF8 } // size 3520 (3 kB) (0 MB) +// { 0xBA56E044, 0xBA56FFFC } // size 8124 (7 kB) (0 MB) +// { 0xBA5702BC, 0xBA572014 } // size 7516 (7 kB) (0 MB) +// { 0xBA576028, 0xBA577FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA57A028, 0xBA57C3FC } // size 9176 (8 kB) (0 MB) +// { 0xBA582028, 0xBA583FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA586028, 0xBA587FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA58A028, 0xBA58BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA58E028, 0xBA58FFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA592BBC, 0xBA593FF8 } // size 5184 (5 kB) (0 MB) +// { 0xBA594050, 0xBA595FFC } // size 8112 (7 kB) (0 MB) +// { 0xBA596298, 0xBA597FFC } // size 7528 (7 kB) (0 MB) +// { 0xBA5B0028, 0xBA5B1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA5B6028, 0xBA5B71FC } // size 4568 (4 kB) (0 MB) +// { 0xBA5B72C0, 0xBA5B7FFC } // size 3392 (3 kB) (0 MB) +// { 0xBA5B8028, 0xBA5B9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA5BE028, 0xBA5BE828 } // size 2052 (2 kB) (0 MB) +// { 0xBA5C4028, 0xBA5C4FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA5C7028, 0xBA5C7FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA5D0028, 0xBA5D1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA5D6028, 0xBA5D7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA5EC828, 0xBA5EE1FC } // size 6616 (6 kB) (0 MB) +// { 0xBA5F2028, 0xBA5F3FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA60204C, 0xBA603FFC } // size 8116 (7 kB) (0 MB) +// { 0xBA604080, 0xBA604FFC } // size 3968 (3 kB) (0 MB) +// { 0xBA60575C, 0xBA605FFC } // size 2212 (2 kB) (0 MB) +// { 0xBA60C048, 0xBA60DFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA60E07C, 0xBA60EFFC } // size 3972 (3 kB) (0 MB) +// { 0xBA60F400, 0xBA60FFFC } // size 3072 (3 kB) (0 MB) +// { 0xBA61223C, 0xBA613FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBA614048, 0xBA615FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA61819C, 0xBA619FF8 } // size 7776 (7 kB) (0 MB) +// { 0xBA61A04C, 0xBA61BFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA61C514, 0xBA61DFFC } // size 6892 (6 kB) (0 MB) +// { 0xBA6741A8, 0xBA674FFC } // size 3672 (3 kB) (0 MB) +// { 0xBA67D36C, 0xBA67DFFC } // size 3220 (3 kB) (0 MB) +// { 0xBA68E028, 0xBA68FFFC } // size 8152 (7 kB) (0 MB) +// { 0xBA692700, 0xBA693FFC } // size 6400 (6 kB) (0 MB) +// { 0xBA6953FC, 0xBA695FFC } // size 3076 (3 kB) (0 MB) +// { 0xBA6A5680, 0xBA6A60FC } // size 2688 (2 kB) (0 MB) +// { 0xBA6A6680, 0xBA6A71FC } // size 2944 (2 kB) (0 MB) +// { 0xBA6A7680, 0xBA6A7FFC } // size 2432 (2 kB) (0 MB) +// { 0xBA6A8658, 0xBA6A9FFC } // size 6568 (6 kB) (0 MB) +// { 0xBA6AF374, 0xBA6AFBFC } // size 2188 (2 kB) (0 MB) +// { 0xBA6B0174, 0xBA6B0DFC } // size 3212 (3 kB) (0 MB) +// { 0xBA6B1374, 0xBA6B1BFC } // size 2188 (2 kB) (0 MB) +// { 0xBA6B2DFC, 0xBA6B3FF8 } // size 4608 (4 kB) (0 MB) +// { 0xBA6B4050, 0xBA6B5FFC } // size 8112 (7 kB) (0 MB) +// { 0xBA6B6C1C, 0xBA6B7FF8 } // size 5088 (4 kB) (0 MB) +// { 0xBA6EB2FC, 0xBA6EBFF8 } // size 3328 (3 kB) (0 MB) +// { 0xBA6EC04C, 0xBA6EDFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA6EE1D0, 0xBA6F01FC } // size 8240 (8 kB) (0 MB) +// { 0xBA704AF8, 0xBA705FFC } // size 5384 (5 kB) (0 MB) +// { 0xBA7087F0, 0xBA709FFC } // size 6160 (6 kB) (0 MB) +// { 0xBA7128DC, 0xBA713FF8 } // size 5920 (5 kB) (0 MB) +// { 0xBA714048, 0xBA715FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA716294, 0xBA717FFC } // size 7532 (7 kB) (0 MB) +// { 0xBA7181E4, 0xBA718FFC } // size 3612 (3 kB) (0 MB) +// { 0xBA71B028, 0xBA71BFFC } // size 4056 (3 kB) (0 MB) +// { 0xBA71E028, 0xBA71F1FC } // size 4568 (4 kB) (0 MB) +// { 0xBA71F2C0, 0xBA71FFFC } // size 3392 (3 kB) (0 MB) +// { 0xBA720028, 0xBA721FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA726254, 0xBA726FFC } // size 3500 (3 kB) (0 MB) +// { 0xBA729028, 0xBA729FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA737028, 0xBA737FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA73C028, 0xBA73E1FC } // size 8664 (8 kB) (0 MB) +// { 0xBA742028, 0xBA743FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA74841C, 0xBA749FF8 } // size 7136 (6 kB) (0 MB) +// { 0xBA74A04C, 0xBA74BFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA74C2A4, 0xBA74DFFC } // size 7516 (7 kB) (0 MB) +// { 0xBA750028, 0xBA750FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA753028, 0xBA7541FC } // size 4568 (4 kB) (0 MB) +// { 0xBA7542C0, 0xBA754FFC } // size 3392 (3 kB) (0 MB) +// { 0xBA755028, 0xBA755FFC } // size 4056 (3 kB) (0 MB) +// { 0xBA75D20C, 0xBA75DFFC } // size 3572 (3 kB) (0 MB) +// { 0xBA762254, 0xBA762FFC } // size 3500 (3 kB) (0 MB) +// { 0xBA76B028, 0xBA76BFFC } // size 4056 (3 kB) (0 MB) +// { 0xBA770028, 0xBA7721FC } // size 8664 (8 kB) (0 MB) +// { 0xBA776028, 0xBA777FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA77C41C, 0xBA77DFF8 } // size 7136 (6 kB) (0 MB) +// { 0xBA77E048, 0xBA77FFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA780168, 0xBA781FFC } // size 7832 (7 kB) (0 MB) +// { 0xBA78257C, 0xBA782FFC } // size 2692 (2 kB) (0 MB) +// { 0xBA785160, 0xBA785FFC } // size 3744 (3 kB) (0 MB) +// { 0xBA792800, 0xBA7942FC } // size 6912 (6 kB) (0 MB) +// { 0xBA794800, 0xBA795FFC } // size 6144 (6 kB) (0 MB) +// { 0xBA796158, 0xBA7971FC } // size 4264 (4 kB) (0 MB) +// { 0xBA7972C0, 0xBA797FFC } // size 3392 (3 kB) (0 MB) +// { 0xBA79915C, 0xBA799FF8 } // size 3744 (3 kB) (0 MB) +// { 0xBA79A04C, 0xBA79BFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA79CBBC, 0xBA79DFF8 } // size 5184 (5 kB) (0 MB) +// { 0xBA79E04C, 0xBA79FFFC } // size 8116 (7 kB) (0 MB) +// { 0xBA7A007C, 0xBA7A0FFC } // size 3972 (3 kB) (0 MB) +// { 0xBA7A2DBC, 0xBA7A3FF8 } // size 4672 (4 kB) (0 MB) +// { 0xBA7A4048, 0xBA7A5FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA7A607C, 0xBA7A6FFC } // size 3972 (3 kB) (0 MB) +// { 0xBA7A75B4, 0xBA7A7FFC } // size 2636 (2 kB) (0 MB) +// { 0xBA7AA23C, 0xBA7ABFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBA7AC048, 0xBA7ADFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA7D0F9C, 0xBA7D1FF8 } // size 4192 (4 kB) (0 MB) +// { 0xBA7D204C, 0xBA7D3FFC } // size 8116 (7 kB) (0 MB) +// { 0xBA7F25DC, 0xBA7F3FF8 } // size 6688 (6 kB) (0 MB) +// { 0xBA7F4050, 0xBA7F5FFC } // size 8112 (7 kB) (0 MB) +// { 0xBA7F6080, 0xBA7F6FFC } // size 3968 (3 kB) (0 MB) +// { 0xBA81A048, 0xBA81BFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA81C15C, 0xBA81DFFC } // size 7844 (7 kB) (0 MB) +// { 0xBA81E1F8, 0xBA81EFFC } // size 3592 (3 kB) (0 MB) +// { 0xBA820780, 0xBA820FFC } // size 2176 (2 kB) (0 MB) +// { 0xBA821028, 0xBA8221FC } // size 4568 (4 kB) (0 MB) +// { 0xBA824610, 0xBA825FFC } // size 6640 (6 kB) (0 MB) +// { 0xBA8677DC, 0xBA867FF8 } // size 2080 (2 kB) (0 MB) +// { 0xBA868048, 0xBA869FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA86A0D4, 0xBA86AFFC } // size 3884 (3 kB) (0 MB) +// { 0xBA86C240, 0xBA86D3FC } // size 4544 (4 kB) (0 MB) +// { 0xBA86F01C, 0xBA8703FC } // size 5092 (4 kB) (0 MB) +// { 0xBA87123C, 0xBA871FF8 } // size 3520 (3 kB) (0 MB) +// { 0xBA872048, 0xBA873FFC } // size 8120 (7 kB) (0 MB) +// { 0xBA87419C, 0xBA875FFC } // size 7780 (7 kB) (0 MB) +// { 0xBA878028, 0xBA87A3FC } // size 9176 (8 kB) (0 MB) +// { 0xBA87C20C, 0xBA87DFFC } // size 7668 (7 kB) (0 MB) +// { 0xBA880028, 0xBA881FFC } // size 8152 (7 kB) (0 MB) +// { 0xBA884BDC, 0xBA885FF8 } // size 5152 (5 kB) (0 MB) +// { 0xBA886044, 0xBA887FFC } // size 8124 (7 kB) (0 MB) +// { 0xBA88861C, 0xBA889FF8 } // size 6624 (6 kB) (0 MB) +// { 0xBA88A048, 0xBA88BFFC } // size 8120 (7 kB) (0 MB) +// { 0xBA88C75C, 0xBA88DFF8 } // size 6304 (6 kB) (0 MB) +// { 0xBA88E050, 0xBA88FFFC } // size 8112 (7 kB) (0 MB) +// { 0xBA890080, 0xBA890FFC } // size 3968 (3 kB) (0 MB) +// { 0xBA895528, 0xBA8CCA24 } // size 226560 (221 kB) (0 MB) +// { 0xBAA4E9DC, 0xBAA4FFF8 } // size 5664 (5 kB) (0 MB) +// { 0xBAA50048, 0xBAA51FFC } // size 8120 (7 kB) (0 MB) +// { 0xBAA5285C, 0xBAA53FF8 } // size 6048 (5 kB) (0 MB) +// { 0xBAA54044, 0xBAA55FFC } // size 8124 (7 kB) (0 MB) +// { 0xBAA56114, 0xBAA57FFC } // size 7916 (7 kB) (0 MB) +// { 0xBAA589E0, 0xBAA593FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA5ABE0, 0xBAA5B5FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA5C9E0, 0xBAA5D3FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA5EBE0, 0xBAA5F5FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA609E0, 0xBAA613FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA62BE0, 0xBAA635FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA649E0, 0xBAA653FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA66BE0, 0xBAA675FC } // size 2592 (2 kB) (0 MB) +// { 0xBAA69308, 0xBAA69FFC } // size 3320 (3 kB) (0 MB) +// { 0xBAA6E374, 0xBAA6F1FC } // size 3724 (3 kB) (0 MB) +// { 0xBAA6FB98, 0xBAA705FC } // size 2664 (2 kB) (0 MB) +// { 0xBAA71998, 0xBAA723FC } // size 2664 (2 kB) (0 MB) +// { 0xBAA908BC, 0xBAA91FF8 } // size 5952 (5 kB) (0 MB) +// { 0xBAA92048, 0xBAA93FFC } // size 8120 (7 kB) (0 MB) +// { 0xBAA94384, 0xBAA95FFC } // size 7292 (7 kB) (0 MB) +// { 0xBAA9E028, 0xBAA9EFFC } // size 4056 (3 kB) (0 MB) +// { 0xBAAA1284, 0xBAAA1FFC } // size 3452 (3 kB) (0 MB) +// { 0xBAAA4154, 0xBAAA51FC } // size 4268 (4 kB) (0 MB) +// { 0xBAAA52C0, 0xBAAA5FFC } // size 3392 (3 kB) (0 MB) +// { 0xBAAA6028, 0xBAAA7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAAAD27C, 0xBAAAE1FC } // size 3972 (3 kB) (0 MB) +// { 0xBAAB22A4, 0xBAAB2FFC } // size 3420 (3 kB) (0 MB) +// { 0xBAAB5028, 0xBAAB5FFC } // size 4056 (3 kB) (0 MB) +// { 0xBAACA828, 0xBAACBFFC } // size 6104 (5 kB) (0 MB) +// { 0xBAAD0028, 0xBAAD1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAAD628C, 0xBAAD81FC } // size 8052 (7 kB) (0 MB) +// { 0xBAADC028, 0xBAADDFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAAE223C, 0xBAAE3FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBAAE4050, 0xBAAE5FFC } // size 8112 (7 kB) (0 MB) +// { 0xBAAE699C, 0xBAAE7FF8 } // size 5728 (5 kB) (0 MB) +// { 0xBAAE804C, 0xBAAE9FFC } // size 8116 (7 kB) (0 MB) +// { 0xBAAEB31C, 0xBAAEBFF8 } // size 3296 (3 kB) (0 MB) +// { 0xBAAEC050, 0xBAAEDFFC } // size 8112 (7 kB) (0 MB) +// { 0xBAAF8058, 0xBAAF9FFC } // size 8104 (7 kB) (0 MB) +// { 0xBAAFAC9C, 0xBAAFBFF8 } // size 4960 (4 kB) (0 MB) +// { 0xBAAFC054, 0xBAAFDFFC } // size 8108 (7 kB) (0 MB) +// { 0xBAAFE1E4, 0xBAB001FC } // size 8220 (8 kB) (0 MB) +// { 0xBAB04028, 0xBAB051FC } // size 4568 (4 kB) (0 MB) +// { 0xBAB052C0, 0xBAB05FFC } // size 3392 (3 kB) (0 MB) +// { 0xBAB06028, 0xBAB07FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB26028, 0xBAB27FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB2E828, 0xBAB301FC } // size 6616 (6 kB) (0 MB) +// { 0xBAB34028, 0xBAB35FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB3EC5C, 0xBAB3FFF8 } // size 5024 (4 kB) (0 MB) +// { 0xBAB40048, 0xBAB41FFC } // size 8120 (7 kB) (0 MB) +// { 0xBAB420A8, 0xBAB42FFC } // size 3928 (3 kB) (0 MB) +// { 0xBAB43304, 0xBAB43FFC } // size 3324 (3 kB) (0 MB) +// { 0xBAB45780, 0xBAB45FFC } // size 2176 (2 kB) (0 MB) +// { 0xBAB4623C, 0xBAB47FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBAB4804C, 0xBAB49FFC } // size 8116 (7 kB) (0 MB) +// { 0xBAB4A360, 0xBAB4BFFC } // size 7328 (7 kB) (0 MB) +// { 0xBAB4C64C, 0xBAB4CFFC } // size 2484 (2 kB) (0 MB) +// { 0xBAB55028, 0xBAB55FFC } // size 4056 (3 kB) (0 MB) +// { 0xBAB5A028, 0xBAB5B1FC } // size 4568 (4 kB) (0 MB) +// { 0xBAB5B2C0, 0xBAB5BFFC } // size 3392 (3 kB) (0 MB) +// { 0xBAB5C028, 0xBAB5E1FC } // size 8664 (8 kB) (0 MB) +// { 0xBAB60710, 0xBAB61FFC } // size 6384 (6 kB) (0 MB) +// { 0xBAB62028, 0xBAB63FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB666F0, 0xBAB67FFC } // size 6416 (6 kB) (0 MB) +// { 0xBAB68028, 0xBAB69FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB6C510, 0xBAB6DFFC } // size 6896 (6 kB) (0 MB) +// { 0xBAB6E168, 0xBAB6FFFC } // size 7832 (7 kB) (0 MB) +// { 0xBAB727F0, 0xBAB73FFC } // size 6160 (6 kB) (0 MB) +// { 0xBAB7518C, 0xBAB75FFC } // size 3700 (3 kB) (0 MB) +// { 0xBAB78410, 0xBAB79FFC } // size 7152 (6 kB) (0 MB) +// { 0xBAB7A604, 0xBAB7C1FC } // size 7164 (6 kB) (0 MB) +// { 0xBAB7E610, 0xBAB7FFFC } // size 6640 (6 kB) (0 MB) +// { 0xBAB80C6C, 0xBAB821FC } // size 5524 (5 kB) (0 MB) +// { 0xBAB84028, 0xBAB85FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB88510, 0xBAB89FFC } // size 6896 (6 kB) (0 MB) +// { 0xBAB8A028, 0xBAB8BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAB8E7F0, 0xBAB8FFFC } // size 6160 (6 kB) (0 MB) +// { 0xBAB9085C, 0xBAB91FF8 } // size 6048 (5 kB) (0 MB) +// { 0xBAB92044, 0xBAB93FFC } // size 8124 (7 kB) (0 MB) +// { 0xBAB96D1C, 0xBAB97FF8 } // size 4832 (4 kB) (0 MB) +// { 0xBAB9804C, 0xBAB99FFC } // size 8116 (7 kB) (0 MB) +// { 0xBAB9AA1C, 0xBAB9BFF8 } // size 5600 (5 kB) (0 MB) +// { 0xBAB9C048, 0xBAB9DFFC } // size 8120 (7 kB) (0 MB) +// { 0xBAB9E1A0, 0xBAB9EFFC } // size 3680 (3 kB) (0 MB) +// { 0xBABBA6BC, 0xBABBBFF8 } // size 6464 (6 kB) (0 MB) +// { 0xBABBC048, 0xBABBDFFC } // size 8120 (7 kB) (0 MB) +// { 0xBABBE078, 0xBABBEFFC } // size 3976 (3 kB) (0 MB) +// { 0xBABC0C4C, 0xBACB9588 } // size 1018176 (994 kB) (0 MB) +// { 0xBACE89C8, 0xBACE9FF8 } // size 5684 (5 kB) (0 MB) +// { 0xBACEA050, 0xBACEBFFC } // size 8112 (7 kB) (0 MB) +// { 0xBACEC088, 0xBACEDFFC } // size 8056 (7 kB) (0 MB) +// { 0xBACEE330, 0xBACF01FC } // size 7888 (7 kB) (0 MB) +// { 0xBACF423C, 0xBACF5FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBACF6048, 0xBACF7FFC } // size 8120 (7 kB) (0 MB) +// { 0xBACF833C, 0xBACF9FFC } // size 7364 (7 kB) (0 MB) +// { 0xBACFA1E8, 0xBACFBFFC } // size 7704 (7 kB) (0 MB) +// { 0xBAD00028, 0xBAD01FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD06028, 0xBAD07FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD0C028, 0xBAD0DFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD12028, 0xBAD12FFC } // size 4056 (3 kB) (0 MB) +// { 0xBAD19798, 0xBAD19FFC } // size 2152 (2 kB) (0 MB) +// { 0xBAD22028, 0xBAD23FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD28028, 0xBAD29FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD2E028, 0xBAD2FFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD34028, 0xBAD35FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD3A028, 0xBAD3BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD4023C, 0xBAD41FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBAD42044, 0xBAD43FFC } // size 8124 (7 kB) (0 MB) +// { 0xBAD44100, 0xBAD45FFC } // size 7936 (7 kB) (0 MB) +// { 0xBAD46620, 0xBAD47FFC } // size 6624 (6 kB) (0 MB) +// { 0xBAD54800, 0xBAD55FFC } // size 6144 (6 kB) (0 MB) +// { 0xBAD56440, 0xBAD57FFC } // size 7104 (6 kB) (0 MB) +// { 0xBAD5841C, 0xBAD59FF8 } // size 7136 (6 kB) (0 MB) +// { 0xBAD5A048, 0xBAD5BFFC } // size 8120 (7 kB) (0 MB) +// { 0xBAD5C38C, 0xBAD5DFFC } // size 7284 (7 kB) (0 MB) +// { 0xBAD62028, 0xBAD63FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD68028, 0xBAD69FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD6E028, 0xBAD6F1FC } // size 4568 (4 kB) (0 MB) +// { 0xBAD6F2C0, 0xBAD6FFFC } // size 3392 (3 kB) (0 MB) +// { 0xBAD70028, 0xBAD71FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD76028, 0xBAD77FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD7C028, 0xBAD7DFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAD81828, 0xBAD82074 } // size 2128 (2 kB) (0 MB) +// { 0xBAD8C028, 0xBAD8C908 } // size 2276 (2 kB) (0 MB) +// { 0xBAD8E028, 0xBAD8EFFC } // size 4056 (3 kB) (0 MB) +// { 0xBADA0028, 0xBADA1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBADA6028, 0xBADA7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBADAC028, 0xBADAE1FC } // size 8664 (8 kB) (0 MB) +// { 0xBADB0528, 0xBADB21FC } // size 7384 (7 kB) (0 MB) +// { 0xBADB6028, 0xBADB7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBADBC23C, 0xBADBDFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBADBE04C, 0xBADBFFFC } // size 8116 (7 kB) (0 MB) +// { 0xBADC019C, 0xBADC1FFC } // size 7780 (7 kB) (0 MB) +// { 0xBADC27B4, 0xBADC3FFC } // size 6220 (6 kB) (0 MB) +// { 0xBADC82F8, 0xBADC9FFC } // size 7432 (7 kB) (0 MB) +// { 0xBADD2F00, 0xBADD44FC } // size 5632 (5 kB) (0 MB) +// { 0xBADD4D80, 0xBADD5FFC } // size 4736 (4 kB) (0 MB) +// { 0xBADD6028, 0xBADD6FFC } // size 4056 (3 kB) (0 MB) +// { 0xBADE0028, 0xBADE1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBADEA23C, 0xBADEBFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBADEC048, 0xBADEDFFC } // size 8120 (7 kB) (0 MB) +// { 0xBADEE6FC, 0xBADEFFF8 } // size 6400 (6 kB) (0 MB) +// { 0xBADF0050, 0xBADF1FFC } // size 8112 (7 kB) (0 MB) +// { 0xBADFAF7C, 0xBADFBFF8 } // size 4224 (4 kB) (0 MB) +// { 0xBADFC048, 0xBADFDFFC } // size 8120 (7 kB) (0 MB) +// { 0xBADFE274, 0xBADFFFFC } // size 7564 (7 kB) (0 MB) +// { 0xBAE001B8, 0xBAE01FFC } // size 7752 (7 kB) (0 MB) +// { 0xBAE0E1F8, 0xBAE0FFFC } // size 7688 (7 kB) (0 MB) +// { 0xBAE347EC, 0xBAE35020 } // size 2104 (2 kB) (0 MB) +// { 0xBAE35F40, 0xBAE36FFC } // size 4288 (4 kB) (0 MB) +// { 0xBAE3723C, 0xBAE37FF8 } // size 3520 (3 kB) (0 MB) +// { 0xBAE3804C, 0xBAE39FFC } // size 8116 (7 kB) (0 MB) +// { 0xBAF04028, 0xBAF04864 } // size 2112 (2 kB) (0 MB) +// { 0xBAF18048, 0xBAF19FFC } // size 8120 (7 kB) (0 MB) +// { 0xBAF1E71C, 0xBAF1FFF8 } // size 6368 (6 kB) (0 MB) +// { 0xBAF20044, 0xBAF21FFC } // size 8124 (7 kB) (0 MB) +// { 0xBAF226E0, 0xBAF23FFC } // size 6432 (6 kB) (0 MB) +// { 0xBAF40798, 0xBAF42FFC } // size 10344 (10 kB) (0 MB) +// { 0xBAF43028, 0xBAF43FFC } // size 4056 (3 kB) (0 MB) +// { 0xBAF66FEC, 0xBAF697FC } // size 10260 (10 kB) (0 MB) +// { 0xBAF69828, 0xBAF6A224 } // size 2560 (2 kB) (0 MB) +// { 0xBAF6AF40, 0xBAF6B7FC } // size 2240 (2 kB) (0 MB) +// { 0xBAF7A028, 0xBAF7BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAF94E98, 0xBAF95908 } // size 2676 (2 kB) (0 MB) +// { 0xBAF96D44, 0xBAF977FC } // size 2748 (2 kB) (0 MB) +// { 0xBAFA4028, 0xBAFA4FFC } // size 4056 (3 kB) (0 MB) +// { 0xBAFA6800, 0xBAFA7338 } // size 2876 (2 kB) (0 MB) +// { 0xBAFBAE14, 0xBAFBBDFC } // size 4076 (3 kB) (0 MB) +// { 0xBAFBC904, 0xBAFBD7FC } // size 3836 (3 kB) (0 MB) +// { 0xBAFCA028, 0xBAFCBFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAFD8028, 0xBAFD9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBAFE6028, 0xBAFE6874 } // size 2128 (2 kB) (0 MB) +// { 0xBAFE8028, 0xBAFE8838 } // size 2068 (2 kB) (0 MB) +// { 0xBAFE9340, 0xBAFE9FFC } // size 3264 (3 kB) (0 MB) +// { 0xBAFEA028, 0xBAFEA908 } // size 2276 (2 kB) (0 MB) +// { 0xBAFEC028, 0xBAFEDFFC } // size 8152 (7 kB) (0 MB) +// { 0xBAFFA028, 0xBAFFBFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB008028, 0xBB009FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB016028, 0xBB017FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB024028, 0xBB025FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB028028, 0xBB029FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB037634, 0xBB037FFC } // size 2508 (2 kB) (0 MB) +// { 0xBB038028, 0xBB039FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB046028, 0xBB047FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB054028, 0xBB0548B8 } // size 2196 (2 kB) (0 MB) +// { 0xBB06A800, 0xBB06BBFC } // size 5120 (5 kB) (0 MB) +// { 0xBB06CB28, 0xBB06D7FC } // size 3288 (3 kB) (0 MB) +// { 0xBB090FEC, 0xBB091820 } // size 2104 (2 kB) (0 MB) +// { 0xBB092740, 0xBB0937FC } // size 4288 (4 kB) (0 MB) +// { 0xBB095724, 0xBB095FFC } // size 2268 (2 kB) (0 MB) +// { 0xBB096028, 0xBB097FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB0A423C, 0xBB0A5FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB0A6044, 0xBB0A7FFC } // size 8124 (7 kB) (0 MB) +// { 0xBB0AAF3C, 0xBB0ABFF8 } // size 4288 (4 kB) (0 MB) +// { 0xBB0AC04C, 0xBB0ADFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB0AE1A0, 0xBB0B01FC } // size 8288 (8 kB) (0 MB) +// { 0xBB0C490C, 0xBB0C5FFC } // size 5876 (5 kB) (0 MB) +// { 0xBB0C87F0, 0xBB0C9FFC } // size 6160 (6 kB) (0 MB) +// { 0xBB0CD23C, 0xBB0CDFF8 } // size 3520 (3 kB) (0 MB) +// { 0xBB0CE04C, 0xBB0CFFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB0D0350, 0xBB0D1FFC } // size 7344 (7 kB) (0 MB) +// { 0xBB0D29E0, 0xBB0D33FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0D4BE0, 0xBB0D55FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0D69E0, 0xBB0D73FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0D8BE0, 0xBB0D95FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0DA9E0, 0xBB0DB3FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0DCBE0, 0xBB0DD5FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0DE9E0, 0xBB0DF3FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0E0BE0, 0xBB0E15FC } // size 2592 (2 kB) (0 MB) +// { 0xBB0E3028, 0xBB0E3FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB164828, 0xBB1651FC } // size 2520 (2 kB) (0 MB) +// { 0xBB165B98, 0xBB1665FC } // size 2664 (2 kB) (0 MB) +// { 0xBB167998, 0xBB1683FC } // size 2664 (2 kB) (0 MB) +// { 0xBB17E028, 0xBB17EFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB18123C, 0xBB181FF8 } // size 3520 (3 kB) (0 MB) +// { 0xBB18204C, 0xBB183FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB18804C, 0xBB189FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB18A278, 0xBB18BFFC } // size 7560 (7 kB) (0 MB) +// { 0xBB19F468, 0xBB1A03FC } // size 3992 (3 kB) (0 MB) +// { 0xBB1A1028, 0xBB1A1FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB1B2A3C, 0xBB1B3FF8 } // size 5568 (5 kB) (0 MB) +// { 0xBB1B404C, 0xBB1B5FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB1B6354, 0xBB1B7FFC } // size 7340 (7 kB) (0 MB) +// { 0xBB1B89E0, 0xBB1B93FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1BABE0, 0xBB1BB5FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1BC9E0, 0xBB1BD3FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1BEBE0, 0xBB1BF5FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1C09E0, 0xBB1C13FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1C2BE0, 0xBB1C35FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1C49E0, 0xBB1C53FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1C6BE0, 0xBB1C75FC } // size 2592 (2 kB) (0 MB) +// { 0xBB1C9028, 0xBB1C9FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB24A028, 0xBB24B1FC } // size 4568 (4 kB) (0 MB) +// { 0xBB24BB98, 0xBB24C5FC } // size 2664 (2 kB) (0 MB) +// { 0xBB24D998, 0xBB24E3FC } // size 2664 (2 kB) (0 MB) +// { 0xBB26723C, 0xBB267FF8 } // size 3520 (3 kB) (0 MB) +// { 0xBB268048, 0xBB269FFC } // size 8120 (7 kB) (0 MB) +// { 0xBB26A4E4, 0xBB26BFFC } // size 6940 (6 kB) (0 MB) +// { 0xBB293028, 0xBB293FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB29C7E8, 0xBB29DFFC } // size 6168 (6 kB) (0 MB) +// { 0xBB29E008, 0xBB29FFFC } // size 8184 (7 kB) (0 MB) +// { 0xBB2FC828, 0xBB2FDFFC } // size 6104 (5 kB) (0 MB) +// { 0xBB330828, 0xBB331FFC } // size 6104 (5 kB) (0 MB) +// { 0xBB33A6E8, 0xBB33C1FC } // size 6936 (6 kB) (0 MB) +// { 0xBB33C208, 0xBB33DFFC } // size 7672 (7 kB) (0 MB) +// { 0xBB35F828, 0xBB360064 } // size 2112 (2 kB) (0 MB) +// { 0xBB362028, 0xBB362864 } // size 2112 (2 kB) (0 MB) +// { 0xBB37E7E8, 0xBB3802FC } // size 6936 (6 kB) (0 MB) +// { 0xBB380308, 0xBB381FFC } // size 7416 (7 kB) (0 MB) +// { 0xBB382028, 0xBB383FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB390028, 0xBB3924FC } // size 9432 (9 kB) (0 MB) +// { 0xBB394694, 0xBB3953FC } // size 3436 (3 kB) (0 MB) +// { 0xBB39A028, 0xBB39BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB3A47E8, 0xBB3A5FFC } // size 6168 (6 kB) (0 MB) +// { 0xBB3A6008, 0xBB3A7FFC } // size 8184 (7 kB) (0 MB) +// { 0xBB3A95FC, 0xBB3A9FF8 } // size 2560 (2 kB) (0 MB) +// { 0xBB3AA04C, 0xBB3ABFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB3AC108, 0xBB3AE000 } // size 7932 (7 kB) (0 MB) +// { 0xBB3B2028, 0xBB3B42FC } // size 8920 (8 kB) (0 MB) +// { 0xBB3B5390, 0xBB3B5FFC } // size 3184 (3 kB) (0 MB) +// { 0xBB3B623C, 0xBB3B7FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB3B804C, 0xBB3B9FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB3BA33C, 0xBB3BBFFC } // size 7364 (7 kB) (0 MB) +// { 0xBB3BD028, 0xBB3BE828 } // size 6148 (6 kB) (0 MB) +// { 0xBB3C0000, 0xBB3C083C } // size 2112 (2 kB) (0 MB) +// { 0xBB3C0FC0, 0xBB3C17FC } // size 2112 (2 kB) (0 MB) +// { 0xBB3C2000, 0xBB3C2800 } // size 2052 (2 kB) (0 MB) +// { 0xBB3C3FFC, 0xBB3C48BC } // size 2244 (2 kB) (0 MB) +// { 0xBB3C4FA0, 0xBB3C67FC } // size 6240 (6 kB) (0 MB) +// { 0xBB3C6828, 0xBB3C71FC } // size 2520 (2 kB) (0 MB) +// { 0xBB3C72C0, 0xBB3C7FFC } // size 3392 (3 kB) (0 MB) +// { 0xBB3C8028, 0xBB3C9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB3FC2B8, 0xBB3FDFFC } // size 7496 (7 kB) (0 MB) +// { 0xBB4076F0, 0xBB4081FC } // size 2832 (2 kB) (0 MB) +// { 0xBB4096F0, 0xBB409FFC } // size 2320 (2 kB) (0 MB) +// { 0xBB40A028, 0xBB40BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB410028, 0xBB4121FC } // size 8664 (8 kB) (0 MB) +// { 0xBB414028, 0xBB4161FC } // size 8664 (8 kB) (0 MB) +// { 0xBB41A028, 0xBB41BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB42023C, 0xBB421FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB422050, 0xBB423FFC } // size 8112 (7 kB) (0 MB) +// { 0xBB49953C, 0xBB499FF8 } // size 2752 (2 kB) (0 MB) +// { 0xBB49A04C, 0xBB49BFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB49C2FC, 0xBB49DFFC } // size 7428 (7 kB) (0 MB) +// { 0xBB4AA394, 0xBB4ABFFC } // size 7276 (7 kB) (0 MB) +// { 0xBB4B8028, 0xBB4B9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB4C6A38, 0xBB4C7FFC } // size 5576 (5 kB) (0 MB) +// { 0xBB4D0F00, 0xBB4D24FC } // size 5632 (5 kB) (0 MB) +// { 0xBB4D2D80, 0xBB4D3FFC } // size 4736 (4 kB) (0 MB) +// { 0xBB4D4028, 0xBB4D4FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB4E004C, 0xBB4E1FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB4E2424, 0xBB4E3FFC } // size 7132 (6 kB) (0 MB) +// { 0xBB4E6028, 0xBB4E6FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB4E9028, 0xBB4EA1FC } // size 4568 (4 kB) (0 MB) +// { 0xBB4EA2C0, 0xBB4EAFFC } // size 3392 (3 kB) (0 MB) +// { 0xBB4EB028, 0xBB4EBFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB4F0028, 0xBB4F1FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB4F6028, 0xBB4F81FC } // size 8664 (8 kB) (0 MB) +// { 0xBB4FC028, 0xBB4FCFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB4FF028, 0xBB4FFFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB504028, 0xBB504FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB51ED24, 0xBB51FFFC } // size 4828 (4 kB) (0 MB) +// { 0xBB52499C, 0xBB525FFC } // size 5732 (5 kB) (0 MB) +// { 0xBB52A828, 0xBB52C1FC } // size 6616 (6 kB) (0 MB) +// { 0xBB530028, 0xBB531FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB536028, 0xBB537FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB53C23C, 0xBB53DFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB53E04C, 0xBB53FFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB54029C, 0xBB541FFC } // size 7524 (7 kB) (0 MB) +// { 0xBB54420C, 0xBB544FFC } // size 3572 (3 kB) (0 MB) +// { 0xBB547210, 0xBB5481FC } // size 4080 (3 kB) (0 MB) +// { 0xBB5482C0, 0xBB548FFC } // size 3392 (3 kB) (0 MB) +// { 0xBB549028, 0xBB549FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB54E254, 0xBB54EFFC } // size 3500 (3 kB) (0 MB) +// { 0xBB551028, 0xBB551FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB55A028, 0xBB55BFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB560FD4, 0xBB561FFC } // size 4140 (4 kB) (0 MB) +// { 0xBB566028, 0xBB5681FC } // size 8664 (8 kB) (0 MB) +// { 0xBB56C028, 0xBB56DFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB57223C, 0xBB573FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB57404C, 0xBB575FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB576450, 0xBB577FFC } // size 7088 (6 kB) (0 MB) +// { 0xBB578308, 0xBB578FFC } // size 3320 (3 kB) (0 MB) +// { 0xBB57F378, 0xBB5801FC } // size 3720 (3 kB) (0 MB) +// { 0xBB5802C0, 0xBB580FFC } // size 3392 (3 kB) (0 MB) +// { 0xBB581028, 0xBB581FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB586028, 0xBB587FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB58C028, 0xBB58E1FC } // size 8664 (8 kB) (0 MB) +// { 0xBB592334, 0xBB592FFC } // size 3276 (3 kB) (0 MB) +// { 0xBB59533C, 0xBB595FFC } // size 3268 (3 kB) (0 MB) +// { 0xBB59A028, 0xBB59AFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB5B8028, 0xBB5B9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB5C36F0, 0xBB5C41FC } // size 2832 (2 kB) (0 MB) +// { 0xBB5C56F0, 0xBB5C5FFC } // size 2320 (2 kB) (0 MB) +// { 0xBB5C6028, 0xBB5C7FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB5CC528, 0xBB5CE1FC } // size 7384 (7 kB) (0 MB) +// { 0xBB5D2028, 0xBB5D3FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB5D8028, 0xBB5D9FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB5DE23C, 0xBB5DFFF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB5E0054, 0xBB5E1FFC } // size 8108 (7 kB) (0 MB) +// { 0xBB5E2220, 0xBB5E3FFC } // size 7648 (7 kB) (0 MB) +// { 0xBB5E4390, 0xBB5E5FFC } // size 7280 (7 kB) (0 MB) +// { 0xBB5EA028, 0xBB5EA940 } // size 2332 (2 kB) (0 MB) +// { 0xBB630028, 0xBB6323FC } // size 9176 (8 kB) (0 MB) +// { 0xBB636050, 0xBB637FFC } // size 8112 (7 kB) (0 MB) +// { 0xBB63A828, 0xBB63B944 } // size 4384 (4 kB) (0 MB) +// { 0xBB64317C, 0xBB643FF8 } // size 3712 (3 kB) (0 MB) +// { 0xBB64404C, 0xBB645FFC } // size 8116 (7 kB) (0 MB) +// { 0xBB64644C, 0xBB647FFC } // size 7092 (6 kB) (0 MB) +// { 0xBB64A028, 0xBB64AFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB64D028, 0xBB64E1FC } // size 4568 (4 kB) (0 MB) +// { 0xBB64E2C0, 0xBB64EFFC } // size 3392 (3 kB) (0 MB) +// { 0xBB64F028, 0xBB64FFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB654028, 0xBB65683C } // size 10264 (10 kB) (0 MB) +// { 0xBB656FC0, 0xBB6577FC } // size 2112 (2 kB) (0 MB) +// { 0xBB658000, 0xBB658800 } // size 2052 (2 kB) (0 MB) +// { 0xBB658FFC, 0xBB6597FC } // size 2052 (2 kB) (0 MB) +// { 0xBB65A000, 0xBB65A93C } // size 2368 (2 kB) (0 MB) +// { 0xBB65AE98, 0xBB65D7FC } // size 10600 (10 kB) (0 MB) +// { 0xBB65EDE0, 0xBB65FFFC } // size 4640 (4 kB) (0 MB) +// { 0xBB664028, 0xBB6661FC } // size 8664 (8 kB) (0 MB) +// { 0xBB66A028, 0xBB66AFFC } // size 4056 (3 kB) (0 MB) +// { 0xBB66D640, 0xBB66DFFC } // size 2496 (2 kB) (0 MB) +// { 0xBB672028, 0xBB672FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB690028, 0xBB691FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB696834, 0xBB6981FC } // size 6604 (6 kB) (0 MB) +// { 0xBB69C028, 0xBB69DFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB6A233C, 0xBB6A3FFC } // size 7364 (7 kB) (0 MB) +// { 0xBB6A823C, 0xBB6A9FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB6AA04C, 0xBB6ABFFC } // size 8116 (7 kB) (0 MB) +// { 0xBB6AC424, 0xBB6ADFFC } // size 7132 (6 kB) (0 MB) +// { 0xBB6B0378, 0xBB6B0FFC } // size 3208 (3 kB) (0 MB) +// { 0xBB6B3028, 0xBB6B41FC } // size 4568 (4 kB) (0 MB) +// { 0xBB6B42C0, 0xBB6B4FFC } // size 3392 (3 kB) (0 MB) +// { 0xBB6B5028, 0xBB6B5FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB6BA028, 0xBB6BBFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB6C0028, 0xBB6C21FC } // size 8664 (8 kB) (0 MB) +// { 0xBB6C6028, 0xBB6C6FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB6CAB1C, 0xBB6CBFFC } // size 5348 (5 kB) (0 MB) +// { 0xBB6D0028, 0xBB6D0FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB6EE028, 0xBB6EFFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB6F4528, 0xBB6F61FC } // size 7384 (7 kB) (0 MB) +// { 0xBB6FA028, 0xBB6FBFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB700640, 0xBB701FFC } // size 6592 (6 kB) (0 MB) +// { 0xBB70623C, 0xBB707FF8 } // size 7616 (7 kB) (0 MB) +// { 0xBB708048, 0xBB709FFC } // size 8120 (7 kB) (0 MB) +// { 0xBB70A38C, 0xBB70BFFC } // size 7284 (7 kB) (0 MB) +// { 0xBB710028, 0xBB711FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB716028, 0xBB717FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB71C028, 0xBB71D1FC } // size 4568 (4 kB) (0 MB) +// { 0xBB71D2C0, 0xBB71DFFC } // size 3392 (3 kB) (0 MB) +// { 0xBB71E028, 0xBB71FFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB724028, 0xBB725FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB72B828, 0xBB72C074 } // size 2128 (2 kB) (0 MB) +// { 0xBB736028, 0xBB736908 } // size 2276 (2 kB) (0 MB) +// { 0xBB738028, 0xBB738FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB741028, 0xBB741FFC } // size 4056 (3 kB) (0 MB) +// { 0xBB748A74, 0xBB749FFC } // size 5516 (5 kB) (0 MB) +// { 0xBB74E028, 0xBB74FFFC } // size 8152 (7 kB) (0 MB) +// { 0xBB754028, 0xBB755FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB75A028, 0xBB75C1FC } // size 8664 (8 kB) (0 MB) +// { 0xBB75E528, 0xBB7601FC } // size 7384 (7 kB) (0 MB) +// { 0xBB764028, 0xBB765FFC } // size 8152 (7 kB) (0 MB) +// { 0xBB76EF88, 0xBB77EEB4 } // size 65328 (63 kB) (0 MB) +// { 0xBB77F7E0, 0xBB8477E4 } // size 819208 (800 kB) (0 MB) +// { 0xBB858010, 0xBB859FF8 } // size 8172 (7 kB) (0 MB) +// { 0xBB86A010, 0xBB86BFF8 } // size 8172 (7 kB) (0 MB) +// { 0xBB87C00C, 0xBB936CB8 } // size 765104 (747 kB) (0 MB) +// { 0xBB936D8C, 0xBB94918C } // size 74756 (73 kB) (0 MB) +// { 0xBB94919C, 0xBB94B18C } // size 8180 (7 kB) (0 MB) +// { 0xBB952414, 0xBB952EA0 } // size 2704 (2 kB) (0 MB) +// { 0xBB95310C, 0xBB953FAC } // size 3748 (3 kB) (0 MB) +// { 0xBB954078, 0xBB954FBC } // size 3912 (3 kB) (0 MB) +// { 0xBB954FC8, 0xBB955FC4 } // size 4096 (4 kB) (0 MB) +// { 0xBB956010, 0xBB95700C } // size 4096 (4 kB) (0 MB) +// { 0xBB9570B8, 0xBB95801C } // size 3944 (3 kB) (0 MB) +// { 0xBB958030, 0xBB959028 } // size 4092 (3 kB) (0 MB) +// { 0xBB95904C, 0xBB95A030 } // size 4072 (3 kB) (0 MB) +// { 0xBB95A080, 0xBB95B054 } // size 4056 (3 kB) (0 MB) +// { 0xBB95B388, 0xBB95C35C } // size 4056 (3 kB) (0 MB) +// { 0xBB95C670, 0xBB95D670 } // size 4100 (4 kB) (0 MB) +// { 0xBB95D67C, 0xBB95E678 } // size 4096 (4 kB) (0 MB) +// { 0xBB95E694, 0xBB95F688 } // size 4088 (3 kB) (0 MB) +// { 0xBB95F698, 0xBB960694 } // size 4096 (4 kB) (0 MB) +// { 0xBB9606A0, 0xBB9616A0 } // size 4100 (4 kB) (0 MB) +// { 0xBB9616C4, 0xBB9626A8 } // size 4072 (3 kB) (0 MB) +// { 0xBB9626C0, 0xBB9636B8 } // size 4092 (3 kB) (0 MB) +// { 0xBB9636C4, 0xBB9646C4 } // size 4100 (4 kB) (0 MB) +// { 0xBB9646D0, 0xBB9656D0 } // size 4100 (4 kB) (0 MB) +// { 0xBB9656DC, 0xBB9666DC } // size 4100 (4 kB) (0 MB) +// { 0xBB9666E8, 0xBB9676E4 } // size 4096 (4 kB) (0 MB) +// { 0xBB967704, 0xBB968704 } // size 4100 (4 kB) (0 MB) +// { 0xBB968710, 0xBB96970C } // size 4096 (4 kB) (0 MB) +// { 0xBB969728, 0xBB96A71C } // size 4088 (3 kB) (0 MB) +// { 0xBB96A72C, 0xBB96B728 } // size 4096 (4 kB) (0 MB) +// { 0xBB96B734, 0xBB96C734 } // size 4100 (4 kB) (0 MB) +// { 0xBB96C758, 0xBB96D73C } // size 4072 (3 kB) (0 MB) +// { 0xBB96D754, 0xBB96E74C } // size 4092 (3 kB) (0 MB) +// { 0xBB96E758, 0xBB96F758 } // size 4100 (4 kB) (0 MB) +// { 0xBB96F764, 0xBB970764 } // size 4100 (4 kB) (0 MB) +// { 0xBB970770, 0xBB971770 } // size 4100 (4 kB) (0 MB) +// { 0xBB97177C, 0xBB972778 } // size 4096 (4 kB) (0 MB) +// { 0xBB97ED38, 0xBB97FFF8 } // size 4804 (4 kB) (0 MB) +// { 0xBB980000, 0xBB990028 } // size 65580 (64 kB) (0 MB) +// { 0xBB9936D0, 0xBB993FF8 } // size 2348 (2 kB) (0 MB) +// { 0xBB994000, 0xBB9A4028 } // size 65580 (64 kB) (0 MB) +// { 0xBB9A8D8C, 0xBB9B8CBC } // size 65332 (63 kB) (0 MB) +// { 0xBB9B9528, 0xBB9C90F4 } // size 64464 (62 kB) (0 MB) +// { 0xBB9C9F0C, 0xBB9CB1BC } // size 4788 (4 kB) (0 MB) +// { 0xBB9CB1E4, 0xBB9DB114 } // size 65332 (63 kB) (0 MB) +// { 0xBB9DD3EC, 0xBB9ED15C } // size 64884 (63 kB) (0 MB) +// { 0xBB9EDAFC, 0xBB9F1AFC } // size 16388 (16 kB) (0 MB) +// { 0xBB9F1B40, 0xBB9F5B3C } // size 16384 (16 kB) (0 MB) +// { 0xBB9FAF24, 0xBBA00B74 } // size 23636 (23 kB) (0 MB) +// { 0xBBA00BC0, 0xBBA0EBC0 } // size 57348 (56 kB) (0 MB) +// { 0xBBA0FE1C, 0xBBA1CBBC } // size 52644 (51 kB) (0 MB) +// { 0xBBA1D144, 0xBBA1DCF0 } // size 2992 (2 kB) (0 MB) +// { 0xBBA1DD40, 0xBBA1FCBC } // size 8064 (7 kB) (0 MB) +// { 0xBBA2057C, 0xBBA21C3C } // size 5828 (5 kB) (0 MB) +// { 0xBBA22438, 0xBBA251E8 } // size 11700 (11 kB) (0 MB) +// { 0xBBA25200, 0xBBA2C1FC } // size 28672 (28 kB) (0 MB) +// { 0xBBA2C7AC, 0xBBA331FC } // size 27220 (26 kB) (0 MB) +// { 0xBBA350C8, 0xBBA3678C } // size 5832 (5 kB) (0 MB) +// { 0xBBA367C0, 0xBBA3A17C } // size 14784 (14 kB) (0 MB) +// { 0xBBA3AB1C, 0xBBA3DB3C } // size 12324 (12 kB) (0 MB) +// { 0xBBA40640, 0xBBA4120C } // size 3024 (2 kB) (0 MB) +// { 0xBBA414AC, 0xBBA41DDC } // size 2356 (2 kB) (0 MB) +// { 0xBBA44700, 0xBBA456C0 } // size 4036 (3 kB) (0 MB) +// { 0xBBA45BFC, 0xBBA4667C } // size 2692 (2 kB) (0 MB) +// { 0xBBA48290, 0xBBA48A90 } // size 2052 (2 kB) (0 MB) +// { 0xBBA722AC, 0xBBA821DC } // size 65332 (63 kB) (0 MB) +// { 0xBBA84708, 0xBBA8A0E8 } // size 23012 (22 kB) (0 MB) +// { 0xBBA8A100, 0xBBA980FC } // size 57344 (56 kB) (0 MB) +// { 0xBBA99EBC, 0xBBAA60FC } // size 49732 (48 kB) (0 MB) +// { 0xBBAAC960, 0xBBAB0480 } // size 15140 (14 kB) (0 MB) +// { 0xBBAB04C0, 0xBBABE4BC } // size 57344 (56 kB) (0 MB) +// { 0xBBAC3B5C, 0xBBACC4BC } // size 35172 (34 kB) (0 MB) +// { 0xBBACFBFC, 0xBBAD0D0C } // size 4372 (4 kB) (0 MB) +// { 0xBBAD0DEC, 0xBBAD1E1C } // size 4148 (4 kB) (0 MB) +// { 0xBBAD4434, 0xBBAD6920 } // size 9456 (9 kB) (0 MB) +// { 0xBBAD6940, 0xBBAE025C } // size 39200 (38 kB) (0 MB) +// { 0xBBAE45BC, 0xBBAE9B7C } // size 21956 (21 kB) (0 MB) +// { 0xBBAED0CC, 0xBBAEF5B8 } // size 9456 (9 kB) (0 MB) +// { 0xBBAEF600, 0xBBAF8F1C } // size 39200 (38 kB) (0 MB) +// { 0xBBAFD27C, 0xBBB0283C } // size 21956 (21 kB) (0 MB) +// { 0xBBB051BC, 0xBBB05D8C } // size 3028 (2 kB) (0 MB) +// { 0xBBB05EDC, 0xBBB0695C } // size 2692 (2 kB) (0 MB) +// { 0xBBB08900, 0xBBB094CC } // size 3024 (2 kB) (0 MB) +// { 0xBBB095AC, 0xBBB0A09C } // size 2804 (2 kB) (0 MB) +// { 0xBBB0D884, 0xBBB0F224 } // size 6564 (6 kB) (0 MB) +// { 0xBBB0F240, 0xBBB1623C } // size 28672 (28 kB) (0 MB) +// { 0xBBB196BC, 0xBBB1D23C } // size 15236 (14 kB) (0 MB) +// { 0xBBB212B4, 0xBBB22894 } // size 5604 (5 kB) (0 MB) +// { 0xBBB228C0, 0xBBB298BC } // size 28672 (28 kB) (0 MB) +// { 0xBBB2D5FC, 0xBBB308BC } // size 12996 (12 kB) (0 MB) +// { 0xBBB364A4, 0xBBB382CC } // size 7724 (7 kB) (0 MB) +// { 0xBBB38300, 0xBBB40EFC } // size 35840 (35 kB) (0 MB) +// { 0xBBB454FC, 0xBBB49AFC } // size 17924 (17 kB) (0 MB) +// { 0xBBB4E6E0, 0xBBB515BC } // size 12000 (11 kB) (0 MB) +// { 0xBBB515D4, 0xBBB52570 } // size 4000 (3 kB) (0 MB) +// { 0xBBB54F5C, 0xBBB5653C } // size 5604 (5 kB) (0 MB) +// { 0xBBB56580, 0xBBB5D57C } // size 28672 (28 kB) (0 MB) +// { 0xBBB612BC, 0xBBB6457C } // size 12996 (12 kB) (0 MB) +// { 0xBBB6A580, 0xBBB6B68C } // size 4368 (4 kB) (0 MB) +// { 0xBBB6B76C, 0xBBB6C79C } // size 4148 (4 kB) (0 MB) +// { 0xBBB70F3C, 0xBBB7251C } // size 5604 (5 kB) (0 MB) +// { 0xBBB72540, 0xBBB7953C } // size 28672 (28 kB) (0 MB) +// { 0xBBB7D27C, 0xBBB8053C } // size 12996 (12 kB) (0 MB) +// { 0xBBB83680, 0xBBB8424C } // size 3024 (2 kB) (0 MB) +// { 0xBBB8439C, 0xBBB84E1C } // size 2692 (2 kB) (0 MB) +// { 0xBBB86DC0, 0xBBB8798C } // size 3024 (2 kB) (0 MB) +// { 0xBBB87A6C, 0xBBB8855C } // size 2804 (2 kB) (0 MB) +// { 0xBBB8FD08, 0xBBB916A8 } // size 6564 (6 kB) (0 MB) +// { 0xBBB916C0, 0xBBB986BC } // size 28672 (28 kB) (0 MB) +// { 0xBBB9BB3C, 0xBBB9F6BC } // size 15236 (14 kB) (0 MB) +// { 0xBBBA2280, 0xBBBA338C } // size 4368 (4 kB) (0 MB) +// { 0xBBBA377C, 0xBBBA449C } // size 3364 (3 kB) (0 MB) +// { 0xBBBAA238, 0xBBBABBD8 } // size 6564 (6 kB) (0 MB) +// { 0xBBBABC00, 0xBBBB2BFC } // size 28672 (28 kB) (0 MB) +// { 0xBBBB607C, 0xBBBB9BFC } // size 15236 (14 kB) (0 MB) +// { 0xBBBBD380, 0xBBBBDF4C } // size 3024 (2 kB) (0 MB) +// { 0xBBBC1230, 0xBBBC1D6C } // size 2880 (2 kB) (0 MB) +// { 0xBBBC1D7C, 0xBBBC4F5C } // size 12772 (12 kB) (0 MB) +// { 0xBBBC74F8, 0xBBBCA22C } // size 11576 (11 kB) (0 MB) +// { 0xBBBCA23C, 0xBBBD513C } // size 44804 (43 kB) (0 MB) +// { 0xBBBD973C, 0xBBBE003C } // size 26884 (26 kB) (0 MB) +// { 0xBBBE1658, 0xBBBE2194 } // size 2880 (2 kB) (0 MB) +// { 0xBBBE21C0, 0xBBBE539C } // size 12768 (12 kB) (0 MB) +// { 0xBBBE8000, 0xBBBE8FBC } // size 4032 (3 kB) (0 MB) +// { 0xBBBE909C, 0xBBBE9F7C } // size 3812 (3 kB) (0 MB) +// { 0xBBBEBE78, 0xBBBED818 } // size 6564 (6 kB) (0 MB) +// { 0xBBBED840, 0xBBBF483C } // size 28672 (28 kB) (0 MB) +// { 0xBBBF7CBC, 0xBBBFB83C } // size 15236 (14 kB) (0 MB) +// { 0xBBBFD970, 0xBBC00750 } // size 11748 (11 kB) (0 MB) +// { 0xBBC00780, 0xBBC0777C } // size 28672 (28 kB) (0 MB) +// { 0xBBC07CBC, 0xBBC0E77C } // size 27332 (26 kB) (0 MB) +// { 0xBBC10478, 0xBBC11E18 } // size 6564 (6 kB) (0 MB) +// { 0xBBC11E40, 0xBBC18E3C } // size 28672 (28 kB) (0 MB) +// { 0xBBC1C2BC, 0xBBC1FE3C } // size 15236 (14 kB) (0 MB) +// { 0xBBC227BC, 0xBBC2338C } // size 3028 (2 kB) (0 MB) +// { 0xBBC234DC, 0xBBC23F5C } // size 2692 (2 kB) (0 MB) +// { 0xBBC25F00, 0xBBC26ACC } // size 3024 (2 kB) (0 MB) +// { 0xBBC26BAC, 0xBBC2769C } // size 2804 (2 kB) (0 MB) +// { 0xBBC2B3EC, 0xBBC2D0C4 } // size 7388 (7 kB) (0 MB) +// { 0xBBC2D100, 0xBBC3543C } // size 33600 (32 kB) (0 MB) +// { 0xBBC3948C, 0xBBC3D77C } // size 17140 (16 kB) (0 MB) +// { 0xBBC3E9D4, 0xBBC3F510 } // size 2880 (2 kB) (0 MB) +// { 0xBBC3F540, 0xBBC4271C } // size 12768 (12 kB) (0 MB) +// { 0xBBC49440, 0xBBC4AA20 } // size 5604 (5 kB) (0 MB) +// { 0xBBC4AA40, 0xBBC51A3C } // size 28672 (28 kB) (0 MB) +// { 0xBBC5577C, 0xBBC58A3C } // size 12996 (12 kB) (0 MB) +// { 0xBBC59C94, 0xBBC5A7D0 } // size 2880 (2 kB) (0 MB) +// { 0xBBC5A800, 0xBBC5D9DC } // size 12768 (12 kB) (0 MB) +// { 0xBBC606C0, 0xBBC617CC } // size 4368 (4 kB) (0 MB) +// { 0xBBC618AC, 0xBBC628DC } // size 4148 (4 kB) (0 MB) +// { 0xBBC69AE4, 0xBBC6B364 } // size 6276 (6 kB) (0 MB) +// { 0xBBC6B380, 0xBBC7237C } // size 28672 (28 kB) (0 MB) +// { 0xBBC75A9C, 0xBBC7937C } // size 14564 (14 kB) (0 MB) +// { 0xBBC7C4C0, 0xBBC7D08C } // size 3024 (2 kB) (0 MB) +// { 0xBBC7D1DC, 0xBBC7DC5C } // size 2692 (2 kB) (0 MB) +// { 0xBBC7FC00, 0xBBC807CC } // size 3024 (2 kB) (0 MB) +// { 0xBBC808AC, 0xBBC8139C } // size 2804 (2 kB) (0 MB) +// { 0xBBC82144, 0xBBC82C80 } // size 2880 (2 kB) (0 MB) +// { 0xBBC82CC0, 0xBBC85E9C } // size 12768 (12 kB) (0 MB) +// { 0xBBC8E4C0, 0xBBC8F08C } // size 3024 (2 kB) (0 MB) +// { 0xBBC8F1DC, 0xBBC8FC5C } // size 2692 (2 kB) (0 MB) +// { 0xBBC91C00, 0xBBC927CC } // size 3024 (2 kB) (0 MB) +// { 0xBBC928AC, 0xBBC9339C } // size 2804 (2 kB) (0 MB) +// { 0xBBC94878, 0xBBC96C38 } // size 9156 (8 kB) (0 MB) +// { 0xBBC96C80, 0xBBC9DC7C } // size 28672 (28 kB) (0 MB) +// { 0xBBC9F95C, 0xBBCA4C7C } // size 21284 (20 kB) (0 MB) +// { 0xBBCA8FB0, 0xBBCABBB0 } // size 11268 (11 kB) (0 MB) +// { 0xBBCABC00, 0xBBCB2BFC } // size 28672 (28 kB) (0 MB) +// { 0xBBCB359C, 0xBBCB9BFC } // size 26212 (25 kB) (0 MB) +// { 0xBBCBBAF0, 0xBBCBE840 } // size 11604 (11 kB) (0 MB) +// { 0xBBCBE880, 0xBBCC587C } // size 28672 (28 kB) (0 MB) +// { 0xBBCC5F0C, 0xBBCCC87C } // size 26996 (26 kB) (0 MB) +// { 0xBBCCE0E8, 0xBBCD1078 } // size 12180 (11 kB) (0 MB) +// { 0xBBCD10C0, 0xBBCD80BC } // size 28672 (28 kB) (0 MB) +// { 0xBBCD820C, 0xBBCDF0BC } // size 28340 (27 kB) (0 MB) +// { 0xBBCE02FC, 0xBBCE307C } // size 11652 (11 kB) (0 MB) +// { 0xBBCE30C0, 0xBBCEA0BC } // size 28672 (28 kB) (0 MB) +// { 0xBBCEA6DC, 0xBBCF10BC } // size 27108 (26 kB) (0 MB) +// { 0xBBCF4750, 0xBBCF66F0 } // size 8100 (7 kB) (0 MB) +// { 0xBBCF6740, 0xBBCFD73C } // size 28672 (28 kB) (0 MB) +// { 0xBBCFFDBC, 0xBBD0473C } // size 18820 (18 kB) (0 MB) +// { 0xBBD07800, 0xBBD083CC } // size 3024 (2 kB) (0 MB) +// { 0xBBD0AF00, 0xBBD0BACC } // size 3024 (2 kB) (0 MB) +// { 0xBBD10FB8, 0xBBD11830 } // size 2172 (2 kB) (0 MB) +// { 0xBBD1205C, 0xBBD1301C } // size 4036 (3 kB) (0 MB) +// { 0xBBD137FC, 0xBBD147BC } // size 4036 (3 kB) (0 MB) +// { 0xBBD158AC, 0xBBD1640C } // size 2916 (2 kB) (0 MB) +// { 0xBBD169BC, 0xBBD1751C } // size 2916 (2 kB) (0 MB) +// { 0xBBD1EE0C, 0xBBD1FB9C } // size 3476 (3 kB) (0 MB) +// { 0xBBD2006C, 0xBBD20DFC } // size 3476 (3 kB) (0 MB) +// { 0xBBD2348C, 0xBBD2405C } // size 3028 (2 kB) (0 MB) +// { 0xBBD246EC, 0xBBD252BC } // size 3028 (2 kB) (0 MB) +// { 0xBBD2786C, 0xBBD2851C } // size 3252 (3 kB) (0 MB) +// { 0xBBD28ACC, 0xBBD2977C } // size 3252 (3 kB) (0 MB) +// { 0xBBD2BAFC, 0xBBD2C9DC } // size 3812 (3 kB) (0 MB) +// { 0xBBD2CD5C, 0xBBD2DC3C } // size 3812 (3 kB) (0 MB) +// { 0xBBD301EC, 0xBBD30E9C } // size 3252 (3 kB) (0 MB) +// { 0xBBD3144C, 0xBBD320FC } // size 3252 (3 kB) (0 MB) +// { 0xBBD346AC, 0xBBD3535C } // size 3252 (3 kB) (0 MB) +// { 0xBBD3590C, 0xBBD365BC } // size 3252 (3 kB) (0 MB) +// { 0xBBD38D9C, 0xBBD3981C } // size 2692 (2 kB) (0 MB) +// { 0xBBD39FFC, 0xBBD3AA7C } // size 2692 (2 kB) (0 MB) +// { 0xBBD3EB3C, 0xBBD402F0 } // size 6072 (5 kB) (0 MB) +// { 0xBBD412FC, 0xBBD4423C } // size 12100 (11 kB) (0 MB) +// { 0xBBD451FC, 0xBBD4813C } // size 12100 (11 kB) (0 MB) +// { 0xBBD496F4, 0xBBD4A7E0 } // size 4336 (4 kB) (0 MB) +// { 0xBBD4AD3C, 0xBBD4D1FC } // size 9412 (9 kB) (0 MB) +// { 0xBBD4D73C, 0xBBD4FBFC } // size 9412 (9 kB) (0 MB) +// { 0xBBD537BC, 0xBBD5955C } // size 23972 (23 kB) (0 MB) +// { 0xBBD5A1BC, 0xBBD6757C } // size 54212 (52 kB) (0 MB) +// { 0xBBD681BC, 0xBBD7557C } // size 54212 (52 kB) (0 MB) +// { 0xBBD769EC, 0xBBD77D4C } // size 4964 (4 kB) (0 MB) +// { 0xBBD78C5C, 0xBBD7B1FC } // size 9636 (9 kB) (0 MB) +// { 0xBBD7C0DC, 0xBBD7E67C } // size 9636 (9 kB) (0 MB) +// { 0xBBD8CF0C, 0xBBD8D9FC } // size 2804 (2 kB) (0 MB) +// { 0xBBD8DECC, 0xBBD8E9BC } // size 2804 (2 kB) (0 MB) +// { 0xBBD9388C, 0xBBD9437C } // size 2804 (2 kB) (0 MB) +// { 0xBBD9484C, 0xBBD9533C } // size 2804 (2 kB) (0 MB) +// { 0xBBD9993C, 0xBBD9A73C } // size 3588 (3 kB) (0 MB) +// { 0xBBD9D140, 0xBBD9E39C } // size 4704 (4 kB) (0 MB) +// { 0xBBD9E94C, 0xBBD9F5FC } // size 3252 (3 kB) (0 MB) +// { 0xBBDA3010, 0xBBDA3AFC } // size 2800 (2 kB) (0 MB) +// { 0xBBDA3B40, 0xBBDA581C } // size 7392 (7 kB) (0 MB) +// { 0xBBDA5F1C, 0xBBDA74FC } // size 5604 (5 kB) (0 MB) +// { 0xBBDAA08C, 0xBBDAB50C } // size 5252 (5 kB) (0 MB) +// { 0xBBDAB540, 0xBBDAE9BC } // size 13440 (13 kB) (0 MB) +// { 0xBBDAF35C, 0xBBDB1E3C } // size 10980 (10 kB) (0 MB) +// { 0xBBDB3180, 0xBBDB43DC } // size 4704 (4 kB) (0 MB) +// { 0xBBDB7BDC, 0xBBDB86C8 } // size 2800 (2 kB) (0 MB) +// { 0xBBDB8700, 0xBBDBA3DC } // size 7392 (7 kB) (0 MB) +// { 0xBBDBAADC, 0xBBDBC0BC } // size 5604 (5 kB) (0 MB) +// { 0xBBDBEA88, 0xBBDC0058 } // size 5588 (5 kB) (0 MB) +// { 0xBBDC0080, 0xBBDC34FC } // size 13440 (13 kB) (0 MB) +// { 0xBBDC387C, 0xBBDC697C } // size 12548 (12 kB) (0 MB) +// { 0xBBDC8374, 0xBBDC96A4 } // size 4916 (4 kB) (0 MB) +// { 0xBBDC96C0, 0xBBDCC5FC } // size 12096 (11 kB) (0 MB) +// { 0xBBDCCB3C, 0xBBDCF53C } // size 10756 (10 kB) (0 MB) +// { 0xBBDD50A4, 0xBBDDB054 } // size 24500 (23 kB) (0 MB) +// { 0xBBDDB080, 0xBBDE907C } // size 57344 (56 kB) (0 MB) +// { 0xBBDE931C, 0xBBDF707C } // size 56676 (55 kB) (0 MB) +// { 0xBBDFABC8, 0xBBDFC388 } // size 6084 (5 kB) (0 MB) +// { 0xBBDFC3C0, 0xBBE033BC } // size 28672 (28 kB) (0 MB) +// { 0xBBE06C9C, 0xBBE0A3BC } // size 14116 (13 kB) (0 MB) +// { 0xBBE0CC2C, 0xBBE0DF94 } // size 4972 (4 kB) (0 MB) +// { 0xBBE0DFC0, 0xBBE1311C } // size 20832 (20 kB) (0 MB) +// { 0xBBE1556C, 0xBBE1827C } // size 11540 (11 kB) (0 MB) +// { 0xBBE1B698, 0xBBE1D0C4 } // size 6704 (6 kB) (0 MB) +// { 0xBBE1D100, 0xBBE22F7C } // size 24192 (23 kB) (0 MB) +// { 0xBBE2512C, 0xBBE28DFC } // size 15572 (15 kB) (0 MB) +// { 0xBBE29650, 0xBBE2B6A8 } // size 8284 (8 kB) (0 MB) +// { 0xBBE2B6C0, 0xBBE3081C } // size 20832 (20 kB) (0 MB) +// { 0xBBE30E3C, 0xBBE3597C } // size 19268 (18 kB) (0 MB) +// { 0xBBE35DF8, 0xBBE38174 } // size 9088 (8 kB) (0 MB) +// { 0xBBE381C0, 0xBBE4247C } // size 41664 (40 kB) (0 MB) +// { 0xBBE46F68, 0xBBE494D8 } // size 9588 (9 kB) (0 MB) +// { 0xBBE49500, 0xBBE504FC } // size 28672 (28 kB) (0 MB) +// { 0xBBE51DEC, 0xBBE574FC } // size 22292 (21 kB) (0 MB) +// { 0xBBE5A278, 0xBBE5BE88 } // size 7188 (7 kB) (0 MB) +// { 0xBBE5BEC0, 0xBBE62EBC } // size 28672 (28 kB) (0 MB) +// { 0xBBE65D8C, 0xBBE69EBC } // size 16692 (16 kB) (0 MB) +// { 0xBBE6C780, 0xBBE6E37C } // size 7168 (7 kB) (0 MB) +// { 0xBBE72240, 0xBBE73E3C } // size 7168 (7 kB) (0 MB) +// { 0xBBE77640, 0xBBE7923C } // size 7168 (7 kB) (0 MB) +// { 0xBBE7CA40, 0xBBE7E63C } // size 7168 (7 kB) (0 MB) +// { 0xBBE85940, 0xBBE870E0 } // size 6052 (5 kB) (0 MB) +// { 0xBBE87A7C, 0xBBE8887C } // size 3588 (3 kB) (0 MB) +// { 0xBBE8AB90, 0xBBE8BA6C } // size 3808 (3 kB) (0 MB) +// { 0xBBE8BA7C, 0xBBE8E47C } // size 10756 (10 kB) (0 MB) +// { 0xBBE8F35C, 0xBBE90E7C } // size 6948 (6 kB) (0 MB) +// { 0xBBE96240, 0xBBE9703C } // size 3584 (3 kB) (0 MB) +// { 0xBBE9711C, 0xBBE97E3C } // size 3364 (3 kB) (0 MB) +// { 0xBBE9AA40, 0xBBE9B83C } // size 3584 (3 kB) (0 MB) +// { 0xBBE9B91C, 0xBBE9C63C } // size 3364 (3 kB) (0 MB) +// { 0xBBEA0280, 0xBBEA107C } // size 3584 (3 kB) (0 MB) +// { 0xBBEA131C, 0xBBEA1E7C } // size 2916 (2 kB) (0 MB) +// { 0xBBEA4A80, 0xBBEA587C } // size 3584 (3 kB) (0 MB) +// { 0xBBEA5A3C, 0xBBEA667C } // size 3140 (3 kB) (0 MB) +// { 0xBBEA7024, 0xBBEA7F00 } // size 3808 (3 kB) (0 MB) +// { 0xBBEA7F40, 0xBBEAA940 } // size 10756 (10 kB) (0 MB) +// { 0xBBEAB81C, 0xBBEAD33C } // size 6948 (6 kB) (0 MB) +// { 0xBBEAFCC0, 0xBBEB0ABC } // size 3584 (3 kB) (0 MB) +// { 0xBBEB0D5C, 0xBBEB18BC } // size 2916 (2 kB) (0 MB) +// { 0xBBEB44C0, 0xBBEB52BC } // size 3584 (3 kB) (0 MB) +// { 0xBBEB547C, 0xBBEB60BC } // size 3140 (3 kB) (0 MB) +// { 0xBBEB6854, 0xBBEB7940 } // size 4336 (4 kB) (0 MB) +// { 0xBBEB7980, 0xBBEBA380 } // size 10756 (10 kB) (0 MB) +// { 0xBBEBA8BC, 0xBBEBCD7C } // size 9412 (9 kB) (0 MB) +// { 0xBBEC4880, 0xBBEC6410 } // size 7060 (6 kB) (0 MB) +// { 0xBBEC73CC, 0xBBEC7F9C } // size 3028 (2 kB) (0 MB) +// { 0xBBED5740, 0xBBED653C } // size 3584 (3 kB) (0 MB) +// { 0xBBED661C, 0xBBED733C } // size 3364 (3 kB) (0 MB) +// { 0xBBED9F40, 0xBBEDAD3C } // size 3584 (3 kB) (0 MB) +// { 0xBBEDAE1C, 0xBBEDBB3C } // size 3364 (3 kB) (0 MB) +// { 0xBBEDE940, 0xBBEDF900 } // size 4036 (3 kB) (0 MB) +// { 0xBBEDFB9C, 0xBBEE08BC } // size 3364 (3 kB) (0 MB) +// { 0xBBEE4300, 0xBBEE50FC } // size 3584 (3 kB) (0 MB) +// { 0xBBEE52BC, 0xBBEE5EFC } // size 3140 (3 kB) (0 MB) +// { 0xBBEE8B00, 0xBBEE98FC } // size 3584 (3 kB) (0 MB) +// { 0xBBEE9B9C, 0xBBEEA6FC } // size 2916 (2 kB) (0 MB) +// { 0xBBEEB440, 0xBBEEC400 } // size 4036 (3 kB) (0 MB) +// { 0xBBEEC69C, 0xBBEED3BC } // size 3364 (3 kB) (0 MB) +// { 0xBBEEFAB4, 0xBBEF0BA4 } // size 4340 (4 kB) (0 MB) +// { 0xBBEF0BC0, 0xBBEF385C } // size 11424 (11 kB) (0 MB) +// { 0xBBEF42DC, 0xBBEF64FC } // size 8740 (8 kB) (0 MB) +// { 0xBBEF71C0, 0xBBEF817C } // size 4032 (3 kB) (0 MB) +// { 0xBBEF83AC, 0xBBEF913C } // size 3476 (3 kB) (0 MB) +// { 0xBBF03080, 0xBBF04C7C } // size 7168 (7 kB) (0 MB) +// { 0xBBF08B40, 0xBBF0A73C } // size 7168 (7 kB) (0 MB) +// { 0xBBF0DF40, 0xBBF0FB3C } // size 7168 (7 kB) (0 MB) +// { 0xBBF13340, 0xBBF14F3C } // size 7168 (7 kB) (0 MB) +// { 0xBBF17CB0, 0xBBF195F0 } // size 6468 (6 kB) (0 MB) +// { 0xBBF19640, 0xBBF2063C } // size 28672 (28 kB) (0 MB) +// { 0xBBF23B9C, 0xBBF2763C } // size 15012 (14 kB) (0 MB) +// { 0xBBF28CC0, 0xBBF2BAA0 } // size 11748 (11 kB) (0 MB) +// { 0xBBF2BAC0, 0xBBF32ABC } // size 28672 (28 kB) (0 MB) +// { 0xBBF32FFC, 0xBBF39ABC } // size 27332 (26 kB) (0 MB) +// { 0xBC9AA154, 0xBC9ABAB8 } // size 6504 (6 kB) (0 MB) +// { 0xBC9AC81C, 0xBC9AFC9C } // size 13444 (13 kB) (0 MB) +// { 0xBC9B09BC, 0xBC9B3E3C } // size 13444 (13 kB) (0 MB) +// { 0xBC9B6E44, 0xBC9B87A8 } // size 6504 (6 kB) (0 MB) +// { 0xBC9B94DC, 0xBC9BC95C } // size 13444 (13 kB) (0 MB) +// { 0xBC9BD67C, 0xBC9C0AFC } // size 13444 (13 kB) (0 MB) +// { 0xBC9C3C98, 0xBC9C871C } // size 19080 (18 kB) (0 MB) +// { 0xBCA0F4A4, 0xBCA35ABC } // size 157212 (153 kB) (0 MB) +// { 0xBCA35AF0, 0xBCA36764 } // size 3192 (3 kB) (0 MB) +// { 0xBCA36774, 0xBCA4662C } // size 65212 (63 kB) (0 MB) +// { 0xBCA48AB0, 0xBCAE0FFC } // size 623952 (609 kB) (0 MB) +// { 0xBCAE7878, 0xBD207DB4 } // size 7472448 (7297 kB) (7 MB) +// { 0xBD3B966C, 0xBD8943C0 } // size 5090648 (4971 kB) (4 MB) +// { 0xBD894770, 0xBD8A037C } // size 48144 (47 kB) (0 MB) +// { 0xBD8A1F88, 0xBD8A2D7C } // size 3576 (3 kB) (0 MB) +// { 0xBD8A63F4, 0xBD8AD3C4 } // size 28628 (27 kB) (0 MB) +// { 0xBD8AD3D8, 0xBDFFFFFC } // size 7679016 (7499 kB) (7 MB) +// { 0xBE2F02A0, 0xBE2F217C } // size 7904 (7 kB) (0 MB) +// { 0xBE320A64, 0xBE323574 } // size 11028 (10 kB) (0 MB) +// { 0xBE324220, 0xBE32B73C } // size 29984 (29 kB) (0 MB) +// { 0xBE34A2A0, 0xBE34C0FC } // size 7776 (7 kB) (0 MB) +// { 0xBE358B80, 0xBE35CCFC } // size 16768 (16 kB) (0 MB) +// { 0xBE363020, 0xBE36407C } // size 4192 (4 kB) (0 MB) +// { 0xBE37EB98, 0xBE38172C } // size 11160 (10 kB) (0 MB) +// { 0xBE382600, 0xBE3AC4BC } // size 171712 (167 kB) (0 MB) +// { 0xBE3BF8D0, 0xBE3E24FC } // size 142384 (139 kB) (0 MB) +// { 0xBE3EB3B0, 0xBE3EE394 } // size 12264 (11 kB) (0 MB) +// { 0xBE3EFD40, 0xBE410CBC } // size 135040 (131 kB) (0 MB) +// { 0xBE41EA50, 0xBE4474FC } // size 166576 (162 kB) (0 MB) +// { 0xBE46ADC0, 0xBE46E57C } // size 14272 (13 kB) (0 MB) +// { 0xBE473BE0, 0xBE47543C } // size 6240 (6 kB) (0 MB) +// { 0xBE47EFD0, 0xBE4884BC } // size 38128 (37 kB) (0 MB) +// { 0xBE49167C, 0xBE493C2C } // size 9652 (9 kB) (0 MB) +// { 0xBE495690, 0xBE49C57C } // size 28400 (27 kB) (0 MB) +// { 0xBE4A58B0, 0xBE4B49FC } // size 61776 (60 kB) (0 MB) +// { 0xBE4DC17C, 0xBE4DF94C } // size 14292 (13 kB) (0 MB) +// { 0xBE4E0AD0, 0xBE5000BC } // size 128496 (125 kB) (0 MB) +// { 0xBE50A1A0, 0xBE53327C } // size 168160 (164 kB) (0 MB) +// { 0xBE536660, 0xBE5584FC } // size 138912 (135 kB) (0 MB) +// { 0xBE58316C, 0xBE58659C } // size 13364 (13 kB) (0 MB) +// { 0xBE586AD0, 0xBE5B86BC } // size 203760 (198 kB) (0 MB) +// { 0xBE5CFF70, 0xBE5D7FBC } // size 32848 (32 kB) (0 MB) +// { 0xBE5DE9D8, 0xBE5E0F8C } // size 9656 (9 kB) (0 MB) +// { 0xBE5E12B0, 0xBE60507C } // size 146896 (143 kB) (0 MB) +// { 0xBE605CBC, 0xBFF849BC } // size 26733828 (26107 kB) (25 MB) +// { 0xBFF869BC, 0xBFF8CA3C } // size 24708 (24 kB) (0 MB) +// { 0xBFF8DA24, 0xBFF8E600 } // size 3040 (2 kB) (0 MB) + +// { 0xC1000000, 0xC1E1FFFC } // size 14811136 (14464 kB) (14 MB) +// { 0xC1EB1380, 0xC1EB4B3C } // size 14272 (13 kB) (0 MB) +// { 0xC1FEFE7C, 0xC1FF5EFC } // size 24708 (24 kB) (0 MB) +// { 0xC1FF6E84, 0xC1FF7AC0 } // size 3136 (3 kB) (0 MB) +// { 0xC2086268, 0xC2090B3C } // size 43224 (42 kB) (0 MB) +// { 0xC20B15D8, 0xC20B97FC } // size 33320 (32 kB) (0 MB) +// { 0xC20BE2A0, 0xC20BED7C } // size 2784 (2 kB) (0 MB) +// { 0xC20CCE7C, 0xC20CEEBC } // size 8260 (8 kB) (0 MB) +// { 0xC20E5888, 0xC20E7E4C } // size 9672 (9 kB) (0 MB) +// { 0xC20E7E58, 0xC20EC73C } // size 18664 (18 kB) (0 MB) +// { 0xC20F212C, 0xC210AF3C } // size 101908 (99 kB) (0 MB) +// { 0xC2119BAC, 0xC211EEFC } // size 21332 (20 kB) (0 MB) +// { 0xC2122F30, 0xC212787C } // size 18768 (18 kB) (0 MB) +// { 0xC2131054, 0xC213C63C } // size 46572 (45 kB) (0 MB) +// { 0xC214A474, 0xC214DC3C } // size 14284 (13 kB) (0 MB) +// { 0xC21ABCA0, 0xC21AE904 } // size 11368 (11 kB) (0 MB) +// { 0xC21AE910, 0xC21C207C } // size 79728 (77 kB) (0 MB) +// { 0xC21DBB50, 0xC21DCFFC } // size 5296 (5 kB) (0 MB) +// { 0xC21DD064, 0xC21E287C } // size 22556 (22 kB) (0 MB) +// { 0xC301308C, 0xC301F0BC } // size 49204 (48 kB) (0 MB) +// { 0xC301F0C4, 0xC3023014 } // size 16212 (15 kB) (0 MB) +// { 0xC30230C4, 0xC3027014 } // size 16212 (15 kB) (0 MB) +// { 0xC30270C4, 0xC302B014 } // size 16212 (15 kB) (0 MB) +// { 0xC302B0C4, 0xC302F014 } // size 16212 (15 kB) (0 MB) +// { 0xC302F0C4, 0xC3033014 } // size 16212 (15 kB) (0 MB) +// { 0xC30330C4, 0xC3037014 } // size 16212 (15 kB) (0 MB) +// { 0xC30398E8, 0xC303A2B4 } // size 2512 (2 kB) (0 MB) +// { 0xC303B068, 0xC303BC68 } // size 3076 (3 kB) (0 MB) +// { 0xC3043150, 0xC3043C64 } // size 2840 (2 kB) (0 MB) +// { 0xC3045AF0, 0xC304E09C } // size 34224 (33 kB) (0 MB) +// { 0xC304E3D4, 0xC3050B24 } // size 10068 (9 kB) (0 MB) +// { 0xC3051940, 0xC30528D4 } // size 3992 (3 kB) (0 MB) +// { 0xC3052930, 0xC30538DC } // size 4016 (3 kB) (0 MB) +// { 0xC3053934, 0xC30548D4 } // size 4004 (3 kB) (0 MB) +// { 0xC30566EC, 0xC3058664 } // size 8060 (7 kB) (0 MB) +// { 0xC30586EC, 0xC305A664 } // size 8060 (7 kB) (0 MB) +// { 0xC305A6EC, 0xC305C664 } // size 8060 (7 kB) (0 MB) +// { 0xC305CB90, 0xC305DC78 } // size 4332 (4 kB) (0 MB) +// { 0xC305E40C, 0xC305ECF0 } // size 2280 (2 kB) (0 MB) +// { 0xC3060044, 0xC3060F8C } // size 3916 (3 kB) (0 MB) +// { 0xC3061040, 0xC306203C } // size 4096 (4 kB) (0 MB) +// { 0xC3062DB8, 0xC306EE3C } // size 49288 (48 kB) (0 MB) +// { 0xC306EE84, 0xC3070DC4 } // size 8004 (7 kB) (0 MB) +// { 0xC3070E84, 0xC3072DC4 } // size 8004 (7 kB) (0 MB) +// { 0xC3072E84, 0xC3074DC4 } // size 8004 (7 kB) (0 MB) +// { 0xC30761F0, 0xC307745C } // size 4720 (4 kB) (0 MB) +// { 0xC307F28C, 0xC307FAC0 } // size 2104 (2 kB) (0 MB) +// { 0xC307FAF8, 0xC3081350 } // size 6236 (6 kB) (0 MB) +// { 0xC3081358, 0xC30822A4 } // size 3920 (3 kB) (0 MB) +// { 0xC3082358, 0xC30832A4 } // size 3920 (3 kB) (0 MB) +// { 0xC3083358, 0xC30842A4 } // size 3920 (3 kB) (0 MB) +// { 0xC30858E4, 0xC30878C4 } // size 8164 (7 kB) (0 MB) +// { 0xC30878F8, 0xC308B8C4 } // size 16336 (15 kB) (0 MB) +// { 0xC308C240, 0xC3097744 } // size 46344 (45 kB) (0 MB) +// { 0xC3097930, 0xC30A37E4 } // size 48824 (47 kB) (0 MB) +// { 0xC30A3818, 0xC30B16BC } // size 57000 (55 kB) (0 MB) +// { 0xC30B16C4, 0xC30B262C } // size 3948 (3 kB) (0 MB) +// { 0xC30B26C0, 0xC30B3B3C } // size 5248 (5 kB) (0 MB) +// { 0xC30B4204, 0xC30B5900 } // size 5888 (5 kB) (0 MB) +// { 0xC30B5934, 0xC30B713C } // size 6156 (6 kB) (0 MB) +// { 0xC30B7190, 0xC30BC074 } // size 20200 (19 kB) (0 MB) +// { 0xC30BC138, 0xC30BD13C } // size 4104 (4 kB) (0 MB) +// { 0xC30BD144, 0xC30C1084 } // size 16196 (15 kB) (0 MB) +// { 0xC30C1144, 0xC30C5084 } // size 16196 (15 kB) (0 MB) +// { 0xC30C5144, 0xC30C9084 } // size 16196 (15 kB) (0 MB) +// { 0xC30CAE10, 0xC30CB788 } // size 2428 (2 kB) (0 MB) +// { 0xC30CC780, 0xC30CCFA4 } // size 2088 (2 kB) (0 MB) +// { 0xC30CDEC0, 0xC30CE6E4 } // size 2088 (2 kB) (0 MB) +// { 0xC30CF600, 0xC30D707C } // size 31360 (30 kB) (0 MB) +// { 0xC30D719C, 0xC30DC3FC } // size 21092 (20 kB) (0 MB) +// { 0xC30DC61C, 0xC318037C } // size 671076 (655 kB) (0 MB) +// { 0xC31804E0, 0xC31C037C } // size 261792 (255 kB) (0 MB) +// { 0xC31C07C4, 0xC321063C } // size 327292 (319 kB) (0 MB) +// { 0xC3227980, 0xC322AF34 } // size 13752 (13 kB) (0 MB) +// { 0xC322C600, 0xC3231D00 } // size 22276 (21 kB) (0 MB) +// { 0xC32327E4, 0xC3233060 } // size 2176 (2 kB) (0 MB) +// { 0xC3234080, 0xC324B340 } // size 94916 (92 kB) (0 MB) +// { 0xC324D8C0, 0xC328D880 } // size 262084 (255 kB) (0 MB) +// { 0xC329D234, 0xC32CA42C } // size 184828 (180 kB) (0 MB) +// { 0xC32CA434, 0xC32CDF68 } // size 15160 (14 kB) (0 MB) +// { 0xC32CE26C, 0xC32CF4FC } // size 4756 (4 kB) (0 MB) +// { 0xC32CF504, 0xC32D0790 } // size 4752 (4 kB) (0 MB) +// { 0xC32D34BC, 0xC32D4A3C } // size 5508 (5 kB) (0 MB) +// { 0xC32EB100, 0xC32EBC98 } // size 2972 (2 kB) (0 MB) +// { 0xC32ED180, 0xC32EFFC0 } // size 11844 (11 kB) (0 MB) +// { 0xC32F4540, 0xC32FA080 } // size 23364 (22 kB) (0 MB) +// { 0xC3302A6C, 0xC33045C0 } // size 7000 (6 kB) (0 MB) +// { 0xC331AE90, 0xC331C33C } // size 5296 (5 kB) (0 MB) +// { 0xC332B500, 0xC3340F88 } // size 88716 (86 kB) (0 MB) +// { 0xC334DB34, 0xC334EB40 } // size 4112 (4 kB) (0 MB) +// { 0xC3354284, 0xC3356354 } // size 8404 (8 kB) (0 MB) +// { 0xC33573C8, 0xC33583FC } // size 4152 (4 kB) (0 MB) +// { 0xC3358A80, 0xC335A484 } // size 6664 (6 kB) (0 MB) +// { 0xC335A4C0, 0xC35021FC } // size 1736000 (1695 kB) (1 MB) +// { 0xC350C1D4, 0xC39182CC } // size 4243708 (4144 kB) (4 MB) +// { 0xC3919AC4, 0xC39298C4 } // size 65028 (63 kB) (0 MB) +// { 0xC3929AC4, 0xC3939534 } // size 64116 (62 kB) (0 MB) +// { 0xC3939AC4, 0xC39498C4 } // size 65028 (63 kB) (0 MB) +// { 0xC3949AC0, 0xC394CFFC } // size 13632 (13 kB) (0 MB) +// { 0xC394EEB0, 0xC3954988 } // size 23260 (22 kB) (0 MB) +// { 0xC3955000, 0xC3955FFC } // size 4096 (4 kB) (0 MB) +// { 0xC395667C, 0xC395778C } // size 4372 (4 kB) (0 MB) +// { 0xC39577C0, 0xC3975C80 } // size 124100 (121 kB) (0 MB) +// { 0xC39769C8, 0xC398D320 } // size 92508 (90 kB) (0 MB) +// { 0xC398DAF8, 0xC399DC08 } // size 65812 (64 kB) (0 MB) +// { 0xC399DC78, 0xC39ABF80 } // size 58124 (56 kB) (0 MB) +// { 0xC39B1124, 0xC39C8200 } // size 94432 (92 kB) (0 MB) +// { 0xC39C966C, 0xC39CB580 } // size 7960 (7 kB) (0 MB) +// { 0xC39CC178, 0xC39D5580 } // size 37900 (37 kB) (0 MB) +// { 0xC39D5E20, 0xC39E5F34 } // size 65816 (64 kB) (0 MB) +// { 0xC39E5F84, 0xC39F6A80 } // size 68352 (66 kB) (0 MB) +// { 0xC39FBC54, 0xC3A14080 } // size 99376 (97 kB) (0 MB) +// { 0xC3A14094, 0xC3EBFFFC } // size 4898668 (4783 kB) (4 MB) +// { 0xC3F028E0, 0xC3F2477C } // size 138912 (135 kB) (0 MB) +// { 0xC3F37B10, 0xC3F5A73C } // size 142384 (139 kB) (0 MB) +// { 0xC3F69350, 0xC3F91DFC } // size 166576 (162 kB) (0 MB) +// { 0xC3F927DC, 0xC3FEE3BC } // size 375780 (366 kB) (0 MB) +// { 0xC3FF23B4, 0xC3FF643C } // size 16524 (16 kB) (0 MB) +// { 0xC3FF7274, 0xC3FF8000 } // size 3472 (3 kB) (0 MB) +// { 0xC3FFFFD4, 0xC8FFFFFC } // size 83886124 (81920 kB) (80 MB) + {0, 0} +}; + +static const memory_values_t mem_vals_532[] = +{ + // TODO: Check which of those areas are usable +// {0xB8000000 + 0x000DCC9C, 0xB8000000 + 0x00174F80}, // 608 kB +// {0xB8000000 + 0x00180B60, 0xB8000000 + 0x001C0A00}, // 255 kB +// {0xB8000000 + 0x001ECE9C, 0xB8000000 + 0x00208CC0}, // 111 kB +// {0xB8000000 + 0x00234180, 0xB8000000 + 0x0024B444}, // 92 kB +// {0xB8000000 + 0x0024D8C0, 0xB8000000 + 0x0028D884}, // 255 kB +// {0xB8000000 + 0x003A745C, 0xB8000000 + 0x004D2B68}, // 1197 kB +// {0xB8000000 + 0x004D77B0, 0xB8000000 + 0x00502200}, // 170 kB +// {0xB8000000 + 0x005B3A88, 0xB8000000 + 0x005C6870}, // 75 kB +// {0xB8000000 + 0x0061F3E4, 0xB8000000 + 0x00632B04}, // 77 kB +// {0xB8000000 + 0x00639790, 0xB8000000 + 0x00649BC4}, // 65 kB +// {0xB8000000 + 0x00691490, 0xB8000000 + 0x006B3CA4}, // 138 kB +// {0xB8000000 + 0x006D7BCC, 0xB8000000 + 0x006EEB84}, // 91 kB +// {0xB8000000 + 0x00704E44, 0xB8000000 + 0x0071E3C4}, // 101 kB +// {0xB8000000 + 0x0073B684, 0xB8000000 + 0x0074C184}, // 66 kB +// {0xB8000000 + 0x00751354, 0xB8000000 + 0x00769784}, // 97 kB +// {0xB8000000 + 0x008627DC, 0xB8000000 + 0x00872904}, // 64 kB +// {0xB8000000 + 0x008C1E98, 0xB8000000 + 0x008EB0A0}, // 164 kB +// {0xB8000000 + 0x008EEC30, 0xB8000000 + 0x00B06E98}, // 2144 kB +// {0xB8000000 + 0x00B06EC4, 0xB8000000 + 0x00B930C4}, // 560 kB +// {0xB8000000 + 0x00BA1868, 0xB8000000 + 0x00BC22A4}, // 130 kB +// {0xB8000000 + 0x00BC48F8, 0xB8000000 + 0x00BDEC84}, // 104 kB +// {0xB8000000 + 0x00BE3DC0, 0xB8000000 + 0x00C02284}, // 121 kB +// {0xB8000000 + 0x00C02FC8, 0xB8000000 + 0x00C19924}, // 90 kB +// {0xB8000000 + 0x00C2D35C, 0xB8000000 + 0x00C3DDC4}, // 66 kB +// {0xB8000000 + 0x00C48654, 0xB8000000 + 0x00C6E2E4}, // 151 kB +// {0xB8000000 + 0x00D04E04, 0xB8000000 + 0x00D36938}, // 198 kB +// {0xB8000000 + 0x00DC88AC, 0xB8000000 + 0x00E14288}, // 302 kB +// {0xB8000000 + 0x00E21ED4, 0xB8000000 + 0x00EC8298}, // 664 kB +// {0xB8000000 + 0x00EDDC7C, 0xB8000000 + 0x00F7C2A8}, // 633 kB +// {0xB8000000 + 0x00F89EF4, 0xB8000000 + 0x010302B8}, // 664 kB +// {0xB8000000 + 0x01030800, 0xB8000000 + 0x013F69A0}, // 3864 kB +// {0xB8000000 + 0x016CE000, 0xB8000000 + 0x016E0AA0}, // 74 kB +// {0xB8000000 + 0x0170200C, 0xB8000000 + 0x018B9C58}, // 1759 kB +// {0xB8000000 + 0x01F17658, 0xB8000000 + 0x01F6765C}, // 320 kB +// {0xB8000000 + 0x01F6779C, 0xB8000000 + 0x01FB77A0}, // 320 kB +// {0xB8000000 + 0x01FB78E0, 0xB8000000 + 0x020078E4}, // 320 kB +// {0xB8000000 + 0x02007A24, 0xB8000000 + 0x02057A28}, // 320 kB +// {0xB8000000 + 0x02057B68, 0xB8000000 + 0x021B957C}, // 1414 kB +// {0xB8000000 + 0x02891528, 0xB8000000 + 0x028C8A28}, // 221 kB +// {0xB8000000 + 0x02BBCC4C, 0xB8000000 + 0x02CB958C}, // 1010 kB +// {0xB8000000 + 0x0378D45C, 0xB8000000 + 0x03855464}, // 800 kB +// {0xB8000000 + 0x0387800C, 0xB8000000 + 0x03944938}, // 818 kB +// {0xB8000000 + 0x03944A08, 0xB8000000 + 0x03956E0C}, // 73 kB +// {0xB8000000 + 0x04A944A4, 0xB8000000 + 0x04ABAAC0}, // 153 kB +// {0xB8000000 + 0x04ADE370, 0xB8000000 + 0x0520EAB8}, // 7361 kB // ok +// {0xB8000000 + 0x053B966C, 0xB8000000 + 0x058943C4}, // 4971 kB // ok +// {0xB8000000 + 0x058AD3D8, 0xB8000000 + 0x06000000}, // 7499 kB +// {0xB8000000 + 0x0638D320, 0xB8000000 + 0x063B0280}, // 139 kB +// {0xB8000000 + 0x063C39E0, 0xB8000000 + 0x063E62C0}, // 138 kB +// {0xB8000000 + 0x063F52A0, 0xB8000000 + 0x06414A80}, // 125 kB +// {0xB8000000 + 0x06422810, 0xB8000000 + 0x0644B2C0}, // 162 kB +// {0xB8000000 + 0x064E48D0, 0xB8000000 + 0x06503EC0}, // 125 kB +// {0xB8000000 + 0x0650E360, 0xB8000000 + 0x06537080}, // 163 kB +// {0xB8000000 + 0x0653A460, 0xB8000000 + 0x0655C300}, // 135 kB +// {0xB8000000 + 0x0658AA40, 0xB8000000 + 0x065BC4C0}, // 198 kB // ok +// {0xB8000000 + 0x065E51A0, 0xB8000000 + 0x06608E80}, // 143 kB // ok +// {0xB8000000 + 0x06609ABC, 0xB8000000 + 0x07F82C00}, // 26084 kB // ok + +// {0xC0000000 + 0x000DCC9C, 0xC0000000 + 0x00180A00}, // 655 kB +// {0xC0000000 + 0x00180B60, 0xC0000000 + 0x001C0A00}, // 255 kB +// {0xC0000000 + 0x001F5EF0, 0xC0000000 + 0x00208CC0}, // 75 kB +// {0xC0000000 + 0x00234180, 0xC0000000 + 0x0024B444}, // 92 kB +// {0xC0000000 + 0x0024D8C0, 0xC0000000 + 0x0028D884}, // 255 kB +// {0xC0000000 + 0x003A745C, 0xC0000000 + 0x004D2B68}, // 1197 kB +// {0xC0000000 + 0x006D3334, 0xC0000000 + 0x00772204}, // 635 kB +// {0xC0000000 + 0x00789C60, 0xC0000000 + 0x007C6000}, // 240 kB +// {0xC0000000 + 0x00800000, 0xC0000000 + 0x01E20000}, // 22876 kB // ok + { 0xBE609ABC, 0xBFF82C00 }, // 26084 kB + { 0xB9030800, 0xB93F69A0 }, // 3864 kB + { 0xB88EEC30, 0xB8B06E98 }, // 2144 kB + { 0xBD3B966C, 0xBD8943C4 }, // 4971 kB + { 0xBCAE0370, 0xBD20EAB8 }, // 7361 kB + { 0xBD8AD3D8, 0xBE000000 }, // 7499 kB + + {0, 0} +}; // total : 66mB + 25mB + +static const memory_values_t mem_vals_540[] = +{ + { 0xBE609EFC, 0xBFF82BC0 }, // 26083 kB + { 0xBD8AD3D8, 0xBE000000 }, // 7499 kB + { 0xBCB56370, 0xBD1EF6B8 }, // 6756 kB + { 0xBD3B966C, 0xBD8943C4 }, // 4971 kB + { 0xB9030800, 0xB93F6A04 }, // 3864 kB + { 0xB88EEC30, 0xB8B06E98 }, // 2144 kB + { 0xB970200C, 0xB98B9C58 }, // 1759 kB + { 0xB8B06EC4, 0xB8B930C4 }, // 560 kB + + {0, 0} +}; + +//! retain container for our memory area table data +static unsigned char ucMemAreaTableBuffer[0xff]; + +s_mem_area * memoryGetAreaTable(void) +{ + return (s_mem_area *) (ucMemAreaTableBuffer); +} + +static inline void memoryAddArea(int start, int end, int cur_index) +{ + // Create and copy new memory area + s_mem_area * mem_area = memoryGetAreaTable(); + mem_area[cur_index].address = start; + mem_area[cur_index].size = end - start; + mem_area[cur_index].next = 0; + + // Fill pointer to this area in the previous area + if (cur_index > 0) + { + mem_area[cur_index - 1].next = &mem_area[cur_index]; + } +} + +/* Create memory areas arrays */ +void memoryInitAreaTable() +{ + u32 ApplicationMemoryEnd; + + asm volatile("lis %0, __CODE_END@h; ori %0, %0, __CODE_END@l" : "=r" (ApplicationMemoryEnd)); + + // This one seems to be available on every firmware and therefore its our code area but also our main RPX area behind our code + // 22876 kB - our application // ok + memoryAddArea(ApplicationMemoryEnd + 0xC0000000, 0xC1E20000, 0); + + const memory_values_t * mem_vals = NULL; + + switch(OS_FIRMWARE) + { + case 500: { + mem_vals = mem_vals_500; + break; + } + case 532: { + mem_vals = mem_vals_532; + break; + } + case 540: + case 550: { + mem_vals = mem_vals_540; + break; + } + default: + return; // no known values + } + + // Fill entries + int i = 0; + while (mem_vals[i].start_address) + { + memoryAddArea(mem_vals[i].start_address, mem_vals[i].end_address, i + 1); + i++; + } +} diff --git a/src/game/memory_area_table.h b/src/game/memory_area_table.h new file mode 100644 index 0000000..1c8af75 --- /dev/null +++ b/src/game/memory_area_table.h @@ -0,0 +1,40 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef _MEMORY_AREA_TABLE_H_ +#define _MEMORY_AREA_TABLE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Struct used to organize empty memory areas */ +typedef struct _s_mem_area +{ + unsigned int address; + unsigned int size; + struct _s_mem_area* next; +} s_mem_area; + +void memoryInitAreaTable(); +s_mem_area * memoryGetAreaTable(void); + + +#ifdef __cplusplus +} +#endif + +#endif // _MEMORY_AREA_TABLE_H_ diff --git a/src/game/rpx_rpl_table.c b/src/game/rpx_rpl_table.c new file mode 100644 index 0000000..bf75620 --- /dev/null +++ b/src/game/rpx_rpl_table.c @@ -0,0 +1,210 @@ +#include +#include "rpx_rpl_table.h" +#include "kernel/kernel_functions.h" +#include "common/common.h" + +//! static container holding our retain data +static unsigned char ucRpxData[0xffff]; +static int iRpxRplCount = 0; + +void rpxRplTableInit(void) +{ + s_rpx_rpl *pRpxData = (s_rpx_rpl*)ucRpxData; + //! initialize the RPL/RPX table first entry to zero + 1 byte for name zero termination + //! just in case no RPL/RPX are found, though it wont boot then anyway + memset(pRpxData, 0, sizeof(s_rpx_rpl) + 1); + iRpxRplCount = 0; +} + +s_rpx_rpl * rpxRplTableAddEntry(const char *name, int offset, int size, int is_rpx, int entry_index, s_mem_area* area) +{ + // fill rpx/rpl entry + s_rpx_rpl * rpx_rpl_data = (s_rpx_rpl *)(ucRpxData); + // get to last entry + while(rpx_rpl_data->next) { + rpx_rpl_data = rpx_rpl_data->next; + } + + // setup next entry on the previous one (only if it is not the first entry) + if(entry_index > 0) { + rpx_rpl_data->next = (s_rpx_rpl *)( ((u32)rpx_rpl_data) + sizeof(s_rpx_rpl) + strlen(rpx_rpl_data->name) + 1 ); + rpx_rpl_data = rpx_rpl_data->next; + } + + // setup current entry + rpx_rpl_data->area = area; + rpx_rpl_data->size = size; + rpx_rpl_data->offset = offset; + rpx_rpl_data->is_rpx = is_rpx; + rpx_rpl_data->next = 0; + strcpy(rpx_rpl_data->name, name); + + iRpxRplCount++; + + return rpx_rpl_data; +} + +s_rpx_rpl* rpxRplTableGet(void) +{ + return (s_rpx_rpl*)ucRpxData; +} + +int rpxRplTableGetCount(void) +{ + return iRpxRplCount; +} + +s_mem_area *rpxRplTableGetNextFreeMemArea(u32 * mem_area_addr_start, u32 * mem_area_addr_end, u32 * mem_area_offset) +{ + s_mem_area * mem_area = memoryGetAreaTable(); + s_rpx_rpl *rpl_struct = rpxRplTableGet(); + while(rpl_struct != 0) + { + // check if this entry was loaded into memory + if(rpl_struct->size == 0) { + // see if we find entries behind this one that was pre-loaded + rpl_struct = rpl_struct->next; + // entry was not loaded into memory -> skip it + continue; + } + + // this entry has been loaded to memory, remember it's area + mem_area = rpl_struct->area; + + int rpl_size = rpl_struct->size; + int rpl_offset = rpl_struct->offset; + // find the end of the entry and switch between areas if needed + while(mem_area && (u32)(rpl_offset + rpl_size) >= mem_area->size) + { + rpl_size -= mem_area->size - rpl_offset; + rpl_offset = 0; + mem_area = mem_area->next; + } + + if(!mem_area) + return NULL; + + // set new start, end and memory area offset + *mem_area_addr_start = mem_area->address; + *mem_area_addr_end = mem_area->address + mem_area->size; + *mem_area_offset = rpl_offset + rpl_size; + + // see if we find entries behind this one that was pre-loaded + rpl_struct = rpl_struct->next; + } + return mem_area; +} + +int rpxRplCopyDataToMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, const u8 *data, u32 dataSize) +{ + s_mem_area *mem_area = rpx_rpl_struct->area; + u32 mem_area_addr_start = mem_area->address; + u32 mem_area_addr_end = mem_area_addr_start + mem_area->size; + u32 mem_area_offset = rpx_rpl_struct->offset; + + // add to offset + mem_area_offset += fileOffset; + + // skip position to the end of the fill + while ((mem_area_addr_start + mem_area_offset) >= mem_area_addr_end) // TODO: maybe >, not >= + { + // subtract what was in the offset left from last memory block + mem_area_offset = (mem_area_addr_start + mem_area_offset) - mem_area_addr_end; + mem_area = mem_area->next; + if(!mem_area) + return 0; + + mem_area_addr_start = mem_area->address; + mem_area_addr_end = mem_area_addr_start + mem_area->size; + } + + // copy to memory + u32 copiedBytes = 0; + while(copiedBytes < dataSize) + { + u32 blockSize = dataSize - copiedBytes; + u32 mem_area_addr_dest = mem_area_addr_start + mem_area_offset; + + if((mem_area_addr_dest + blockSize) > mem_area_addr_end) + blockSize = mem_area_addr_end - mem_area_addr_dest; + + if(blockSize == 0) + { + // Set next memory area + mem_area = mem_area->next; + if(!mem_area) + return 0; + + mem_area_addr_start = mem_area->address; + mem_area_addr_end = mem_area->address + mem_area->size; + mem_area_offset = 0; + continue; + } + + SC0x25_KernelCopyData(mem_area_addr_dest, (u32)&data[copiedBytes], blockSize); + mem_area_offset += blockSize; + copiedBytes += blockSize; + } + + return copiedBytes; +} + +int rpxRplCopyDataFromMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, u8 *data, u32 dataSize) +{ + s_mem_area *mem_area = rpx_rpl_struct->area; + u32 mem_area_addr_start = mem_area->address; + u32 mem_area_addr_end = mem_area_addr_start + mem_area->size; + u32 mem_area_offset = rpx_rpl_struct->offset; + + if(fileOffset > rpx_rpl_struct->size) + return 0; + + if((fileOffset + dataSize) > rpx_rpl_struct->size) + dataSize = rpx_rpl_struct->size - fileOffset; + + // add to offset + mem_area_offset += fileOffset; + + // skip position to the end of the fill + while ((mem_area_addr_start + mem_area_offset) >= mem_area_addr_end) // TODO: maybe >, not >= + { + // subtract what was in the offset left from last memory block + mem_area_offset = (mem_area_addr_start + mem_area_offset) - mem_area_addr_end; + mem_area = mem_area->next; + if(!mem_area) + return 0; + + mem_area_addr_start = mem_area->address; + mem_area_addr_end = mem_area_addr_start + mem_area->size; + } + + // copy to memory + u32 copiedBytes = 0; + while(copiedBytes < dataSize) + { + u32 blockSize = dataSize - copiedBytes; + u32 mem_area_addr_dest = mem_area_addr_start + mem_area_offset; + + if((mem_area_addr_dest + blockSize) > mem_area_addr_end) + blockSize = mem_area_addr_end - mem_area_addr_dest; + + if(blockSize == 0) + { + // Set next memory area + mem_area = mem_area->next; + if(!mem_area) + return 0; + + mem_area_addr_start = mem_area->address; + mem_area_addr_end = mem_area->address + mem_area->size; + mem_area_offset = 0; + continue; + } + + SC0x25_KernelCopyData((u32)&data[copiedBytes], mem_area_addr_dest, blockSize); + mem_area_offset += blockSize; + copiedBytes += blockSize; + } + + return copiedBytes; +} diff --git a/src/game/rpx_rpl_table.h b/src/game/rpx_rpl_table.h new file mode 100644 index 0000000..b114b70 --- /dev/null +++ b/src/game/rpx_rpl_table.h @@ -0,0 +1,37 @@ +#ifndef __RPX_ARRAY_H_ +#define __RPX_ARRAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "common/common.h" +#include "memory_area_table.h" + +/* Struct used to organize rpx/rpl data in memory */ +typedef struct _s_rpx_rpl +{ + struct _s_rpx_rpl* next; + s_mem_area* area; + unsigned int offset; + unsigned int size; + unsigned char is_rpx; + char name[0]; +} s_rpx_rpl; + +void rpxRplTableInit(void); +s_rpx_rpl* rpxRplTableAddEntry(const char *name, int offset, int size, int is_rpx, int entry_index, s_mem_area* area); +s_rpx_rpl* rpxRplTableGet(void); +int rpxRplTableGetCount(void); + +s_mem_area *rpxRplTableGetNextFreeMemArea(u32 * mem_area_addr_start, u32 * mem_area_addr_end, u32 * mem_area_offset); +int rpxRplCopyDataToMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, const u8 *data, u32 dataSize); +int rpxRplCopyDataFromMem(s_rpx_rpl *rpx_rpl_struct, u32 fileOffset, u8 *data, u32 dataSize); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/kernel/kernel_functions.c b/src/kernel/kernel_functions.c new file mode 100644 index 0000000..72b5525 --- /dev/null +++ b/src/kernel/kernel_functions.c @@ -0,0 +1,94 @@ +#include +#include "common/common.h" +#include "common/kernel_defs.h" +#include "kernel/kernel_functions.h" +#include "kernel/syscalls.h" +#include "start.h" + +/* our retain data */ +ReducedCosAppXmlInfo cosAppXmlInfoStruct __attribute__((section(".data"))); +/* + * This function is a kernel hook function. It is called directly from kernel code at position 0xFFF18558. + */ +void my_PrepareTitle(CosAppXmlInfo *xmlKernelInfo) +{ + /** + * DBAT for access to our data region is setup at this point for the 0xC0000000 area. + */ + + //! Copy all data from the XML info + strncpy(cosAppXmlInfoStruct.rpx_name, xmlKernelInfo->rpx_name, FS_MAX_ENTNAME_SIZE); + + cosAppXmlInfoStruct.version_cos_xml = xmlKernelInfo->version_cos_xml; + cosAppXmlInfoStruct.os_version = xmlKernelInfo->os_version; + cosAppXmlInfoStruct.title_id = xmlKernelInfo->title_id; + cosAppXmlInfoStruct.app_type = xmlKernelInfo->app_type; + cosAppXmlInfoStruct.cmdFlags = xmlKernelInfo->cmdFlags; + cosAppXmlInfoStruct.max_size = xmlKernelInfo->max_size; + cosAppXmlInfoStruct.avail_size = xmlKernelInfo->avail_size; + cosAppXmlInfoStruct.codegen_size = xmlKernelInfo->codegen_size; + cosAppXmlInfoStruct.codegen_core = xmlKernelInfo->codegen_core; + cosAppXmlInfoStruct.max_codesize = xmlKernelInfo->max_codesize; + cosAppXmlInfoStruct.overlay_arena = xmlKernelInfo->overlay_arena; + cosAppXmlInfoStruct.default_stack0_size = xmlKernelInfo->default_stack0_size; + cosAppXmlInfoStruct.default_stack1_size = xmlKernelInfo->default_stack1_size; + cosAppXmlInfoStruct.default_stack2_size = xmlKernelInfo->default_stack2_size; + cosAppXmlInfoStruct.default_redzone0_size = xmlKernelInfo->default_redzone0_size; + cosAppXmlInfoStruct.default_redzone1_size = xmlKernelInfo->default_redzone1_size; + cosAppXmlInfoStruct.default_redzone2_size = xmlKernelInfo->default_redzone2_size; + cosAppXmlInfoStruct.exception_stack0_size = xmlKernelInfo->exception_stack0_size; + cosAppXmlInfoStruct.exception_stack1_size = xmlKernelInfo->exception_stack1_size; + cosAppXmlInfoStruct.exception_stack2_size = xmlKernelInfo->exception_stack2_size; + cosAppXmlInfoStruct.sdk_version = xmlKernelInfo->sdk_version; + cosAppXmlInfoStruct.title_version = xmlKernelInfo->title_version; + + // on title switch reset the dumper + Reset(); +} + +void SetupKernelCallback(void) +{ + KernelSetupSyscalls(); +} + +void KernelSetDBATs(bat_table_t * table) +{ + KernelSetDBATsInternal(table,0xC0001FFF,0x30000012); +} + +/* physical_address is the physical address*/ +void KernelSetDBATsForDynamicFuction(bat_table_t * table, unsigned int physical_address) +{ + KernelSetDBATsInternal(table,(physical_address & 0xFFFC0000) | 0x0F,(physical_address & 0xFFFC0000) | 0x32); +} + +void KernelSetDBATsInternal(bat_table_t * table, unsigned int high_address, unsigned int low_address) +{ + SC0x36_KernelReadDBATs(table); + bat_table_t bat_table_copy = *table; + + // try to use a free slot + int iUse; + for(iUse = 0; iUse < 7; iUse++) + { + // skip position 5 as it is our main DBAT for our code data + if(iUse == 5) + continue; + + if(bat_table_copy.bat[iUse].h == 0 || bat_table_copy.bat[iUse].l == 0) + { + break; + } + } + + bat_table_copy.bat[iUse].h = high_address; + bat_table_copy.bat[iUse].l = low_address; + + SC0x37_KernelWriteDBATs(&bat_table_copy); +} + + +void KernelRestoreDBATs(bat_table_t * table) +{ + SC0x37_KernelWriteDBATs(table); +} diff --git a/src/kernel/kernel_functions.h b/src/kernel/kernel_functions.h new file mode 100644 index 0000000..a7ea049 --- /dev/null +++ b/src/kernel/kernel_functions.h @@ -0,0 +1,24 @@ +#ifndef __KERNEL_FUNCTIONS_H_ +#define __KERNEL_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "common/kernel_defs.h" +#include "syscalls.h" + +extern ReducedCosAppXmlInfo cosAppXmlInfoStruct; + +void SetupKernelCallback(void); + +void KernelRestoreDBATs(bat_table_t * table); +void KernelSetDBATs(bat_table_t * table); +void KernelSetDBATsForDynamicFuction(bat_table_t * table, unsigned int physical_address); +void KernelSetDBATsInternal(bat_table_t * table, unsigned int high_address, unsigned int low_address); + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_FUNCTIONS_H_ diff --git a/src/kernel/kernel_hooks.S b/src/kernel/kernel_hooks.S new file mode 100644 index 0000000..e2ed3d5 --- /dev/null +++ b/src/kernel/kernel_hooks.S @@ -0,0 +1,135 @@ +# This stuff may need a change in different kernel versions +# This is only needed when launched directly through browser and not SD card. + +.section ".kernel_code" + .globl SaveAndResetDataBATs_And_SRs_hook +SaveAndResetDataBATs_And_SRs_hook: + # setup CTR to the position we need to return to + mflr r5 + mtctr r5 + # set link register to its original value + mtlr r7 + # setup us a nice DBAT for our code data with same region as our code + mfspr r5, 560 + mtspr 570, r5 + mfspr r5, 561 + mtspr 571, r5 + # restore the original kernel instructions that we replaced + lwz r5, 0x34(r3) + lwz r6, 0x38(r3) + lwz r7, 0x3C(r3) + lwz r8, 0x40(r3) + lwz r9, 0x44(r3) + lwz r10, 0x48(r3) + lwz r11, 0x4C(r3) + lwz r3, 0x50(r3) + isync + mtsr 7, r5 + # jump back to the position in kernel after our patch (from LR) + bctr + +.extern my_PrepareTitle + .globl my_PrepareTitle_hook +my_PrepareTitle_hook: + # store all registers on stack to avoid issues with the call to C functions + stwu r1, -0x90(r1) + # registers for our own usage + # only need r31 and rest is from tests before, just leaving it for later tests + stw r28, 0x20(r1) + stw r29, 0x24(r1) + stw r30, 0x28(r1) + stw r31, 0x2C(r1) + + stw r3, 0x30(r1) + stw r4, 0x34(r1) + stw r5, 0x38(r1) + stw r6, 0x3C(r1) + stw r7, 0x40(r1) + stw r8, 0x44(r1) + stw r9, 0x48(r1) + stw r10, 0x4C(r1) + stw r11, 0x50(r1) + stw r12, 0x54(r1) + stw r13, 0x58(r1) + stw r14, 0x5C(r1) + stw r15, 0x60(r1) + stw r16, 0x64(r1) + stw r17, 0x68(r1) + stw r18, 0x6C(r1) + stw r19, 0x70(r1) + stw r20, 0x74(r1) + stw r21, 0x78(r1) + stw r22, 0x7C(r1) + + # save original DBAT registers + mfdbatu r28, 0 + mfdbatl r29, 0 + + # setup access to our data memory range + lis r3, 0xC000 + ori r3, r3, 0x1FFF + mtdbatu 0, r3 + lis r3, 0x3000 + ori r3, r3, 0x0012 + mtdbatl 0, r3 + + # memory barrier + eieio + isync + + # save the LR from where we came + mflr r31 + + # the cos.xml/app.xml structure is at the location 0x68 of r11 + # there are actually many places that can be hooked for it + # e.g. 0xFFF16130 and r27 points to this structure + addi r3, r11, 0x68 + + bl my_PrepareTitle + + # restore original DBAT registers + mtdbatu 0, r28 + mtdbatl 0, r29 + + # memory barrier + eieio + isync + + # setup LR to jump back to kernel code + mtlr r31 + + # restore all original values of registers from stack + lwz r28, 0x20(r1) + lwz r29, 0x24(r1) + lwz r30, 0x28(r1) + lwz r31, 0x2C(r1) + + lwz r3, 0x30(r1) + lwz r4, 0x34(r1) + lwz r5, 0x38(r1) + lwz r6, 0x3C(r1) + lwz r7, 0x40(r1) + lwz r8, 0x44(r1) + lwz r9, 0x48(r1) + lwz r10, 0x4C(r1) + lwz r11, 0x50(r1) + lwz r12, 0x54(r1) + lwz r13, 0x58(r1) + lwz r14, 0x5C(r1) + lwz r15, 0x60(r1) + lwz r16, 0x64(r1) + lwz r17, 0x68(r1) + lwz r18, 0x6C(r1) + lwz r19, 0x70(r1) + lwz r20, 0x74(r1) + lwz r21, 0x78(r1) + lwz r22, 0x7C(r1) + + # restore the stack + addi r1, r1, 0x90 + + # restore original instruction that we replaced in the kernel + clrlwi r7, r12, 0 + + # jump back + blr diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c new file mode 100644 index 0000000..7bce2b1 --- /dev/null +++ b/src/kernel/syscalls.c @@ -0,0 +1,208 @@ +#include "common/os_defs.h" +#include "common/kernel_defs.h" +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "utils/utils.h" +#include "syscalls.h" + +extern void my_PrepareTitle_hook(void); + +static unsigned int origPrepareTitleInstr __attribute__((section(".data"))) = 0; + +static void KernelCopyData(unsigned int addr, unsigned int src, unsigned int len) +{ + /* + * Setup a DBAT access for our 0xC0800000 area and our 0xBC000000 area which hold our variables like GAME_LAUNCHED and our BSS/rodata section + */ + register int dbatu0, dbatl0, dbatu1, dbatl1; + // save the original DBAT value + asm volatile("mfdbatu %0, 0" : "=r" (dbatu0)); + asm volatile("mfdbatl %0, 0" : "=r" (dbatl0)); + asm volatile("mfdbatu %0, 1" : "=r" (dbatu1)); + asm volatile("mfdbatl %0, 1" : "=r" (dbatl1)); + + // write our own DBATs into the array + if( ((addr & 0xFFF00000) == 0xFFF00000) || ((src & 0xFFF00000) == 0xFFF00000) ) + { + // setup kernel code access + unsigned int dbatu = 0; + unsigned int dbatl = 0; + + if((src & 0xFFF00000) == 0xFFF00000) { + dbatu = (src & 0xFFF00000) | 0x02; + dbatl = (src & 0xFFF00000) | 0x32; + } + else { + dbatu = (addr & 0xFFF00000) | 0x02; + dbatl = (addr & 0xFFF00000) | 0x32; + } + + if( ((addr & 0xFFF00000) != (dbatu0 & 0xFFF00000)) && ((src & 0xFFF00000) != (dbatu0 & 0xFFF00000)) ) + { + asm volatile("mtdbatu 0, %0" : : "r" (dbatu)); + asm volatile("mtdbatl 0, %0" : : "r" (dbatl)); + } + else + { + asm volatile("mtdbatu 1, %0" : : "r" (dbatu)); + asm volatile("mtdbatl 1, %0" : : "r" (dbatl)); + } + } + else + { + asm volatile("mtdbatu 0, %0" : : "r" (0xC0001FFF)); + asm volatile("mtdbatl 0, %0" : : "r" (0x30000012)); + asm volatile("mtdbatu 1, %0" : : "r" (0xB0801FFF)); + asm volatile("mtdbatl 1, %0" : : "r" (0x20800012)); + } + asm volatile("eieio; isync"); + + + unsigned char *src_p = (unsigned char*)src; + unsigned char *dst_p = (unsigned char*)addr; + + unsigned int i; + for(i = 0; i < len; i++) + { + dst_p[i] = src_p[i]; + } + + /* + * Restore original DBAT value + */ + asm volatile("mtdbatu 0, %0" : : "r" (dbatu0)); + asm volatile("mtdbatl 0, %0" : : "r" (dbatl0)); + asm volatile("mtdbatu 1, %0" : : "r" (dbatu1)); + asm volatile("mtdbatl 1, %0" : : "r" (dbatl1)); + asm volatile("eieio; isync"); +} + +static void KernelReadDBATs(bat_table_t * table) +{ + u32 i = 0; + + asm volatile("eieio; isync"); + + asm volatile("mfspr %0, 536" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 537" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 538" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 539" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 540" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 541" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 542" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 543" : "=r" (table->bat[i].l)); + i++; + + asm volatile("mfspr %0, 568" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 569" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 570" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 571" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 572" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 573" : "=r" (table->bat[i].l)); + i++; + asm volatile("mfspr %0, 574" : "=r" (table->bat[i].h)); + asm volatile("mfspr %0, 575" : "=r" (table->bat[i].l)); +} + +static void KernelWriteDBATs(bat_table_t * table) +{ + u32 i = 0; + + asm volatile("eieio; isync"); + + asm volatile("mtspr 536, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 537, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 538, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 539, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 540, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 541, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 542, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 543, %0" : : "r" (table->bat[i].l)); + i++; + + asm volatile("mtspr 568, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 569, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 570, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 571, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 572, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 573, %0" : : "r" (table->bat[i].l)); + i++; + asm volatile("mtspr 574, %0" : : "r" (table->bat[i].h)); + asm volatile("mtspr 575, %0" : : "r" (table->bat[i].l)); + + asm volatile("eieio; isync"); +} + +/* Write a 32-bit word with kernel permissions */ +static void __attribute__ ((noinline)) kern_write(void *addr, uint32_t value) +{ + asm volatile ( + "li 3,1\n" + "li 4,0\n" + "mr 5,%1\n" + "li 6,0\n" + "li 7,0\n" + "lis 8,1\n" + "mr 9,%0\n" + "mr %1,1\n" + "li 0,0x3500\n" + "sc\n" + "nop\n" + "mr 1,%1\n" + : + : "r"(addr), "r"(value) + : "memory", "ctr", "lr", "0", "3", "4", "5", "6", "7", "8", "9", "10", + "11", "12" + ); +} + +void KernelSetupSyscalls(void) +{ + //! assign 1 so that this variable gets into the retained .data section + static uint8_t ucSyscallsSetupRequired = 1; + if(!ucSyscallsSetupRequired) + return; + + ucSyscallsSetupRequired = 0; + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x36 * 4)), (unsigned int)KernelReadDBATs); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x37 * 4)), (unsigned int)KernelWriteDBATs); + + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl1 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl2 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl3 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl4 + (0x25 * 4)), (unsigned int)KernelCopyData); + kern_write((void*)(OS_SPECIFICS->addr_KernSyscallTbl5 + (0x25 * 4)), (unsigned int)KernelCopyData); + + //! write our hook to the + u32 addr_my_PrepareTitle_hook = ((u32)my_PrepareTitle_hook) | 0x48000003; + + SC0x25_KernelCopyData((u32)&origPrepareTitleInstr, (u32)addr_PrepareTitle_hook, 4); + SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)&addr_my_PrepareTitle_hook, 4); +} + + +void KernelRestoreInstructions(void) +{ + if(origPrepareTitleInstr != 0) + SC0x25_KernelCopyData((u32)addr_PrepareTitle_hook, (u32)&origPrepareTitleInstr, 4); +} diff --git a/src/kernel/syscalls.h b/src/kernel/syscalls.h new file mode 100644 index 0000000..e5a9dac --- /dev/null +++ b/src/kernel/syscalls.h @@ -0,0 +1,23 @@ +#ifndef __SYSCALLS_H_ +#define __SYSCALLS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "common/kernel_defs.h" + +void KernelSetupSyscalls(void); +void KernelRestoreInstructions(void); + +void SC0x25_KernelCopyData(unsigned int addr, unsigned int src, unsigned int len); +void SC0x36_KernelReadDBATs(bat_table_t * table); +void SC0x37_KernelWriteDBATs(bat_table_t * table); + + +#ifdef __cplusplus +} +#endif + +#endif // __KERNEL_FUNCTIONS_H_ diff --git a/src/kernel/syscalls_asm.S b/src/kernel/syscalls_asm.S new file mode 100644 index 0000000..99e2c82 --- /dev/null +++ b/src/kernel/syscalls_asm.S @@ -0,0 +1,19 @@ +# Syscalls for kernel that we use + + .globl SC0x36_KernelReadDBATs +SC0x36_KernelReadDBATs: + li r0, 0x3600 + sc + blr + + .globl SC0x37_KernelWriteDBATs +SC0x37_KernelWriteDBATs: + li r0, 0x3700 + sc + blr + + .globl SC0x25_KernelCopyData +SC0x25_KernelCopyData: + li r0, 0x2500 + sc + blr diff --git a/src/link.ld b/src/link.ld new file mode 100644 index 0000000..2f20681 --- /dev/null +++ b/src/link.ld @@ -0,0 +1,43 @@ +OUTPUT(ddd.elf); + +/* Tell linker where our application entry is so the garbage collect can work correct */ +ENTRY(__entry_menu); + +SECTIONS { + . = 0x00802000; + .text : { + *(.kernel_code*); + *(.text*); + /* Tell linker to not garbage collect this section as it is not referenced anywhere */ + KEEP(*(.kernel_code*)); + } + .rodata : { + *(.rodata*); + } + .data : { + *(.data*); + + __sdata_start = .; + *(.sdata*); + __sdata_end = .; + + __sdata2_start = .; + *(.sdata2*); + __sdata2_end = .; + } + .bss : { + __bss_start = .; + *(.bss*); + *(.sbss*); + *(COMMON); + __bss_end = .; + } + __CODE_END = .; + + /DISCARD/ : { + *(*); + } +} + +/******************************************************** FS ********************************************************/ +/* coreinit.rpl difference in addresses 0xFE3C00 */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..a39d0ae --- /dev/null +++ b/src/main.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/gx2_functions.h" +#include "dynamic_libs/syshid_functions.h" +#include "dynamic_libs/vpad_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "system/memory.h" +#include "utils/logger.h" +#include "common/common.h" +#include "game/rpx_rpl_table.h" +#include "game/memory_area_table.h" +#include "start.h" +#include "patcher/function_hooks.h" +#include "kernel/kernel_functions.h" +#include "system/exception_handler.h" +#include "fs/fs_utils.h" +#include "fs/sd_fat_devoptab.h" +#include "controller_patcher/controller_patcher.h" + +typedef union u_serv_ip +{ + uint8_t digit[4]; + uint32_t full; +} u_serv_ip; + +#define PRINT_TEXT2(x, y, ...) { snprintf(msg, 80, __VA_ARGS__); OSScreenPutFontEx(0, x, y, msg); OSScreenPutFontEx(1, x, y, msg); } + +/* Entry point */ +int Menu_Main(void) +{ + //!******************************************************************* + //! Initialize function pointers * + //!******************************************************************* + //! do OS (for acquire) and sockets first so we got logging + InitOSFunctionPointers(); + InitSocketFunctionPointers(); + InitGX2FunctionPointers(); + InitSysFunctionPointers(); + + log_init("192.168.0.181"); + + SetupKernelCallback(); + log_printf("Started %s\n", cosAppXmlInfoStruct.rpx_name); + + //!******************************************************************* + //! Initialize HID Config * + //!******************************************************************* + init_config_controller(); + + PatchMethodHooks(); + if(strlen(cosAppXmlInfoStruct.rpx_name) > 0 && strcasecmp("ffl_app.rpx", cosAppXmlInfoStruct.rpx_name) != 0) + { + return EXIT_RELAUNCH_ON_LOAD; + } + + if(strlen(cosAppXmlInfoStruct.rpx_name) <= 0){ // First boot back to SysMenu + log_printf("Startssed %s\n", cosAppXmlInfoStruct.rpx_name); + SYSLaunchMenu(); + return EXIT_RELAUNCH_ON_LOAD; + } + log_printf("Stafdsf %s\n", cosAppXmlInfoStruct.rpx_name); + RestoreInstructions(); + + deinit_config_controller(); + + log_deinit(); + + + return EXIT_SUCCESS; +} + diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..0147292 --- /dev/null +++ b/src/main.h @@ -0,0 +1,19 @@ +#ifndef _MAIN_H_ +#define _MAIN_H_ + +#include "common/types.h" +#include "dynamic_libs/os_functions.h" + +/* Main */ +#ifdef __cplusplus +extern "C" { +#endif + +//! C wrapper for our C++ functions +int Menu_Main(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/patcher/cpp_to_c_util.cpp b/src/patcher/cpp_to_c_util.cpp new file mode 100644 index 0000000..af3d0e7 --- /dev/null +++ b/src/patcher/cpp_to_c_util.cpp @@ -0,0 +1,45 @@ +#include "cpp_to_c_util.h" +#include +#include "common/common.h" +#include "video/shaders/ColorShader.h" + +// TODO: not creating these stuff at every frame +void draw_Cursor_at(f32 x, f32 y) { + f32 widthScaleFactor = 1.0f / (f32)1280; + f32 heightScaleFactor = 1.0f / (f32)720; + + int width = 20; + + glm::vec3 positionOffsets = glm::vec3(0.0f); + + positionOffsets[0] = (x-((1280)/2)+(width/2)) * widthScaleFactor * 2.0f; + positionOffsets[1] = -(y-((720)/2)+(width/2)) * heightScaleFactor * 2.0f; + + u8 colorVtxs[16]; + memset(colorVtxs,0xFF,16*sizeof(u8)); + + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, colorVtxs, 16 * sizeof(u8)); + + glm::vec4 colorIntensity = glm::vec4(1.0f); + colorIntensity[3] = 255; + + glm::vec3 scale(width*widthScaleFactor,width*heightScaleFactor,1.0f); + + ColorShader::instance()->setShaders(); + ColorShader::instance()->setAttributeBuffer(colorVtxs, NULL, 4); + ColorShader::instance()->setAngle(0); + ColorShader::instance()->setOffset(positionOffsets); + ColorShader::instance()->setScale(scale); + ColorShader::instance()->setColorIntensity(colorIntensity); + ColorShader::instance()->draw(GX2_PRIMITIVE_QUADS, 4); +} + + +void draw_Cursor_destroy() { + //! destroy shaders + ColorShader::destroyInstance(); +} + + + + diff --git a/src/patcher/cpp_to_c_util.h b/src/patcher/cpp_to_c_util.h new file mode 100644 index 0000000..b22e9f5 --- /dev/null +++ b/src/patcher/cpp_to_c_util.h @@ -0,0 +1,12 @@ + #ifdef __cplusplus + #define EXTERNC extern "C" + #else + #define EXTERNC + #endif + + #include "../dynamic_libs/gx2_types.h" + + EXTERNC void draw_Cursor_at(f32 x, f32 y); + EXTERNC void draw_Cursor_destroy(); + + #undef EXTERNC diff --git a/src/patcher/function_hooks.c b/src/patcher/function_hooks.c new file mode 100644 index 0000000..167db42 --- /dev/null +++ b/src/patcher/function_hooks.c @@ -0,0 +1,348 @@ +#include +#include +#include +#include "common/common.h" +#include "common/fs_defs.h" +#include "common/loader_defs.h" +#include "controller_patcher/cp_retain_vars.h" +#include "game/rpx_rpl_table.h" +#include "dynamic_libs/aoc_functions.h" +#include "dynamic_libs/ax_functions.h" +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/gx2_functions.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/padscore_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "dynamic_libs/vpad_functions.h" +#include "dynamic_libs/acp_functions.h" +#include "dynamic_libs/syshid_functions.h" +#include "kernel/kernel_functions.h" +#include "system/exception_handler.h" +#include "function_hooks.h" +#include "fs/fs_utils.h" +#include "utils/logger.h" +#include "system/memory.h" + +#include "cpp_to_c_util.h" + +#define LIB_CODE_RW_BASE_OFFSET 0xC1000000 +#define CODE_RW_BASE_OFFSET 0x00000000 +#define DEBUG_LOG_DYN 0 + +#define USE_EXTRA_LOG_FUNCTIONS 0 + +#define DECL(res, name, ...) \ + res (* real_ ## name)(__VA_ARGS__) __attribute__((section(".data"))); \ + res my_ ## name(__VA_ARGS__) + +DECL(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32 scan_target){ + + if(gHIDCurrentDevice & HID_LIST_MOUSE && gHID_Mouse_Mode == HID_MOUSE_MODE_TOUCH) { + draw_Cursor_at(gHID_Mouse.pad_data[0].data[0].X, gHID_Mouse.pad_data[0].data[0].Y); + } + real_GX2CopyColorBufferToScanBuffer(colorBuffer,scan_target); +} + +DECL(void, _Exit, void){ + draw_Cursor_destroy(); + real__Exit(); +} + +DECL(int, VPADRead, int chan, VPADData *buffer, u32 buffer_size, s32 *error) { + + int result = real_VPADRead(chan, buffer, buffer_size, error); + + if(gHIDAttached){ + setControllerDataFromHID(buffer,gHIDCurrentDevice); + } + + return result; +} + +/* ***************************************************************************** + * Creates function pointer array + * ****************************************************************************/ +#define MAKE_MAGIC(x, lib,functionType) { (unsigned int) my_ ## x, (unsigned int) &real_ ## x, lib, # x,0,0,functionType,0} + +static struct hooks_magic_t { + const unsigned int replaceAddr; + const unsigned int replaceCall; + const unsigned int library; + const char functionName[50]; + unsigned int realAddr; + unsigned int restoreInstruction; + unsigned char functionType; + unsigned char alreadyPatched; +} method_hooks[] = { + // Common FS functions + MAKE_MAGIC(VPADRead, LIB_VPAD,STATIC_FUNCTION), + MAKE_MAGIC(GX2CopyColorBufferToScanBuffer, LIB_GX2,STATIC_FUNCTION), + MAKE_MAGIC(_Exit, LIB_CORE_INIT,STATIC_FUNCTION), +}; + +//! buffer to store our 7 instructions needed for our replacements +//! the code will be placed in the address of that buffer - CODE_RW_BASE_OFFSET +//! avoid this buffer to be placed in BSS and reset on start up +volatile unsigned int dynamic_method_calls[sizeof(method_hooks) / sizeof(struct hooks_magic_t) * 7] __attribute__((section(".data"))); + +/* +*Patches a function that is loaded at the start of each application. Its not required to restore, at least when they are really dynamic. +* "normal" functions should be patch with the normal patcher. +*/ +void PatchMethodHooks(void) +{ + /* Patch branches to it. */ + volatile unsigned int *space = &dynamic_method_calls[0]; + + int method_hooks_count = sizeof(method_hooks) / sizeof(struct hooks_magic_t); + + u32 skip_instr = 1; + u32 my_instr_len = 6; + u32 instr_len = my_instr_len + skip_instr; + u32 flush_len = 4*instr_len; + for(int i = 0; i < method_hooks_count; i++) + { + if(method_hooks[i].functionType == STATIC_FUNCTION && method_hooks[i].alreadyPatched == 1){ + if(isDynamicFunction((u32)OSEffectiveToPhysical((void*)method_hooks[i].realAddr))){ + log_printf("The function %s is a dynamic function. Please fix that <3\n", method_hooks[i].functionName); + method_hooks[i].functionType = DYNAMIC_FUNCTION; + }else{ + log_printf("Skipping %s, its already patched\n", method_hooks[i].functionName); + space += instr_len; + continue; + } + } + + u32 physical = 0; + unsigned int repl_addr = (unsigned int)method_hooks[i].replaceAddr; + unsigned int call_addr = (unsigned int)method_hooks[i].replaceCall; + + unsigned int real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library); + + if(!real_addr){ + log_printf("OSDynLoad_FindExport failed for %s\n", method_hooks[i].functionName); + space += instr_len; + continue; + } + + if(DEBUG_LOG_DYN)log_printf("%s is located at %08X!\n", method_hooks[i].functionName,real_addr); + + physical = (u32)OSEffectiveToPhysical((void*)real_addr); + if(!physical){ + log_printf("Something is wrong with the physical address\n"); + space += instr_len; + continue; + } + + if(DEBUG_LOG_DYN)log_printf("%s physical is located at %08X!\n", method_hooks[i].functionName,physical); + + bat_table_t my_dbat_table; + if(DEBUG_LOG_DYN)log_printf("Setting up DBAT\n"); + KernelSetDBATsForDynamicFuction(&my_dbat_table,physical); + + //log_printf("Setting call_addr to %08X\n",(unsigned int)(space) - CODE_RW_BASE_OFFSET); + *(volatile unsigned int *)(call_addr) = (unsigned int)(space) - CODE_RW_BASE_OFFSET; + + // copy instructions from real function. + u32 offset_ptr = 0; + for(offset_ptr = 0;offset_ptr> 16) & 0x0000FFFF); // lis r3, real_addr@h + space++; + *space = 0x60630000 | ((real_addr + (skip_instr * 4)) & 0x0000ffff); // ori r3, r3, real_addr@l + space++; + *space = 0x7C6903A6; // mtctr r3 + space++; + *space = 0x8061FFE0; // lwz r3,-32(r1) + space++; + *space = 0x4E800420; // bctr + space++; + DCFlushRange((void*)(space - instr_len), flush_len); + ICInvalidateRange((unsigned char*)(space - instr_len), flush_len); + + //setting jump back + unsigned int replace_instr = 0x48000002 | (repl_addr & 0x03fffffc); + *(volatile unsigned int *)(physical) = replace_instr; + ICInvalidateRange((void*)(real_addr), 4); + + //restore my dbat stuff + KernelRestoreDBATs(&my_dbat_table); + + method_hooks[i].alreadyPatched = 1; + } + log_print("Done with patching all functions!\n"); +} + +/* ****************************************************************** */ +/* RESTORE ORIGINAL INSTRUCTIONS */ +/* ****************************************************************** */ +void RestoreInstructions(void) +{ + bat_table_t table; + KernelSetDBATs(&table); + log_printf("Restore functions!\n"); + int method_hooks_count = sizeof(method_hooks) / sizeof(struct hooks_magic_t); + for(int i = 0; i < method_hooks_count; i++) + { + if(method_hooks[i].restoreInstruction == 0 || method_hooks[i].realAddr == 0){ + log_printf("I dont have the information for the restore =( skip\n"); + continue; + } + + unsigned int real_addr = GetAddressOfFunction(method_hooks[i].functionName,method_hooks[i].library); + + if(!real_addr){ + log_printf("OSDynLoad_FindExport failed for %s\n", method_hooks[i].functionName); + continue; + } + + u32 physical = (u32)OSEffectiveToPhysical((void*)real_addr); + if(!physical){ + log_printf("Something is wrong with the physical address\n"); + continue; + } + + if(isDynamicFunction(physical)){ + log_printf("Its a dynamic function. We don't need to restore it! %s\n",method_hooks[i].functionName); + }else{ + KernelSetDBATs(&table); + + *(volatile unsigned int *)(LIB_CODE_RW_BASE_OFFSET + method_hooks[i].realAddr) = method_hooks[i].restoreInstruction; + DCFlushRange((void*)(LIB_CODE_RW_BASE_OFFSET + method_hooks[i].realAddr), 4); + ICInvalidateRange((void*)method_hooks[i].realAddr, 4); + log_printf("Restored %s\n",method_hooks[i].functionName); + KernelRestoreDBATs(&table); + } + method_hooks[i].alreadyPatched = 0; // In case a + } + KernelRestoreInstructions(); + log_print("Done with restoring all functions!\n"); +} + +int isDynamicFunction(unsigned int physicalAddress){ + if((physicalAddress & 0x80000000) == 0x80000000){ + return 1; + } + return 0; +} + +unsigned int GetAddressOfFunction(const char * functionName,unsigned int library){ + unsigned int real_addr = 0; + + unsigned int rpl_handle = 0; + if(library == LIB_CORE_INIT){ + log_printf("FindExport of %s! From LIB_CORE_INIT\n", functionName); + if(coreinit_handle == 0){log_print("LIB_CORE_INIT not aquired\n"); return 0;} + rpl_handle = coreinit_handle; + } + else if(library == LIB_NSYSNET){ + log_printf("FindExport of %s! From LIB_NSYSNET\n", functionName); + if(nsysnet_handle == 0){log_print("LIB_NSYSNET not aquired\n"); return 0;} + rpl_handle = nsysnet_handle; + } + else if(library == LIB_GX2){ + log_printf("FindExport of %s! From LIB_GX2\n", functionName); + if(gx2_handle == 0){log_print("LIB_GX2 not aquired\n"); return 0;} + rpl_handle = gx2_handle; + } + else if(library == LIB_AOC){ + log_printf("FindExport of %s! From LIB_AOC\n", functionName); + if(aoc_handle == 0){log_print("LIB_AOC not aquired\n"); return 0;} + rpl_handle = aoc_handle; + } + else if(library == LIB_AX){ + log_printf("FindExport of %s! From LIB_AX\n", functionName); + if(sound_handle == 0){log_print("LIB_AX not aquired\n"); return 0;} + rpl_handle = sound_handle; + } + else if(library == LIB_FS){ + log_printf("FindExport of %s! From LIB_FS\n", functionName); + if(coreinit_handle == 0){log_print("LIB_FS not aquired\n"); return 0;} + rpl_handle = coreinit_handle; + } + else if(library == LIB_OS){ + log_printf("FindExport of %s! From LIB_OS\n", functionName); + if(coreinit_handle == 0){log_print("LIB_OS not aquired\n"); return 0;} + rpl_handle = coreinit_handle; + } + else if(library == LIB_PADSCORE){ + log_printf("FindExport of %s! From LIB_PADSCORE\n", functionName); + if(padscore_handle == 0){log_print("LIB_PADSCORE not aquired\n"); return 0;} + rpl_handle = padscore_handle; + } + else if(library == LIB_SOCKET){ + log_printf("FindExport of %s! From LIB_SOCKET\n", functionName); + if(nsysnet_handle == 0){log_print("LIB_SOCKET not aquired\n"); return 0;} + rpl_handle = nsysnet_handle; + } + else if(library == LIB_SYS){ + log_printf("FindExport of %s! From LIB_SYS\n", functionName); + if(sysapp_handle == 0){log_print("LIB_SYS not aquired\n"); return 0;} + rpl_handle = sysapp_handle; + } + else if(library == LIB_VPAD){ + log_printf("FindExport of %s! From LIB_VPAD\n", functionName); + if(vpad_handle == 0){log_print("LIB_VPAD not aquired\n"); return 0;} + rpl_handle = vpad_handle; + } + else if(library == LIB_NN_ACP){ + log_printf("FindExport of %s! From LIB_NN_ACP\n", functionName); + if(acp_handle == 0){log_print("LIB_NN_ACP not aquired\n"); return 0;} + rpl_handle = acp_handle; + } + else if(library == LIB_SYSHID){ + log_printf("FindExport of %s! From LIB_SYSHID\n", functionName); + if(syshid_handle == 0){log_print("LIB_SYSHID not aquired\n"); return 0;} + rpl_handle = syshid_handle; + } + else if(library == LIB_VPADBASE){ + log_printf("FindExport of %s! From LIB_VPADBASE\n", functionName); + if(vpadbase_handle == 0){log_print("LIB_VPADBASE not aquired\n"); return 0;} + rpl_handle = vpadbase_handle; + } + + if(!rpl_handle){ + log_printf("Failed to find the RPL handle for %s\n", functionName); + return 0; + } + + OSDynLoad_FindExport(rpl_handle, 0, functionName, &real_addr); + + if(!real_addr){ + log_printf("OSDynLoad_FindExport failed for %s\n", functionName); + return 0; + } + + if((u32)(*(volatile unsigned int*)(real_addr) & 0xFF000000) == 0x48000000){ + real_addr += (u32)(*(volatile unsigned int*)(real_addr) & 0x0000FFFF); + if((u32)(*(volatile unsigned int*)(real_addr) & 0xFF000000) == 0x48000000){ + return 0; + } + } + + return real_addr; +} diff --git a/src/patcher/function_hooks.h b/src/patcher/function_hooks.h new file mode 100644 index 0000000..79d0b28 --- /dev/null +++ b/src/patcher/function_hooks.h @@ -0,0 +1,41 @@ +#ifndef _FUNCTION_HOOKS_H_ +#define _FUNCTION_HOOKS_H_ + +#include "dynamic_libs/syshid_functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/* Forward declarations */ +#define MAX_CLIENT 32 + +struct bss_t { + int global_sock; + int socket_fs[MAX_CLIENT]; + void *pClient_fs[MAX_CLIENT]; + volatile int lock; + char mount_base[255]; + char save_base[255]; + void* file_replacer; + char update_path[50]; + char save_dir_common[7]; + char save_dir_user[9]; +}; + +#define bss_ptr (*(struct bss_t **)0x100000e4) +#define bss (*bss_ptr) + +void PatchMethodHooks(void); +void RestoreInstructions(void); +unsigned int GetAddressOfFunction(const char * functionName,unsigned int library); +int isDynamicFunction(unsigned int physicalAddress); +void PatchSDK(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _FS_H */ diff --git a/src/start.c b/src/start.c new file mode 100644 index 0000000..f746af5 --- /dev/null +++ b/src/start.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include "common/kernel_defs.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/fs_functions.h" +#include "dynamic_libs/aoc_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "dynamic_libs/sys_functions.h" +#include "game/rpx_rpl_table.h" +#include "game/memory_area_table.h" +#include "utils/net.h" +#include "start.h" + +void StartFunction() +{ +} + +void Reset(void) +{ + +} + + diff --git a/src/start.h b/src/start.h new file mode 100644 index 0000000..ac72c4a --- /dev/null +++ b/src/start.h @@ -0,0 +1,18 @@ +#ifndef _DISCDUMPER_H_ +#define _DISCDUMPER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void StartFunction(void); +void Reset(void); + +void SetServerIp(u32 ip); +u32 GetServerIp(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/system/exception_handler.c b/src/system/exception_handler.c new file mode 100644 index 0000000..b642248 --- /dev/null +++ b/src/system/exception_handler.c @@ -0,0 +1,169 @@ +#include +#include "dynamic_libs/os_functions.h" +#include "utils/logger.h" +#include "exception_handler.h" + +#define OS_EXCEPTION_MODE_GLOBAL_ALL_CORES 4 + +#define OS_EXCEPTION_DSI 2 +#define OS_EXCEPTION_ISI 3 +#define OS_EXCEPTION_PROGRAM 6 + +/* Exceptions */ +typedef struct OSContext +{ + /* OSContext identifier */ + uint32_t tag1; + uint32_t tag2; + + /* GPRs */ + uint32_t gpr[32]; + + /* Special registers */ + uint32_t cr; + uint32_t lr; + uint32_t ctr; + uint32_t xer; + + /* Initial PC and MSR */ + uint32_t srr0; + uint32_t srr1; + + /* Only valid during DSI exception */ + uint32_t exception_specific0; + uint32_t exception_specific1; + + /* There is actually a lot more here but we don't need the rest*/ +} OSContext; + +#define CPU_STACK_TRACE_DEPTH 10 +#define __stringify(rn) #rn + +#define mfspr(_rn) \ +({ register uint32_t _rval = 0; \ + asm volatile("mfspr %0," __stringify(_rn) \ + : "=r" (_rval));\ + _rval; \ +}) + +typedef struct _framerec { + struct _framerec *up; + void *lr; +} frame_rec, *frame_rec_t; + +static const char *exception_names[] = { + "DSI", + "ISI", + "PROGRAM" +}; + +static const char exception_print_formats[18][45] = { + "Exception type %s occurred!\n", // 0 + "GPR00 %08X GPR08 %08X GPR16 %08X GPR24 %08X\n", // 1 + "GPR01 %08X GPR09 %08X GPR17 %08X GPR25 %08X\n", // 2 + "GPR02 %08X GPR10 %08X GPR18 %08X GPR26 %08X\n", // 3 + "GPR03 %08X GPR11 %08X GPR19 %08X GPR27 %08X\n", // 4 + "GPR04 %08X GPR12 %08X GPR20 %08X GPR28 %08X\n", // 5 + "GPR05 %08X GPR13 %08X GPR21 %08X GPR29 %08X\n", // 6 + "GPR06 %08X GPR14 %08X GPR22 %08X GPR30 %08X\n", // 7 + "GPR07 %08X GPR15 %08X GPR23 %08X GPR31 %08X\n", // 8 + "LR %08X SRR0 %08x SRR1 %08x\n", // 9 + "DAR %08X DSISR %08X\n", // 10 + "\nSTACK DUMP:", // 11 + " --> ", // 12 + " -->\n", // 13 + "\n", // 14 + "%p", // 15 + "\nCODE DUMP:\n", // 16 + "%p: %08X %08X %08X %08X\n", // 17 +}; + +static unsigned char exception_cb(void * c, unsigned char exception_type) { + char buf[850]; + int pos = 0; + + OSContext *context = (OSContext *) c; + /* + * This part is mostly from libogc. Thanks to the devs over there. + */ + pos += sprintf(buf + pos, exception_print_formats[0], exception_names[exception_type]); + pos += sprintf(buf + pos, exception_print_formats[1], context->gpr[0], context->gpr[8], context->gpr[16], context->gpr[24]); + pos += sprintf(buf + pos, exception_print_formats[2], context->gpr[1], context->gpr[9], context->gpr[17], context->gpr[25]); + pos += sprintf(buf + pos, exception_print_formats[3], context->gpr[2], context->gpr[10], context->gpr[18], context->gpr[26]); + pos += sprintf(buf + pos, exception_print_formats[4], context->gpr[3], context->gpr[11], context->gpr[19], context->gpr[27]); + pos += sprintf(buf + pos, exception_print_formats[5], context->gpr[4], context->gpr[12], context->gpr[20], context->gpr[28]); + pos += sprintf(buf + pos, exception_print_formats[6], context->gpr[5], context->gpr[13], context->gpr[21], context->gpr[29]); + pos += sprintf(buf + pos, exception_print_formats[7], context->gpr[6], context->gpr[14], context->gpr[22], context->gpr[30]); + pos += sprintf(buf + pos, exception_print_formats[8], context->gpr[7], context->gpr[15], context->gpr[23], context->gpr[31]); + pos += sprintf(buf + pos, exception_print_formats[9], context->lr, context->srr0, context->srr1); + + //if(exception_type == OS_EXCEPTION_DSI) { + pos += sprintf(buf + pos, exception_print_formats[10], context->exception_specific1, context->exception_specific0); // this freezes + //} + + void *pc = (void*)context->srr0; + void *lr = (void*)context->lr; + void *r1 = (void*)context->gpr[1]; + register uint32_t i = 0; + register frame_rec_t l,p = (frame_rec_t)lr; + + l = p; + p = r1; + if(!p) + asm volatile("mr %0,%%r1" : "=r"(p)); + + pos += sprintf(buf + pos, exception_print_formats[11]); + + for(i = 0; i < CPU_STACK_TRACE_DEPTH-1 && p->up; p = p->up, i++) { + if(i % 4) + pos += sprintf(buf + pos, exception_print_formats[12]); + else { + if(i > 0) + pos += sprintf(buf + pos, exception_print_formats[13]); + else + pos += sprintf(buf + pos, exception_print_formats[14]); + } + + switch(i) { + case 0: + if(pc) + pos += sprintf(buf + pos, exception_print_formats[15],pc); + break; + case 1: + if(!l) + l = (frame_rec_t)mfspr(8); + pos += sprintf(buf + pos, exception_print_formats[15],(void*)l); + break; + default: + pos += sprintf(buf + pos, exception_print_formats[15],(void*)(p->up->lr)); + break; + } + } + + //if(exception_type == OS_EXCEPTION_DSI) { + uint32_t *pAdd = (uint32_t*)context->srr0; + pos += sprintf(buf + pos, exception_print_formats[16]); + // TODO by Dimok: this was actually be 3 instead of 2 lines in libogc .... but there is just no more space anymore on the screen + for (i = 0; i < 8; i += 4) + pos += sprintf(buf + pos, exception_print_formats[17], &(pAdd[i]),pAdd[i], pAdd[i+1], pAdd[i+2], pAdd[i+3]); + //} + log_print(buf); + OSFatal(buf); + return 1; +} + +static unsigned char dsi_exception_cb(void * context) { + return exception_cb(context, 0); +} +static unsigned char isi_exception_cb(void * context) { + return exception_cb(context, 1); +} +static unsigned char program_exception_cb(void * context) { + return exception_cb(context, 2); +} + +void setup_os_exceptions(void) { + OSSetExceptionCallback(OS_EXCEPTION_DSI, &dsi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_ISI, &isi_exception_cb); + OSSetExceptionCallback(OS_EXCEPTION_PROGRAM, &program_exception_cb); +} diff --git a/src/system/exception_handler.h b/src/system/exception_handler.h new file mode 100644 index 0000000..7626f92 --- /dev/null +++ b/src/system/exception_handler.h @@ -0,0 +1,14 @@ +#ifndef __EXCEPTION_HANDLER_H_ +#define __EXCEPTION_HANDLER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void setup_os_exceptions(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/system/memory.c b/src/system/memory.c new file mode 100644 index 0000000..91f5392 --- /dev/null +++ b/src/system/memory.c @@ -0,0 +1,198 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "dynamic_libs/os_functions.h" +#include "common/common.h" +#include "memory.h" + +#define MEMORY_ARENA_1 0 +#define MEMORY_ARENA_2 1 +#define MEMORY_ARENA_3 2 +#define MEMORY_ARENA_4 3 +#define MEMORY_ARENA_5 4 +#define MEMORY_ARENA_6 5 +#define MEMORY_ARENA_7 6 +#define MEMORY_ARENA_8 7 +#define MEMORY_ARENA_FG_BUCKET 8 + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Memory functions +//! This is the only place where those are needed so lets keep them more or less private +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern unsigned int * pMEMAllocFromDefaultHeapEx; +extern unsigned int * pMEMAllocFromDefaultHeap; +extern unsigned int * pMEMFreeToDefaultHeap; + +extern int (* MEMGetBaseHeapHandle)(int mem_arena); +extern unsigned int (* MEMGetAllocatableSizeForFrmHeapEx)(int heap, int align); +extern void *(* MEMAllocFromFrmHeapEx)(int heap, unsigned int size, int align); +extern void (* MEMFreeToFrmHeap)(int heap, int mode); +extern void *(* MEMAllocFromExpHeapEx)(int heap, unsigned int size, int align); +extern int (* MEMCreateExpHeapEx)(void* address, unsigned int size, unsigned short flags); +extern void *(* MEMDestroyExpHeap)(int heap); +extern void (* MEMFreeToExpHeap)(int heap, void* ptr); + +static int mem1_heap = -1; +static int bucket_heap = -1; + +void memoryInitialize(void) +{ + int mem1_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_1); + unsigned int mem1_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(mem1_heap_handle, 4); + void *mem1_memory = MEMAllocFromFrmHeapEx(mem1_heap_handle, mem1_allocatable_size, 4); + if(mem1_memory) + mem1_heap = MEMCreateExpHeapEx(mem1_memory, mem1_allocatable_size, 0); + + int bucket_heap_handle = MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET); + unsigned int bucket_allocatable_size = MEMGetAllocatableSizeForFrmHeapEx(bucket_heap_handle, 4); + void *bucket_memory = MEMAllocFromFrmHeapEx(bucket_heap_handle, bucket_allocatable_size, 4); + if(bucket_memory) + bucket_heap = MEMCreateExpHeapEx(bucket_memory, bucket_allocatable_size, 0); +} + +void memoryRelease(void) +{ + MEMDestroyExpHeap(mem1_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_1), 3); + mem1_heap = -1; + + MEMDestroyExpHeap(bucket_heap); + MEMFreeToFrmHeap(MEMGetBaseHeapHandle(MEMORY_ARENA_FG_BUCKET), 3); + bucket_heap = -1; +} + +//!------------------------------------------------------------------------------------------- +//! wraps +//!------------------------------------------------------------------------------------------- +void *__wrap_malloc(size_t size) +{ + // pointer to a function resolve + return ((void * (*)(size_t))(*pMEMAllocFromDefaultHeap))(size); +} + +void *__wrap_memalign(size_t align, size_t size) +{ + if (align < 4) + align = 4; + + // pointer to a function resolve + return ((void * (*)(size_t, size_t))(*pMEMAllocFromDefaultHeapEx))(size, align); +} + +void __wrap_free(void *p) +{ + // pointer to a function resolve + if(p != 0) + ((void (*)(void *))(*pMEMFreeToDefaultHeap))(p); +} + +void *__wrap_calloc(size_t n, size_t size) +{ + void *p = __wrap_malloc(n * size); + if (p != 0) { + memset(p, 0, n * size); + } + return p; +} + +size_t __wrap_malloc_usable_size(void *p) +{ + //! TODO: this is totally wrong and needs to be addressed + return 0x7FFFFFFF; +} + +void *__wrap_realloc(void *p, size_t size) +{ + void *new_ptr = __wrap_malloc(size); + if (new_ptr != 0) + { + memcpy(new_ptr, p, __wrap_malloc_usable_size(p) < size ? __wrap_malloc_usable_size(p) : size); + __wrap_free(p); + } + return new_ptr; +} + +//!------------------------------------------------------------------------------------------- +//! reent versions +//!------------------------------------------------------------------------------------------- +void *__wrap__malloc_r(struct _reent *r, size_t size) +{ + return __wrap_malloc(size); +} + +void *__wrap__calloc_r(struct _reent *r, size_t n, size_t size) +{ + return __wrap_calloc(n, size); +} + +void *__wrap__memalign_r(struct _reent *r, size_t align, size_t size) +{ + return __wrap_memalign(align, size); +} + +void __wrap__free_r(struct _reent *r, void *p) +{ + __wrap_free(p); +} + +size_t __wrap__malloc_usable_size_r(struct _reent *r, void *p) +{ + return __wrap_malloc_usable_size(p); +} + +void *__wrap__realloc_r(struct _reent *r, void *p, size_t size) +{ + return __wrap_realloc(p, size); +} + +//!------------------------------------------------------------------------------------------- +//! some wrappers +//!------------------------------------------------------------------------------------------- +void * MEM2_alloc(unsigned int size, unsigned int align) +{ + return __wrap_memalign(align, size); +} + +void MEM2_free(void *ptr) +{ + __wrap_free(ptr); +} + +void * MEM1_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(mem1_heap, size, align); +} + +void MEM1_free(void *ptr) +{ + MEMFreeToExpHeap(mem1_heap, ptr); +} + +void * MEMBucket_alloc(unsigned int size, unsigned int align) +{ + if (align < 4) + align = 4; + return MEMAllocFromExpHeapEx(bucket_heap, size, align); +} + +void MEMBucket_free(void *ptr) +{ + MEMFreeToExpHeap(bucket_heap, ptr); +} diff --git a/src/system/memory.h b/src/system/memory.h new file mode 100644 index 0000000..59764d0 --- /dev/null +++ b/src/system/memory.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef __MEMORY_H_ +#define __MEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +void memoryInitialize(void); +void memoryRelease(void); + +void * MEM2_alloc(unsigned int size, unsigned int align); +void MEM2_free(void *ptr); + +void * MEM1_alloc(unsigned int size, unsigned int align); +void MEM1_free(void *ptr); + +void * MEMBucket_alloc(unsigned int size, unsigned int align); +void MEMBucket_free(void *ptr); + +#ifdef __cplusplus +} +#endif + +#endif // __MEMORY_H_ diff --git a/src/utils/logger.c b/src/utils/logger.c new file mode 100644 index 0000000..f4795b4 --- /dev/null +++ b/src/utils/logger.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "logger.h" + +#ifdef DEBUG_LOGGER +static int log_socket = -1; +static volatile int log_lock = 0; + + +void log_init(const char * ipString) +{ + log_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (log_socket < 0) + return; + + struct sockaddr_in connect_addr; + memset(&connect_addr, 0, sizeof(connect_addr)); + connect_addr.sin_family = AF_INET; + connect_addr.sin_port = 4405; + inet_aton(ipString, &connect_addr.sin_addr); + + if(connect(log_socket, (struct sockaddr*)&connect_addr, sizeof(connect_addr)) < 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_deinit(void) +{ + if(log_socket >= 0) + { + socketclose(log_socket); + log_socket = -1; + } +} + +void log_print(const char *str) +{ + // socket is always 0 initially as it is in the BSS + if(log_socket < 0) { + return; + } + + while(log_lock) + usleep(1000); + log_lock = 1; + + int len = strlen(str); + int ret; + while (len > 0) { + int block = len < 1400 ? len : 1400; // take max 1400 bytes per UDP packet + ret = send(log_socket, str, block, 0); + if(ret < 0) + break; + + len -= ret; + str += ret; + } + + log_lock = 0; +} + +void log_printf(const char *format, ...) +{ + if(log_socket < 0) { + return; + } + + char * tmp = NULL; + + va_list va; + va_start(va, format); + if((vasprintf(&tmp, format, va) >= 0) && tmp) + { + log_print(tmp); + } + va_end(va); + + if(tmp) + free(tmp); +} +#endif diff --git a/src/utils/logger.h b/src/utils/logger.h new file mode 100644 index 0000000..dd7cc71 --- /dev/null +++ b/src/utils/logger.h @@ -0,0 +1,26 @@ +#ifndef __LOGGER_H_ +#define __LOGGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEBUG_LOGGER 1 + +#ifdef DEBUG_LOGGER +void log_init(const char * ip); +void log_deinit(void); +void log_print(const char *str); +void log_printf(const char *format, ...); +#else +#define log_init(x) +#define log_deinit() +#define log_print(x) +#define log_printf(x, ...) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/utils/net.c b/src/utils/net.c new file mode 100644 index 0000000..e2d7b3c --- /dev/null +++ b/src/utils/net.c @@ -0,0 +1,636 @@ +#include +#include +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "net.h" + +#define CHECK_ERROR(cond) if (cond) { goto error; } + + +#include +#include +#include "common/common.h" +#include "dynamic_libs/os_functions.h" +#include "dynamic_libs/socket_functions.h" +#include "net.h" + +static volatile int iLock = 0; + +#define CHECK_ERROR(cond) if (cond) { goto error; } + +void cafiine_connect(int *psock,u32 server_ip) { + struct sockaddr_in addr; + int sock, ret; + + socket_lib_init(); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + CHECK_ERROR(sock == -1); + + addr.sin_family = AF_INET; + addr.sin_port = 7332; + addr.sin_addr.s_addr = server_ip; + + ret = connect(sock, (void *)&addr, sizeof(addr)); + CHECK_ERROR(ret < 0); + ret = cafiine_handshake(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_NORMAL); + + *psock = sock; + return; +error: + if (sock != -1) + socketclose(sock); + *psock = -1; + return; +} + +void cafiine_disconnect(int sock) { + CHECK_ERROR(sock == -1); + socketclose(sock); +error: + return; +} + +int cafiine_handshake(int sock) { + int ret; + + unsigned char buffer[16]; + + u64 title_id = OSGetTitleID(); + memcpy(buffer, &title_id, 16); + + ret = sendwait(sock, buffer, sizeof(buffer)); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + return ret; +error: + return ret; +} + +int getMode(int sock,int * result) +{ + int ret = 0; + CHECK_ERROR(sock == -1); + + // create and send buffer with : [cmd id][fd][size][buffer data ...] + { + ret = sendbyte(sock, BYTE_G_MODE); + + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + if(ret == BYTE_MODE_D) *result = BYTE_MODE_D; + if(ret == BYTE_MODE_I) *result = BYTE_MODE_I; + ret = 1; + } +error: + return ret; +} + +int cafiine_fsetpos(int sock, int *result, int fd, int set) { + + CHECK_ERROR(sock == -1); + + int ret; + char buffer[1 + 8]; + buffer[0] = BYTE_SETPOS; + *(int *)(buffer + 1) = fd; + *(int *)(buffer + 5) = set; + ret = sendwait(sock, buffer, 1 + 8); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_NORMAL); + ret = recvwait(sock, result, 4); + CHECK_ERROR(ret < 0); + + + return 0; +error: + return -1; +} + +int cafiine_send_handle(int sock, const char *path, int handle) +{ + + + CHECK_ERROR(sock == -1); + + // create and send buffer with : [cmd id][handle][path length][path data ...] + { + int ret; + int len_path = 0; + while (path[len_path++]); + char buffer[1 + 4 + 4 + len_path]; + + buffer[0] = BYTE_HANDLE; + *(int *)(buffer + 1) = handle; + *(int *)(buffer + 5) = len_path; + for (ret = 0; ret < len_path; ret++) + buffer[9 + ret] = path[ret]; + + // send buffer, wait for reply + ret = sendwait(sock, buffer, 1 + 4 + 4 + len_path); + CHECK_ERROR(ret < 0); + + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_SPECIAL); + if(ret == BYTE_REQUEST){ + ret = 1; + }else{ + ret = 2; + } + // wait reply + int special_ret = recvbyte(sock); + CHECK_ERROR(special_ret < 0); + CHECK_ERROR(special_ret != BYTE_SPECIAL); + + return ret; + } + +error: + + return -1; +} + +int cafiine_fopen(int sock, int *result, const char *path, const char *mode, int *handle) { + + + int final_result = -1; + CHECK_ERROR(sock == -1); + + int ret; + int len_path = 0; + while (path[len_path++]); + int len_mode = 0; + while (mode[len_mode++]); + + // + { + char buffer[1 + 8 + len_path + len_mode]; + buffer[0] = BYTE_OPEN; + *(int *)(buffer + 1) = len_path; + *(int *)(buffer + 5) = len_mode; + for (ret = 0; ret < len_path; ret++) + buffer[9 + ret] = path[ret]; + for (ret = 0; ret < len_mode; ret++) + buffer[9 + len_path + ret] = mode[ret]; + + ret = sendwait(sock, buffer, 1 + 8 + len_path + len_mode); + CHECK_ERROR(ret < 0); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret == BYTE_NORMAL); + + ret = recvwait(sock, result, 4); + CHECK_ERROR(ret < 0); + ret = recvwait(sock, handle, 4); + CHECK_ERROR(ret < 0); + } + final_result = 0; + + +error: + + return final_result; +} + +void cafiine_send_file(int sock, char *file, int size, int fd) { + + + CHECK_ERROR(sock == -1); + + int ret; + + // create and send buffer with : [cmd id][fd][size][buffer data ...] + { + char buffer[1 + 4 + 4 + size]; + + buffer[0] = BYTE_DUMP; + *(int *)(buffer + 1) = fd; + *(int *)(buffer + 5) = size; + for (ret = 0; ret < size; ret++) + buffer[9 + ret] = file[ret]; + + // send buffer, wait for reply + ret = sendwait(sock, buffer, 1 + 4 + 4 + size); + CHECK_ERROR(ret < 0); + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret != BYTE_SPECIAL); + } + +error: + + return; +} + +int cafiine_fread(int sock, int *result, void *ptr, int size, int fd) { + + + CHECK_ERROR(sock == -1); + + int ret; + char buffer[1 + 8]; + buffer[0] = BYTE_READ; + *(int *)(buffer + 1) = size; + *(int *)(buffer + 5) = fd; + ret = sendwait(sock, buffer, 1 + 8); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret == BYTE_NORMAL); + int sz; + ret = recvwait(sock, &sz, 4); + CHECK_ERROR(ret < 0); + ret = recvwaitlen(sock, ptr, sz); + *result = sz - ret; + ret = sendbyte(sock, BYTE_OK); + CHECK_ERROR(ret < 0); + + + return 0; +error: + + return -1; +} + +int cafiine_fclose(int sock, int *result, int fd,int dumpclose) { + + + CHECK_ERROR(sock == -1); + + int ret; + char buffer[1 + 4]; + buffer[0] = BYTE_CLOSE; + if(dumpclose)buffer[0] = BYTE_CLOSE_DUMP; + *(int *)(buffer + 1) = fd; + ret = sendwait(sock, buffer, 1 + 4); + CHECK_ERROR(ret < 0); + ret = recvbyte(sock); + CHECK_ERROR(ret == BYTE_NORMAL); + ret = recvwait(sock, result, 4); + CHECK_ERROR(ret < 0); + + + return 0; +error: + + return -1; +} + +int saviine_start_injection(int sock, long persistentID,int * mask){ + + + int result = 0; + CHECK_ERROR(sock == -1); + int ret; + { + char buffer[1+4]; + + buffer[0] = BYTE_INJECTSTART; + *(long *)(buffer + 1) = persistentID; + ret = sendwait(sock, buffer, 1 + 4); + CHECK_ERROR(ret < 0); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_SPECIAL); + + ret = recvwait(sock, mask, 4); + CHECK_ERROR(ret < 0); + CHECK_ERROR((*mask & MASK_NORMAL) != MASK_NORMAL); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_SPECIAL); + result = 1; + } +error: + + return result; +} + +int saviine_end_injection(int sock){ + + + int result = 0; + CHECK_ERROR(sock == -1); + int ret; + { + ret = sendbyte(sock, BYTE_INJECTEND); + CHECK_ERROR(ret < 0); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_OK); + result = 1; + } +error: + + return result; +} + +int saviine_start_dump(int sock, long persistentID,int * mask){ + + + int result = 0; + CHECK_ERROR(sock == -1); + int ret; + { + char buffer[1+4]; + + buffer[0] = BYTE_DUMPSTART; + *(long *)(buffer + 1) = persistentID; + ret = sendwait(sock, buffer, 1 + 4); + CHECK_ERROR(ret < 0); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_SPECIAL); + + ret = recvwait(sock, mask, 4); + CHECK_ERROR(ret < 0); + CHECK_ERROR((*mask & MASK_NORMAL) != MASK_NORMAL); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_SPECIAL); + result = 1; + } +error: + + return result; +} + +int saviine_end_dump(int sock){ + + + int result = 0; + CHECK_ERROR(sock == -1); + int ret; + { + ret = sendbyte(sock, BYTE_DUMPEND); + CHECK_ERROR(ret < 0); + + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_OK); + result = 1; + } +error: + + return result; +} + +int saviine_readdir(int sock, char * path,char * resultname, int * resulttype, int * filesize){ + int result = 0; + CHECK_ERROR(sock == -1); + int ret; + // create and send buffer with : [cmd id][len_path][path][filesize] + { + int size = 0; + while (path[size++]); + char buffer[1+4+size]; + + buffer[0] = BYTE_READ_DIR; + *(int *)(buffer + 1) = size; + for (ret = 0; ret < size; ret++) + buffer[5 + ret] = path[ret]; + + // send buffer, wait for reply + ret = sendwait(sock, buffer, 1+4+size); + CHECK_ERROR(ret < 0); + + // wait reply + ret = recvbyte(sock); + CHECK_ERROR(ret != BYTE_OK); + + ret = recvbyte(sock); + CHECK_ERROR(ret != BYTE_FILE && ret != BYTE_FOLDER); + *resulttype = ret; + size = 0; + ret = recvwait(sock, &size, 4); + CHECK_ERROR(ret < 0); + + ret = recvwait(sock, resultname, size+1); + CHECK_ERROR(ret < 0); + + size = 0; + ret = recvwait(sock, &size, 4); + CHECK_ERROR(ret < 0); + *filesize = size; + ret = recvbyte(sock); + CHECK_ERROR(ret < 0); + CHECK_ERROR(ret != BYTE_SPECIAL); + result = 1; + + } +error: + + return result; +} + +void cafiine_send_ping(int sock, int val1, int val2) { + + int ret; + char buffer[1 + 4 + 4]; + buffer[0] = BYTE_PING; + *(int *)(buffer + 1) = val1; + *(int *)(buffer + 5) = val2; + + ret = sendwait(sock, buffer, 1 + 4 + 4); + CHECK_ERROR(ret < 0); + + error: + + return; +} + + + int recvwaitlen(int sock, void *buffer, int len) { + int ret; + while (len > 0) { + ret = recv(sock, buffer, len, 0); + CHECK_ERROR(ret < 0); + len -= ret; + buffer += ret; + } + return 0; +error: + return len; +} + + + int recvbyte(int sock) { + unsigned char buffer[1]; + int ret; + + ret = recvwait(sock, buffer, 1); + if (ret < 0) return ret; + return buffer[0]; +} + +void log_string(int sock, const char* str, char flag_byte) { + if(sock == -1) { + return; + } + + + int i; + int len_str = 0; + while (str[len_str++]); + + // + { + char buffer[1 + 4 + len_str]; + buffer[0] = flag_byte; + *(int *)(buffer + 1) = len_str; + for (i = 0; i < len_str; i++) + buffer[5 + i] = str[i]; + + buffer[5 + i] = 0; + + sendwait(sock, buffer, 1 + 4 + len_str); + } + + +} + +int sendbyte(int sock, unsigned char byte) { + unsigned char buffer[1]; + + buffer[0] = byte; + return sendwait(sock, buffer, 1); +} + + + +int sendwait(int sock, const void *buffer, int len) +{ + while (iLock) + usleep(5000); + iLock = 1; + + int ret; + while (len > 0) { + ret = send(sock, buffer, len, 0); + CHECK_ERROR(ret <= 0); + len -= ret; + buffer += ret; + } + iLock = 0; + return 0; +error: + iLock = 0; + return ret; +} + +int recvwait(int sock, void *buffer, int len) +{ + while (iLock) + usleep(5000); + iLock = 1; + + int ret; + int received = 0; + while (len > 0) + { + ret = recv(sock, buffer, len, 0); + if(ret > 0) + { + len -= ret; + buffer += ret; + received += ret; + } + else + { + received = ret < 0 ? ret : -1; + break; + } + } + + iLock = 0; + return received; +} +/* +s32 create_server(void) { + socket_lib_init(); + + s32 server = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (server < 0) + return -1; + + u32 enable = 1; + setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); + + struct sockaddr_in bindAddress; + memset(&bindAddress, 0, sizeof(bindAddress)); + bindAddress.sin_family = AF_INET; + bindAddress.sin_port = 7333; + bindAddress.sin_addr.s_addr = INADDR_ANY; + + s32 ret; + if ((ret = bind(server, (struct sockaddr *)&bindAddress, sizeof(bindAddress))) < 0) { + socketclose(server); + return ret; + } + if ((ret = listen(server, 3)) < 0) { + socketclose(server); + return ret; + } + + return server; +} + +s32 accept_client(s32 server) +{ + struct sockaddr addr; + s32 addrlen = sizeof(addr); + + return accept(server, &addr, &addrlen); +} +*/ + + +int server_connect(int *psock, unsigned int server_ip) +{ + struct sockaddr_in addr; + int sock, ret; + + // No ip means that we don't have any server running, so no logs + if (server_ip == 0) { + *psock = -1; + return 0; + } + + socket_lib_init(); + + sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(sock < 0) + return sock; + + addr.sin_family = AF_INET; + addr.sin_port = 7333; + addr.sin_addr.s_addr = server_ip; + + ret = connect(sock, (void *)&addr, sizeof(addr)); + if(ret < 0) + { + socketclose(sock); + return -1; + } + + int enable = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&enable, sizeof(enable)); + + *psock = sock; + iLock = 0; + return 0; +} diff --git a/src/utils/net.h b/src/utils/net.h new file mode 100644 index 0000000..d2fbef7 --- /dev/null +++ b/src/utils/net.h @@ -0,0 +1,64 @@ +#ifndef NETWORK_H_ +#define NETWORK_H_ + +#define BYTE_NORMAL 0xff +#define BYTE_SPECIAL 0xfe +#define BYTE_OPEN 0x00 +#define BYTE_READ 0x01 +#define BYTE_CLOSE 0x02 +#define BYTE_OK 0x03 +#define BYTE_SETPOS 0x04 +#define BYTE_STATFILE 0x05 +#define BYTE_EOF 0x06 +#define BYTE_GETPOS 0x07 +#define BYTE_REQUEST 0x08 +#define BYTE_REQUEST_SLOW 0x09 +#define BYTE_HANDLE 0x0A +#define BYTE_DUMP 0x0B +#define BYTE_PING 0x0C +#define BYTE_G_MODE 0x0D +#define BYTE_MODE_D 0x0E +#define BYTE_MODE_I 0x0F +#define BYTE_CLOSE_DUMP 0x10 +#define BYTE_LOG_STR 0xfb +#define BYTE_FILE 0xC0 +#define BYTE_FOLDER 0xC1 +#define BYTE_READ_DIR 0xCC +#define BYTE_INJECTSTART 0x40 +#define BYTE_INJECTEND 0x41 +#define BYTE_DUMPSTART 0x42 +#define BYTE_DUMPEND 0x43 +#define BYTE_END 0xfd + +#define MASK_NORMAL 0x8000 +#define MASK_USER 0x0100 +#define MASK_COMMON 0x0200 +#define MASK_COMMON_CLEAN 0x0400 + +void cafiine_connect(int *psock,u32 ip); +void cafiine_disconnect(int sock); +int cafiine_handshake(int sock); +int getMode(int sock,int * result); +int cafiine_fsetpos(int sock, int *result, int fd, int set); +int cafiine_send_handle(int sock, const char *path, int handle); +int cafiine_fopen(int sock, int *result, const char *path, const char *mode, int *handle); +void cafiine_send_file(int sock, char *file, int size, int fd); +int cafiine_fread(int sock, int *result, void *ptr, int size, int fd); +int cafiine_fclose(int sock, int *result, int fd,int dumpclose); +int saviine_start_injection(int sock, long persistentID,int * mask); +int saviine_end_injection(int sock); +int saviine_start_dump(int sock, long persistentID,int * mask); +int saviine_end_dump(int sock); +int saviine_readdir(int sock, char * path,char * resultname, int * resulttype, int * filesize); +void cafiine_send_ping(int sock, int val1, int val2); + + int recvwaitlen(int sock, void *buffer, int len); + int recvbyte(int sock); +void log_string(int sock, const char* str, char flag_byte); +int sendbyte(int sock, unsigned char byte); + +int server_connect(int *psock, unsigned int server_ip); +int recvwait(int sock, void *buffer, int len); +int sendwait(int sock, const void *buffer, int len); + +#endif diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..c460fa2 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,47 @@ +#ifndef __UTILS_H_ +#define __UTILS_H_ + +#include +#include "../common/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FlushBlock(addr) asm volatile("dcbf %0, %1\n" \ + "icbi %0, %1\n" \ + "sync\n" \ + "eieio\n" \ + "isync\n" \ + : \ + :"r"(0), "r"(((addr) & ~31)) \ + :"memory", "ctr", "lr", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" \ + ); + +#define LIMIT(x, min, max) \ + ({ \ + typeof( x ) _x = x; \ + typeof( min ) _min = min; \ + typeof( max ) _max = max; \ + ( ( ( _x ) < ( _min ) ) ? ( _min ) : ( ( _x ) > ( _max ) ) ? ( _max) : ( _x ) ); \ + }) + +#define DegToRad(a) ( (a) * 0.01745329252f ) +#define RadToDeg(a) ( (a) * 57.29577951f ) + +#define ALIGN4(x) (((x) + 3) & ~3) +#define ALIGN32(x) (((x) + 31) & ~31) + +// those work only in powers of 2 +#define ROUNDDOWN(val, align) ((val) & ~(align-1)) +#define ROUNDUP(val, align) ROUNDDOWN(((val) + (align-1)), align) + +#define le16(i) ((((u16) ((i) & 0xFF)) << 8) | ((u16) (((i) & 0xFF00) >> 8))) +#define le32(i) ((((u32)le16((i) & 0xFFFF)) << 16) | ((u32)le16(((i) & 0xFFFF0000) >> 16))) +#define le64(i) ((((u64)le32((i) & 0xFFFFFFFFLL)) << 32) | ((u64)le32(((i) & 0xFFFFFFFF00000000LL) >> 32))) + +#ifdef __cplusplus +} +#endif + +#endif // __UTILS_H_ diff --git a/src/video/shaders/ColorShader.cpp b/src/video/shaders/ColorShader.cpp new file mode 100644 index 0000000..d8e963e --- /dev/null +++ b/src/video/shaders/ColorShader.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "ColorShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000078a0, + 0x3c200000,0x88060094,0x00c00000,0x88062014, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00a11f00,0xfc00620f,0x02490001,0x80000040, + 0xfd041f80,0x900c0060,0x83f9223e,0x0000803f, + 0xfe282001,0x10000040,0xfe001f80,0x00080060, + 0xfeac9f80,0xfd00624f,0xdb0f49c0,0xdb0fc940, + 0xfea81f80,0x9000e02f,0x83f9223e,0x00000000, + 0xfe041f80,0x00370000,0xffa01f00,0x80000000, + 0xff101f00,0x800c0020,0x7f041f80,0x80370000, + 0x0000103f,0x00000000,0x02c51f00,0x80000000, + 0xfea41f00,0x80000020,0xffa09f00,0x80000040, + 0xff001f80,0x800c0060,0x398ee33f,0x0000103f, + 0x02c41f00,0x9000e00f,0x02c59f01,0x80000020, + 0xfea81f00,0x80000040,0x02c19f80,0x9000e06f, + 0x398ee33f,0x00000000,0x02c11f01,0x80000000, + 0x02c49f80,0x80000060,0x02e08f01,0xfe0c620f, + 0x02c01f80,0x7f00622f,0xfe242000,0x10000000, + 0xfe20a080,0x10000020,0xf2178647,0x49c0e9fb, + 0xfbbdb2ab,0x768ac733 +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000103,0x00000000,0x00000000,0x00000001, + 0xffffff00,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000001,0x00000000,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x00000ca0,0x00000000,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00002000,0x90000000,0x0004a000,0x90000020, + 0x00082001,0x90000040,0x000ca081,0x90000060, + 0xbb7dd898,0x9746c59c,0xc69b00e7,0x03c36218 +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000001,0x00000002,0x14000001,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +ColorShader * ColorShader::shaderInstance = NULL; + +ColorShader::ColorShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + colorIntensityLocation = 0; + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + angleLocation = 0; + offsetLocation = 4; + scaleLocation = 8; + vertexShader.addUniformVar((GX2UniformVar){ "unf_angle", GX2_VAR_TYPE_FLOAT, 1, angleLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_offset", GX2_VAR_TYPE_VEC3, 1, offsetLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_scale", GX2_VAR_TYPE_VEC3, 1, scaleLocation, 0xffffffff }); + + colorLocation = 1; + positionLocation = 0; + vertexShader.addAttribVar((GX2AttribVar){ "attr_color", GX2_VAR_TYPE_VEC4, 0, colorLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), colorLocation, 1, 0, GX2_ATTRIB_FORMAT_8_8_8_8_UNORM); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + positionVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, cuPositionVtxsSize); + if(positionVtxs) + { + //! position vertex structure + int i = 0; + positionVtxs[i++] = -1.0f; positionVtxs[i++] = -1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = 1.0f; positionVtxs[i++] = -1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = 1.0f; positionVtxs[i++] = 1.0f; positionVtxs[i++] = 0.0f; + positionVtxs[i++] = -1.0f; positionVtxs[i++] = 1.0f; positionVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, positionVtxs, cuPositionVtxsSize); + } +} + +ColorShader::~ColorShader() +{ + if(positionVtxs) + { + free(positionVtxs); + positionVtxs = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/ColorShader.h b/src/video/shaders/ColorShader.h new file mode 100644 index 0000000..35c13b6 --- /dev/null +++ b/src/video/shaders/ColorShader.h @@ -0,0 +1,100 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef __COLOR_SHADER_H_ +#define __COLOR_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class ColorShader : public Shader +{ +private: + ColorShader(); + virtual ~ColorShader(); + + static const u32 cuAttributeCount = 2; + static const u32 cuPositionVtxsSize = 4 * cuVertexAttrSize; + + static ColorShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *positionVtxs; + + u32 angleLocation; + u32 offsetLocation; + u32 scaleLocation; + u32 colorLocation; + u32 colorIntensityLocation; + u32 positionLocation; +public: + static const u32 cuColorVtxsSize = 4 * cuColorAttrSize; + + static ColorShader *instance() { + if(!shaderInstance) { + shaderInstance = new ColorShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u8 * colorAttr, const f32 * posVtxs_in = NULL, const u32 & vtxCount = 0) const + { + if(posVtxs_in && vtxCount) { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuColorAttrSize, cuColorAttrSize, colorAttr); + } + else { + VertexShader::setAttributeBuffer(0, cuPositionVtxsSize, cuVertexAttrSize, positionVtxs); + VertexShader::setAttributeBuffer(1, cuColorVtxsSize, cuColorAttrSize, colorAttr); + } + } + + void setAngle(const float & val) + { + VertexShader::setUniformReg(angleLocation, 4, &val); + } + void setOffset(const glm::vec3 & vec) + { + VertexShader::setUniformReg(offsetLocation, 4, &vec[0]); + } + void setScale(const glm::vec3 & vec) + { + VertexShader::setUniformReg(scaleLocation, 4, &vec[0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } +}; + +#endif // __COLOR_SHADER_H_ diff --git a/src/video/shaders/FXAAShader.cpp b/src/video/shaders/FXAAShader.cpp new file mode 100644 index 0000000..f86087b --- /dev/null +++ b/src/video/shaders/FXAAShader.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "FXAAShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000004a0, + 0x3ca00000,0x88060094,0x00400000,0xff0f2094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c2060,0x0000803f,0x00000000, + 0xc1a229f5,0xd0eddc33,0x426618fd,0x8509cfe7 +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000102,0x00000000,0x00000000,0x00000001, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffe, + 0x00000001,0x00000000,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x00003ca0,0xa0000000,0x000c8080, + 0x30000000,0x000010a1,0xa8000000,0x0010c080, + 0x75000000,0x000088a0,0x00800100,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00241f02,0x1000e00f,0x00241f00,0x1000e02f, + 0x00201f02,0x00000040,0x00201f00,0x00000060, + 0x00011f80,0x10332060,0xff000000,0xff102200, + 0xfd001f00,0x900cc020,0xffc09f01,0x90004040, + 0xffc01f01,0x90000060,0x00051f80,0x1033a040, + 0x0000803f,0x00000000,0xffe00f00,0x90004000, + 0xff008000,0xff102220,0xffe08f00,0x90000440, + 0x010c0000,0x010c4660,0xff008080,0xff004220, + 0x01a01f00,0x00280000,0x01a49f00,0x00280020, + 0x01a81f01,0x00280040,0xfd0c1f00,0x1028e06f, + 0x00208081,0x90002000,0x8716993e,0xa245163f, + 0xd578e93d,0x00000080,0x03a01f00,0x00280000, + 0x03a49f00,0x00280020,0x03a81f01,0x1028e04f, + 0xfd0c1f00,0x00280060,0x00a40081,0x90002020, + 0x8716993e,0xa245163f,0xd578e93d,0x00000080, + 0x04a01f00,0x00280000,0x04a49f00,0x1028a02f, + 0x04a81f01,0x00280040,0xfd0c1f00,0x00280060, + 0x7fcc1f80,0x1000c02f,0x8716993e,0xa245163f, + 0xd578e93d,0x00000080,0x02a01f00,0x1028e00f, + 0x02a49f00,0x00280020,0x02a81f01,0x00280040, + 0xfd0c1f00,0x00280060,0x7fcc1f80,0x1000e02f, + 0x8716993e,0xa245163f,0xd578e93d,0x00000080, + 0x7dc41f00,0x00020000,0x7fec0f01,0x00020020, + 0x7fc81f00,0x00000040,0x7dc41f00,0x00000060, + 0x7fec0f81,0x9001802f,0xfef88f00,0x1000e00f, + 0xfedc8f00,0x00000420,0x7de40f00,0x80010040, + 0x7ec49f01,0x00001060,0xfec41f80,0x10024060, + 0xfed49f00,0x80020000,0xfe141f00,0x900c802f, + 0xfeac1f00,0x80000040,0xfec01f02,0x80020060, + 0x7cc41f81,0x90010060,0x0000003d,0x00000000, + 0xfd001f00,0x900c6000,0xfea89f00,0x80010020, + 0xfec09f81,0x00020040,0x0000803f,0x0000003e, + 0xfec41f81,0x00000020,0xfe041f80,0x00330000, + 0x7fe01f00,0x80000040,0x7ce41f80,0x80000060, + 0xfea81f00,0x80010000,0xfeac1f80,0x80010020, + 0x000000c1,0x00000000,0xfea01f00,0x00020040, + 0xfea41f80,0x00020060,0x00000041,0x00000000, + 0x05c81f01,0x9000e00f,0x01cc9f81,0x9000e06f, + 0xfeac1f00,0x01004200,0xfea01f00,0x01044220, + 0xfeac9f00,0x01002240,0xfea09f00,0x01042260, + 0xfe8c1f80,0x01008600,0xacaa2a3e,0xaaaa2abe, + 0x7f9c1f00,0x0100a200,0x7f801f00,0x01048220, + 0x7f901f80,0x0104a240,0x02080001,0x7000a00f, + 0x02000000,0x7000c04f,0x02048000,0x7000e06f, + 0x01a81f80,0x9000e00f,0xd578e93d,0x00000000, + 0x04a80001,0x1000c00f,0x04a48000,0x00000020, + 0x04a00000,0x00000040,0xfe081f00,0xe00c0060, + 0xfe0c1f80,0xe00c0000,0x01a41f00,0x7f00620f, + 0xfea89f00,0xfe0c822f,0xfea49f00,0xff00a24f, + 0x7d001f80,0xe00c0060,0xa245163f,0x0000803e, + 0x7ea01f00,0xfe0ce20f,0x01a09f80,0xfe006a4f, + 0x0000803e,0x8716993e,0xfe088001,0x9001c00f, + 0xfe488001,0x1002e44f,0xfea01f80,0x80000000, + 0xd578e93d,0x00000000,0x7ca41f00,0x00280000, + 0x7da89f00,0x00280020,0xff201f00,0x00280040, + 0xfd081f80,0x00280060,0x8716993e,0xa245163f, + 0x00000080,0x00000000,0x7fc81f00,0x80060000, + 0xfec00f80,0x80060060,0xfec09f81,0xfb80634f, + 0xfe888f00,0x7e886300,0xfea80f01,0x7f8c6320, + 0xfee80f00,0x7d806340,0xfe680080,0x06846f60, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000100,0x01101df0,0x00008010,0xecdfea0d, + 0x10000200,0x03101df0,0x00002050,0xecdfea0d, + 0x10000000,0x04101df0,0x00003071,0xecdfea0d, + 0x10000200,0x02101df0,0x0000b070,0xecdfea0d, + 0x10000200,0x02101df0,0x00008010,0xecdfea0d, + 0x10000100,0x00101df0,0x0000a051,0xecdfea0d, + 0x10000400,0x04101df0,0x00008010,0xecdfea0d, + 0x10000500,0x05101df0,0x00000011,0xecdfea0d, + 0x10000100,0x01101df0,0x00008010,0xecdfea0d, + 0xfe2e963a,0x0269a9a3,0x38f88096,0x400cf48b +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000007,0x00000002,0x04000101,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +FXAAShader * FXAAShader::shaderInstance = NULL; + +FXAAShader::FXAAShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + resolutionLocation = 0; + pixelShader.addUniformVar((GX2UniformVar){ "unf_resolution", GX2_VAR_TYPE_VEC2, 1, resolutionLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +FXAAShader::~FXAAShader() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/FXAAShader.h b/src/video/shaders/FXAAShader.h new file mode 100644 index 0000000..b7604bc --- /dev/null +++ b/src/video/shaders/FXAAShader.h @@ -0,0 +1,86 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef __FXAA_SHADER_H_ +#define __FXAA_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class FXAAShader : public Shader +{ +public: + static FXAAShader *instance() { + if(!shaderInstance) { + shaderInstance = new FXAAShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer() const + { + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + + void setResolution(const glm::vec2 & vec) + { + PixelShader::setUniformReg(resolutionLocation, 4, &vec[0]); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } + +private: + FXAAShader(); + virtual ~FXAAShader(); + + static const u32 cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + static FXAAShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 samplerLocation; + u32 positionLocation; + u32 texCoordLocation; + u32 resolutionLocation; +}; + +#endif // __FXAA_SHADER_H_ diff --git a/src/video/shaders/FetchShader.h b/src/video/shaders/FetchShader.h new file mode 100644 index 0000000..292052f --- /dev/null +++ b/src/video/shaders/FetchShader.h @@ -0,0 +1,58 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef FETCH_SHADER_H +#define FETCH_SHADER_H + +#include "Shader.h" + +class FetchShader : public Shader +{ +public: + FetchShader(GX2AttribStream * attributes, u32 attrCount, s32 type = GX2_FETCH_SHADER_TESSELATION_NONE, s32 tess = GX2_TESSELLATION_MODE_DISCRETE) + : fetchShader(NULL) + , fetchShaderProgramm(NULL) + { + u32 shaderSize = GX2CalcFetchShaderSizeEx(attrCount, type, tess); + fetchShaderProgramm = memalign(GX2_SHADER_ALIGNMENT, shaderSize); + if(fetchShaderProgramm) + { + fetchShader = new GX2FetchShader; + GX2InitFetchShaderEx(fetchShader, fetchShaderProgramm, attrCount, attributes, type, tess); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, fetchShaderProgramm, shaderSize); + } + } + virtual ~FetchShader() { + if(fetchShaderProgramm) + free(fetchShaderProgramm); + if(fetchShader) + delete fetchShader; + } + + GX2FetchShader *getFetchShader() const { + return fetchShader; + } + + void setShader(void) const { + GX2SetFetchShader(fetchShader); + } + +protected: + GX2FetchShader *fetchShader; + void *fetchShaderProgramm; +}; + +#endif // FETCH_SHADER_H diff --git a/src/video/shaders/PixelShader.h b/src/video/shaders/PixelShader.h new file mode 100644 index 0000000..a1fa76b --- /dev/null +++ b/src/video/shaders/PixelShader.h @@ -0,0 +1,150 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef PIXEL_SHADER_H +#define PIXEL_SHADER_H + +#include "Shader.h" + +class PixelShader : public Shader +{ +public: + PixelShader() + : pixelShader((GX2PixelShader*) memalign(0x40, sizeof(GX2PixelShader))) + { + if(pixelShader) + { + memset(pixelShader, 0, sizeof(GX2PixelShader)); + pixelShader->shader_mode = GX2_SHADER_MODE_UNIFORM_REGISTER; + } + } + virtual ~PixelShader() + { + if(pixelShader) + { + if(pixelShader->shader_data) + free(pixelShader->shader_data); + + for(u32 i = 0; i < pixelShader->uniform_blocks_count; i++) + free((void*)pixelShader->uniform_block[i].name); + + if(pixelShader->uniform_block) + free((void*)pixelShader->uniform_block); + + for(u32 i = 0; i < pixelShader->uniform_vars_count; i++) + free((void*)pixelShader->uniform_var[i].name); + + if(pixelShader->uniform_var) + free((void*)pixelShader->uniform_var); + + if(pixelShader->initial_value) + free((void*)pixelShader->initial_value); + + for(u32 i = 0; i < pixelShader->sampler_vars_count; i++) + free((void*)pixelShader->sampler_var[i].name); + + if(pixelShader->sampler_var) + free((void*)pixelShader->sampler_var); + + if(pixelShader->loops_data) + free((void*)pixelShader->loops_data); + + free(pixelShader); + } + } + + void setProgram(const u32 * program, const u32 & programSize, const u32 * regs, const u32 & regsSize) + { + if(!pixelShader) + return; + + //! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100 + pixelShader->shader_size = programSize; + pixelShader->shader_data = memalign(GX2_SHADER_ALIGNMENT, pixelShader->shader_size); + if(pixelShader->shader_data) + { + memcpy(pixelShader->shader_data, program, pixelShader->shader_size); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, pixelShader->shader_data, pixelShader->shader_size); + } + + memcpy(pixelShader->regs, regs, regsSize); + } + + void addUniformVar(const GX2UniformVar & var) + { + if(!pixelShader) + return; + + u32 idx = pixelShader->uniform_vars_count; + + GX2UniformVar* newVar = (GX2UniformVar*) malloc((pixelShader->uniform_vars_count + 1) * sizeof(GX2UniformVar)); + if(newVar) + { + if(pixelShader->uniform_var) + { + memcpy(newVar, pixelShader->uniform_var, pixelShader->uniform_vars_count * sizeof(GX2UniformVar)); + free(pixelShader->uniform_var); + } + pixelShader->uniform_var = newVar; + + memcpy(pixelShader->uniform_var + idx, &var, sizeof(GX2UniformVar)); + pixelShader->uniform_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)pixelShader->uniform_var[idx].name, var.name); + + pixelShader->uniform_vars_count++; + } + } + + void addSamplerVar(const GX2SamplerVar & var) + { + if(!pixelShader) + return; + + u32 idx = pixelShader->sampler_vars_count; + + GX2SamplerVar* newVar = (GX2SamplerVar*) malloc((pixelShader->sampler_vars_count + 1) * sizeof(GX2SamplerVar)); + if(newVar) + { + if(pixelShader->sampler_var) + { + memcpy(newVar, pixelShader->sampler_var, pixelShader->sampler_vars_count * sizeof(GX2SamplerVar)); + free(pixelShader->sampler_var); + } + pixelShader->sampler_var = newVar; + + memcpy(pixelShader->sampler_var + idx, &var, sizeof(GX2SamplerVar)); + pixelShader->sampler_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)pixelShader->sampler_var[idx].name, var.name); + + pixelShader->sampler_vars_count++; + } + } + GX2PixelShader * getPixelShader() const { + return pixelShader; + } + + void setShader(void) const { + GX2SetPixelShader(pixelShader); + } + + static inline void setUniformReg(u32 location, u32 size, const void * reg) { + GX2SetPixelUniformReg(location, size, reg); + } +protected: + GX2PixelShader *pixelShader; +}; + +#endif // PIXEL_SHADER_H diff --git a/src/video/shaders/Shader.h b/src/video/shaders/Shader.h new file mode 100644 index 0000000..93741d5 --- /dev/null +++ b/src/video/shaders/Shader.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef SHADER_H_ +#define SHADER_H_ + +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" +#include "dynamic_libs/gx2_functions.h" +#include "utils/utils.h" + +class Shader +{ +protected: + Shader() {} + virtual ~Shader() {} +public: + static const u16 cuVertexAttrSize = sizeof(f32) * 3; + static const u16 cuTexCoordAttrSize = sizeof(f32) * 2; + static const u16 cuColorAttrSize = sizeof(u8) * 4; + + static void setLineWidth(const f32 & width) { + GX2SetLineWidth(width); + } + + static void draw(s32 primitive = GX2_PRIMITIVE_QUADS, u32 vtxCount = 4) + { + switch(primitive) + { + default: + case GX2_PRIMITIVE_QUADS: + { + GX2DrawEx(GX2_PRIMITIVE_QUADS, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_TRIANGLES: + { + GX2DrawEx(GX2_PRIMITIVE_TRIANGLES, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_TRIANGLE_FAN: + { + GX2DrawEx(GX2_PRIMITIVE_TRIANGLE_FAN, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_LINES: + { + GX2DrawEx(GX2_PRIMITIVE_LINES, vtxCount, 0, 1); + break; + } + case GX2_PRIMITIVE_LINE_STRIP: + { + GX2DrawEx(GX2_PRIMITIVE_LINE_STRIP, vtxCount, 0, 1); + break; + } + //! TODO: add other primitives later + }; + } +}; + +#endif // SHADER_H_ diff --git a/src/video/shaders/Shader3D.cpp b/src/video/shaders/Shader3D.cpp new file mode 100644 index 0000000..6857cd1 --- /dev/null +++ b/src/video/shaders/Shader3D.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "Shader3D.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x0000e4a1, + 0x00c00100,0x88048093,0x01c00300,0x98060014, + 0x9a000000,0x000058a0,0x3c200200,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x0765a101,0x9000e00f,0x0761a101,0x9000e02f, + 0x01081f00,0x900ce040,0x01041f00,0x900ce060, + 0x01001f80,0x900ce000,0x02001f00,0x900c6000, + 0x02041f00,0x900c6020,0x076da101,0x9000e04f, + 0x0769a181,0x9000e06f,0x0745a101,0x9000c00f, + 0x0741a181,0x9000c02f,0x074da101,0x9000c04f, + 0x0749a181,0x9000c06f,0x0bc9a000,0x7f00e20f, + 0x0bc92080,0x7f04e22f,0x0bc9a001,0x7f08e24f, + 0x0bc92081,0x7f0ce26f,0x0725a101,0x9000a00f, + 0x0721a181,0x9000a02f,0x072da101,0x9000a04f, + 0x0729a181,0x9000a06f,0x0ac9a000,0x7e00c20f, + 0x0ac92080,0x7e04c22f,0x0ac9a001,0x7e08c24f, + 0x0ac92081,0x7e0cc26f,0x0ba5a000,0x7f00e20f, + 0x0ba52080,0x7f04e22f,0x0ba5a001,0x7f08e24f, + 0x0ba52081,0x7f0ce26f,0x08eda000,0x9000800f, + 0x08ed2080,0x9000802f,0x08eda001,0x9000804f, + 0x08ed2081,0x9000806f,0x09c9a000,0x7d00a20f, + 0x09c92080,0x7d04a22f,0x09c9a001,0x7d08a24f, + 0x09c92081,0x7d0ca26f,0x0aa5a000,0x7e00c20f, + 0x0aa52080,0x7e04c22f,0x0aa5a001,0x7e08c24f, + 0x0aa52081,0x7e0cc26f,0x0b81a000,0x7f004200, + 0x0b812080,0x7f044220,0x0b81a001,0x7f082240, + 0x0b812081,0x7f0c0260,0x08c9a000,0x7c00820f, + 0x08c92080,0x7c04822f,0x08c9a001,0x7c08824f, + 0x08c92081,0x7c0c826f,0x09a5a000,0x7d00a20f, + 0x09a52080,0x7d04a22f,0x09a5a001,0x7d08a24f, + 0x09a52081,0x7d0ca26f,0x0a81a000,0x7e000200, + 0x0a812080,0x7e040220,0x0a81a001,0x7e080240, + 0x0a812081,0x7e0c2260,0x0240a001,0x9000c00f, + 0x0244a001,0x9000c02f,0x0148a001,0x9000c04f, + 0x004ca001,0x9000c06f,0x0264a081,0x9000e02f, + 0x0260a001,0x9000e00f,0x0224a001,0x90002020, + 0x0168a001,0x9000e04f,0x006ca001,0x9000e06f, + 0x0220a081,0x90002000,0x08a5a000,0x7c00820f, + 0x08a52080,0x7c04822f,0x08a5a001,0x7c08824f, + 0x08a52081,0x7c0c826f,0x0981a000,0x7d008200, + 0x09812080,0x7d048220,0x0981a001,0x7d084240, + 0x09812081,0x7d0c4260,0x02090000,0x7e00c20f, + 0x02098000,0x7e04c22f,0x0128a001,0x9000a04f, + 0x002ca001,0x9000c06f,0x02298081,0x7e0caa6f, + 0x03090000,0x7f00e20f,0x03098000,0x7f04e22f, + 0x02090001,0x7e08f64f,0x03298001,0x7f0ce26f, + 0x03090081,0x7f08ca4f,0x0881a000,0x7c00c200, + 0x08812080,0x7c04e220,0x0881a001,0x7c08a240, + 0x08812081,0x7c0c8260,0x0200a001,0x9000800f, + 0x0204a001,0x9000802f,0x0108a001,0x9000804f, + 0x000ca001,0x9000806f,0x01098080,0x0104aa2f, + 0x01090000,0x0100a20f,0x02858000,0x7e04c22f, + 0x01090001,0x7d08a24f,0x01298081,0x7e0cc26f, + 0x02850000,0x7e00f60f,0x03858000,0x7f04622f, + 0x02450001,0x7f08e24f,0x02458001,0x7d0ca26f, + 0x03850080,0x7f00ca0f,0x00090000,0x7c004200, + 0x00098000,0x7c04b220,0x03450001,0x7e08c24f, + 0x03458001,0x7f0ce26f,0x03e18080,0xfe042620, + 0x01850000,0x7d00a200,0x01858000,0x7d04622f, + 0x00090001,0x7c086240,0x00298081,0x7c0c0260, + 0x02c10000,0x7f000200,0x02e18000,0x7e040620, + 0x01450001,0x7d088240,0x01458001,0x7e0c6260, + 0x01e18080,0xfe04c620,0x03c10000,0x7e002200, + 0x03818001,0x7f0c4220,0x02a10001,0x7f081640, + 0x02818001,0x7d0c3660,0x03a10081,0x7e082a40, + 0x07080000,0x0100c20f,0x07088000,0x0104622f, + 0x00458001,0x000cea4f,0x07288081,0x0204f66f, + 0x00850000,0x0200620f,0x00858000,0x05046a2f, + 0x07080001,0x0108c24f,0x01818001,0x030c726f, + 0x07cc8080,0xfe04c22f,0x01c10000,0x0500660f, + 0x00e18000,0xfe04622f,0x00450001,0x0308624f, + 0x07cc9f01,0x7f0ce26f,0x00c10080,0xfe00e60f, + 0x07cc1f00,0x7e00660f,0x00a10001,0xfe08c22f, + 0x01a10001,0x0408624f,0x00818001,0x7f086a6f, + 0x07c09f80,0x7e048200,0x07e00f00,0xfe008220, + 0x07cc1f01,0x7e086a4f,0x07c09f81,0x7f0c8240, + 0x07c08f80,0xfe088260,0x2c34800d,0xe3b4f15e, + 0x7642ed30,0x7408600d +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000108,0x00000000,0x00000002,0x00000001, + 0xffff0001,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000000,0x00000001,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cPixelShaderProgram[] = +{ + 0x20000000,0x000008a4,0x03000000,0x01004085, + 0x23000000,0x000044a8,0x35000000,0x000000a4, + 0x06000000,0x01004085,0x36000000,0x00002ca8, + 0x50000000,0x0000c080,0x42000000,0x00001ca0, + 0x00800000,0x88062094,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c0060,0x0000803f,0x00000000, + 0x02011f80,0x8c110000,0xf8402000,0x9006a00f, + 0x02552001,0x00000020,0x01248082,0x80020060, + 0xfe3c1f00,0x1000e04f,0xfe041f80,0x1033c00f, + 0xfe482081,0x80060020,0xfee40f81,0x0289e30f, + 0x02c51f80,0x80060060,0xfeec0f80,0x0285634f, + 0xfec80f80,0x80000060,0xfe4ca081,0x9000e04f, + 0xfe281f00,0x80060000,0xf8c01f81,0x9006e02f, + 0xfee00f81,0xfd80636f,0x0000803f,0x00000000, + 0x7fc49f81,0xf880e34f,0xfe381f80,0x00000000, + 0x7de00f81,0xfe800360,0x01011f80,0x8c100000, + 0x00a81f00,0x9000e02f,0x00000082,0x80020060, + 0x00002040,0x00000000,0xfeac9f80,0xfd00624f, + 0x3333333f,0x00002040,0xfee88f80,0x0101620f, + 0x00cc1f80,0x9000e06f,0xf8c09f01,0x80060020, + 0xfe2c1f80,0x9006e04f,0xfee48f81,0xf880630f, + 0x7fc81f80,0xfd800360,0x0000803f,0x00000000, + 0x000ca001,0x80000000,0x00091f00,0x800c0020, + 0x00051f00,0x800c0040,0x00011f80,0x800c0060, + 0xfe2c0000,0x90002000,0xfe288000,0x90002020, + 0xfe240001,0x90002040,0xfe208081,0x90002060, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x99720984,0x041cab0d,0xa28a9ccd,0x95d199a5 +}; +static const u32 cPixelShaderRegs[] = { + 0x00000102,0x00000002,0x14000002,0x00000000, + 0x00000002,0x00000100,0x00000101,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +Shader3D * Shader3D::shaderInstance = NULL; + +Shader3D::Shader3D() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs)); + + colorIntensityLocation = 0; + fadeDistanceLocation = 4; + fadeOutLocation = 8; + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_distance", GX2_VAR_TYPE_FLOAT, 1, fadeDistanceLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_out_alpha", GX2_VAR_TYPE_VEC4, 1, fadeOutLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + modelMatrixLocation = 0; + projectionMatrixLocation = 16; + viewMatrixLocation = 32; + vertexShader.addUniformVar((GX2UniformVar){ "modelMatrix", GX2_VAR_TYPE_MAT4, 1, modelMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "viewMatrix", GX2_VAR_TYPE_MAT4, 1, projectionMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "projectionMatrix", GX2_VAR_TYPE_MAT4, 1, viewMatrixLocation, 0xffffffff }); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! initialize default quad texture vertexes as those are very commonly used + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +Shader3D::~Shader3D() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/Shader3D.h b/src/video/shaders/Shader3D.h new file mode 100644 index 0000000..7289152 --- /dev/null +++ b/src/video/shaders/Shader3D.h @@ -0,0 +1,119 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef SHADER_3D_H_ +#define SHADER_3D_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class Shader3D : public Shader +{ +private: + Shader3D(); + virtual ~Shader3D(); + + static Shader3D * shaderInstance; + + static const unsigned char cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 modelMatrixLocation; + u32 viewMatrixLocation; + u32 projectionMatrixLocation; + u32 positionLocation; + u32 texCoordLocation; + + u32 colorIntensityLocation; + u32 fadeDistanceLocation; + u32 fadeOutLocation; + u32 samplerLocation; +public: + static Shader3D *instance() { + if(!shaderInstance) { + shaderInstance = new Shader3D(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u32 & vtxCount = 0, const f32 * posVtxs_in = NULL, const f32 * texCoords_in = NULL) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + } + else { + //! use default quad vertex and texture coordinates if nothing is passed + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + } + + void setProjectionMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]); + } + void setViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]); + } + void setModelViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setAlphaFadeOut(const glm::vec4 & vec) + { + PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]); + } + void setDistanceFadeOut(const float & value) + { + PixelShader::setUniformReg(fadeDistanceLocation, 4, &value); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } +}; + +#endif // SHADER_3D_H_ diff --git a/src/video/shaders/ShaderFractalColor.cpp b/src/video/shaders/ShaderFractalColor.cpp new file mode 100644 index 0000000..7e8624c --- /dev/null +++ b/src/video/shaders/ShaderFractalColor.cpp @@ -0,0 +1,373 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "ShaderFractalColor.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x0000eca1, + 0x00c00000,0x88068093,0x01400200,0x9a048013, + 0x9c000000,0x000044a0,0x3c200000,0x88060094, + 0x02400000,0x88062014,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x0765a101,0x9000e00f,0x0761a101,0x9000e02f, + 0x03001f00,0x900c8040,0x03041f80,0x900c8060, + 0x076da101,0x9000e04f,0x0769a181,0x9000e06f, + 0x0745a101,0x9000c00f,0x0741a181,0x9000c02f, + 0x074da101,0x9000c04f,0x0749a181,0x9000c06f, + 0x0bc9a000,0x7f00e20f,0x0bc92080,0x7f04e22f, + 0x0bc9a001,0x7f08e24f,0x0bc92081,0x7f0ce26f, + 0x0725a101,0x9000a00f,0x0721a181,0x9000a02f, + 0x072da101,0x9000a04f,0x0729a181,0x9000a06f, + 0x0ac9a000,0x7e00c20f,0x0ac92080,0x7e04c22f, + 0x0ac9a001,0x7e08c24f,0x0ac92081,0x7e0cc26f, + 0x0ba5a000,0x7f00e20f,0x0ba52080,0x7f04e22f, + 0x0ba5a001,0x7f08e24f,0x0ba52081,0x7f0ce26f, + 0x08eda000,0x9000800f,0x08ed2080,0x9000802f, + 0x08eda001,0x9000804f,0x08ed2081,0x9000806f, + 0x09c9a000,0x7d00a20f,0x09c92080,0x7d04a22f, + 0x09c9a001,0x7d08a24f,0x09c92081,0x7d0ca26f, + 0x0aa5a000,0x7e00c20f,0x0aa52080,0x7e04c22f, + 0x0aa5a001,0x7e08c24f,0x0aa52081,0x7e0cc26f, + 0x0b81a000,0x7f006200,0x0b812080,0x7f046220, + 0x0b81a001,0x7f080240,0x0b812081,0x7f0c0260, + 0x08c9a000,0x7c00820f,0x08c92080,0x7c04822f, + 0x08c9a001,0x7c08824f,0x08c92081,0x7c0c826f, + 0x09a5a000,0x7d00a20f,0x09a52080,0x7d04a22f, + 0x09a5a001,0x7d08a24f,0x09a52081,0x7d0ca26f, + 0x0a81a000,0x7e008200,0x0a812080,0x7e048220, + 0x0a81a001,0x7e086240,0x0a812081,0x7e0c4260, + 0x0340a001,0x9000c00f,0x0344a001,0x9000c02f, + 0x0048a001,0x9000c04f,0x004ca001,0x9000c06f, + 0x0364a081,0x9000e02f,0x0360a001,0x9000e00f, + 0x0324a001,0x90000020,0x0068a001,0x9000e04f, + 0x006ca001,0x9000e06f,0x0320a081,0x90000000, + 0x08a5a000,0x7c00820f,0x08a52080,0x7c04822f, + 0x08a5a001,0x7c08824f,0x08a52081,0x7c0c826f, + 0x0981a000,0x7d00a200,0x09812080,0x7d04a220, + 0x0981a001,0x7d08a240,0x09812081,0x7d0c6260, + 0x02890000,0x7e00c20f,0x02898000,0x7e04c22f, + 0x0028a001,0x9000a04f,0x002ca001,0x9000c06f, + 0x02498081,0x7e0caa6f,0x03890000,0x7f00e20f, + 0x03898000,0x7f04e22f,0x02690001,0x7e08f64f, + 0x03498001,0x7f0ce26f,0x03690081,0x7f08ca4f, + 0x0881a000,0x7c00c200,0x08812080,0x7c04c220, + 0x0881a001,0x7c08e240,0x08812081,0x7c0ca260, + 0x0300a001,0x9000800f,0x0304a001,0x9000802f, + 0x0008a001,0x9000804f,0x000ca001,0x9000806f, + 0x01898080,0x0004aa2f,0x01890000,0x0000a20f, + 0x02a58000,0x7e04c22f,0x01690001,0x7d08a24f, + 0x01498081,0x7e0cc26f,0x02a50000,0x7e00f60f, + 0x03a58000,0x7f04622f,0x02a50001,0x7f08e24f, + 0x02658001,0x7d0ca26f,0x03a50080,0x7f00ca0f, + 0x00890000,0x7c00820f,0x00898000,0x7c049220, + 0x03a50001,0x7e08c24f,0x03658001,0x7f0ce26f, + 0x03c18080,0xfe04862f,0x01a50000,0x7d008200, + 0x01a58000,0x7d04622f,0x00690001,0x7c086240, + 0x00498081,0x7c0c4260,0x02c10000,0x7f00e20f, + 0x02c18000,0x7e04c62f,0x01a50001,0x7d080240, + 0x01658001,0x7e0c0260,0x01c18080,0xfe040620, + 0x03c10000,0x7e00620f,0x03a18001,0x7f0c622f, + 0x02e10001,0x7f08764f,0x02a18001,0x7d0c766f, + 0x03e10081,0x7e084a0f,0x02e80f00,0xfe000e00, + 0x02c88f00,0x7c046220,0x02c81f01,0xff00c240, + 0x02c89f01,0xfe04c260,0x00a50080,0x7c00aa00, + 0x01c10000,0x0400760f,0x00a58000,0x0404622f, + 0x00a50001,0x0308e24f,0x00658001,0x020c626f, + 0x00c10080,0x0500ea0f,0x02c41f00,0x0000620f, + 0x00c18000,0xfe04c22f,0x01e10001,0x0008624f, + 0x01a18001,0x000c666f,0x00a18081,0xfe0ce66f, + 0x00e10001,0x7f08620f,0x02048000,0x03046a2f, + 0x02c41f01,0x06086a4f,0x02c49f01,0x060c6a6f, + 0x02e00f80,0xfe000220,0x02c08f00,0xfe040200, + 0x02e08f01,0xfe0c0240,0x02c01f80,0xfe080260, + 0x8aa480ad,0x2bfc5ca6,0xb5e05b5b,0xd48dc71c +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000108,0x00000000,0x00000004,0x00000001, + 0xff000201,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffff8, + 0x00000003,0x00000001,0x00000000,0x00000002, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cpPixelShaderProgram[] = +{ + 0x20000000,0x000008a4,0x04000000,0x01004085, + 0x23000000,0x0000eca1,0x9f000000,0x0000e0a8, + 0xd8000000,0x000000a4,0x07000000,0x01004085, + 0xd9000000,0x000048a8,0xec000000,0x000000a4, + 0x0a000000,0x01004085,0xed000000,0x000050a8, + 0x02010000,0x000030a0,0x00000000,0x88062094, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0xfd001f80,0x900c0060,0x0000803f,0x00000000, + 0x03011f80,0x8c210000,0xfd001f00,0x900c0000, + 0xfd001f00,0x900ca02f,0x00000002,0x80020040, + 0x00048002,0x80020060,0xf8001f80,0x900cc04f, + 0x0000803f,0x00000000,0xfea81f00,0x9000e00f, + 0xfeac1f00,0x9000e02f,0xf8001f00,0x900c804f, + 0xf8001f80,0x900ca06f,0x00000040,0x00000000, + 0xfea01f00,0x00280000,0xfea41f00,0x00280020, + 0xfe041f00,0x00280040,0xfd041f80,0x00280060, + 0xaf67bb3e,0x00000080,0x7fc41f00,0x00000000, + 0x7fc01f80,0x00000020,0xfe041f00,0x100ac00f, + 0xfe001f80,0x100ac02f,0xfea01f00,0x00280000, + 0xfea41f00,0x00280020,0xfe041f00,0x00280040, + 0xfd041f00,0x1028e06f,0x7fc01f82,0x00000000, + 0x8c65583e,0x00000080,0x7ea41f00,0x80000000, + 0x7ea01f00,0x80000020,0xfee01f00,0x10006040, + 0x7fc48f82,0x00000860,0xa7c4623b,0x00000000, + 0xfea81f00,0x1000e00f,0x7fcc9f01,0x10006020, + 0xfe001f00,0x000a0040,0xfe041f00,0x000a0060, + 0xfea89f80,0x10008040,0x8c65583e,0x3acd13bf, + 0xfeb81f00,0x7e04c20f,0xfebc1f00,0x7e00822f, + 0x03c89f00,0x80060040,0xfea49f00,0x1000e06f, + 0xfea41f81,0x10006060,0x00809043,0x8c65583e, + 0x3acd13bf,0x00000000,0xfea81f00,0xf880a30f, + 0xfe001f00,0x900ca02f,0x7dc41f00,0x1000e04f, + 0xfe081f00,0xfd80636f,0x04081f80,0x900c800f, + 0x0000803f,0x00000000,0xfea81f00,0xf900620f, + 0xfea41f00,0xf900622f,0xfe0c1f00,0x900ca04f, + 0xfec00f00,0x1000c46f,0xfefc0f80,0x10006000, + 0x00000842,0x00000000,0xfeac1f00,0xf900620f, + 0x7fc81f00,0x9000c02f,0x7dc49f00,0x9000e04f, + 0x7df08f01,0x10008060,0x030c1f80,0x900ca02f, + 0x00000842,0x00000000,0xfea41f00,0x80000000, + 0x7ecc1f00,0x9000e02f,0x7e688000,0x80000040, + 0xfea81f00,0x80000060,0x7d6c8081,0x80000000, + 0xa7c4623b,0x00000000,0xfe001f00,0x000a0000, + 0xfe0c1f00,0x000a0020,0xfea41f00,0x80000040, + 0x03648000,0xfe08626f,0x7d648081,0xff00420f, + 0xa7c4623b,0x00000000,0xfeb01f00,0x7e04620f, + 0xfeb41f00,0x7f08662f,0x7c800001,0xff006e4f, + 0xfe081f00,0x000a0060,0x03680081,0xfe0c4e0f, + 0x00809043,0x00000000,0xfebc1f00,0x7f04620f, + 0x7cc41f00,0x00000020,0x7cc49f00,0x1000e04f, + 0xff901f00,0x00000060,0xfe981f80,0x00000000, + 0x00809043,0x00000000,0xfea81f00,0xf900620f, + 0x7cc41f00,0x00000020,0x00c09f00,0x1000c04f, + 0xfe0c1f00,0x80010060,0xff001f80,0x80010000, + 0x00000842,0x00000000,0xfea81f00,0xf900620f, + 0xfecc9f01,0x80000020,0x7fc81f00,0x9000e04f, + 0x7dc89f00,0x1000c86f,0xffe01f80,0x80000000, + 0x00000842,0x00000000,0xfeac1f00,0xf900620f, + 0x7ec81f00,0x9000802f,0xfec49f00,0x9000a040, + 0xfea89f00,0x80000060,0xffe01f80,0x9000a060, + 0x00000842,0xa7c4623b,0xfea41f00,0x80000000, + 0x7ecc1f00,0x9000e02f,0xfe0c1f00,0x000a0040, + 0x7c888081,0x80000000,0xa7c4623b,0x00000000, + 0xfe001f00,0x000a0000,0xfeb81f00,0x7f08622f, + 0xfea49f00,0x80000040,0x048c8081,0xff00420f, + 0x00809043,0xa7c4623b,0xfeb01f00,0x7c04620f, + 0x03600000,0xff00622f,0xfea49f00,0x80000040, + 0xfe081f80,0x000a0060,0x00809043,0x0ccec73c, + 0xfebc1f00,0x7f040200,0xfea09f00,0x90000020, + 0xfe941f00,0x10000040,0xfe081f80,0x30080060, + 0x00809043,0x0ccec73c,0x00041f00,0x20080000, + 0x00a01f00,0x80000020,0x002c1f02,0x1000e04f, + 0x00081f80,0x80010060,0x0ccec73c,0x00000000, + 0xfe201f02,0x1000800f,0xfec81f03,0x80020020, + 0xfe041f00,0x20080040,0xfe881f00,0x00000060, + 0xfecc9f81,0x9000a06f,0xfe0c1f00,0x000a0000, + 0xfe801f00,0x00000020,0xfec01f02,0x80020040, + 0xfe281f02,0x1000c06f,0xfe841f82,0x1000804f, + 0xfe041f00,0x000a0000,0x7fc81f02,0x00000020, + 0xfe8c1f00,0x00000040,0xfecc9f03,0x80020060, + 0xfe881f82,0x1000a00f,0x7cc01f02,0x00000000, + 0xfe8c1f02,0x1000e02f,0xfec49f00,0x80000040, + 0xfe081f00,0x000a0060,0x03c89f80,0x9000e04f, + 0x7ecc9f03,0x00000000,0xfec01f00,0x80000020, + 0x04c81f00,0x80000040,0x7c880f01,0xfe086a6f, + 0x7dac8f81,0x9000800f,0x7da00f00,0xfe04620f, + 0xfec01f00,0x80000020,0x03c01f00,0x80000840, + 0x03ac0f00,0xfe08c66f,0xfebc9f80,0xfd00420f, + 0xe07be53f,0x5c8e5a3f,0xfeb09f00,0xfd00620f, + 0x05e81f00,0x9000f02f,0x7fe48f00,0xfe04624f, + 0x04ec8f00,0xfe08626f,0x03840f81,0x7f08a20f, + 0xe07be53f,0x5c8e5a3f,0x7e0c1f00,0x900ce00f, + 0xfe0c1f00,0x900c802f,0x05cc1f00,0x9000e84f, + 0xfeb89f80,0xfd00626f,0xe07be53f,0x5c8e5a3f, + 0x7cc09f81,0x80000020,0x7fa40f00,0x00280000, + 0xfe848f00,0x00280020,0x7fe80f00,0x00280440, + 0xfd001f80,0x00280060,0x00000080,0x00000000, + 0xfdc01f80,0xf800620f,0x00000243,0x00000000, + 0xfea01f80,0x90000060,0x5555d53f,0x00000000, + 0x02011f80,0x8c110000,0x02448002,0x80020000, + 0xf8402000,0x9006a02f,0x02552081,0x00000040, + 0xfe301f00,0x1000e06f,0xfe081f80,0x1033c02f, + 0xfe4c2081,0x80060040,0xfee88f81,0x0289e32f, + 0x02c59f80,0x80060000,0xfee08f80,0x0285636f, + 0xfecc8f80,0x80000000,0xfe40a081,0x80000060, + 0x00cc9f81,0x9000e04f,0xfe281f00,0x80060000, + 0xf8c01f81,0x9006c02f,0xfee00f81,0xfd80636f, + 0x0000803f,0x00000000,0x7ec49f81,0xf880e34f, + 0xfe381f80,0x00000000,0x7de40f81,0xfe800360, + 0x00011f80,0x8c100000,0xf8001f00,0x900ce00f, + 0x00311f00,0x1000e02f,0x02a41f00,0xf910624f, + 0x02a01f00,0xf910626f,0x00011f80,0x1033e04f, + 0x00000040,0x00000000,0xfecc9f03,0x80020000, + 0xfec81f83,0x80020060,0x7fd49f01,0x00000020, + 0x7fd41f80,0x00000040,0xfe081f00,0x80010000, + 0xfe041f80,0x80010060,0xfee00f01,0x80000000, + 0xfeec0f81,0x80000020,0xfec01f00,0x00280000, + 0xfec49f00,0x00280020,0x7fe00f00,0x00280040, + 0xfd001f80,0x00280060,0x00000080,0x00000000, + 0xfe001f80,0x00350000,0x00ec1f82,0x000c0260, + 0x01011f00,0x800c0000,0x01051f00,0x800c0020, + 0x002c1f00,0x80060040,0xf8008001,0x9006e06f, + 0x01091f80,0x800c0000,0x01c01f00,0x90000000, + 0xfe088001,0xfd80632f,0x01e81f00,0x90000040, + 0x01c49f80,0x90000020,0x0000803f,0x00000000, + 0x7fcc9f80,0xf880630f,0xfe20a081,0x80000000, + 0x01cc1f80,0x90000060,0xc21e82a7,0x62ccc547, + 0x1708607c,0x73ea57a6 +}; +static const u32 cpPixelShaderRegs[] = { + 0x00000106,0x00000002,0x14000003,0x00000000, + 0x00000003,0x00000100,0x00000101,0x00000102, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +ShaderFractalColor * ShaderFractalColor::shaderInstance = NULL; + +ShaderFractalColor::ShaderFractalColor() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cpPixelShaderProgram, sizeof(cpPixelShaderProgram), cpPixelShaderRegs, sizeof(cpPixelShaderRegs)); + + blurLocation = 0; + colorIntensityLocation = 4; + fadeOutLocation = 8; + fractalLocation = 12; + pixelShader.addUniformVar((GX2UniformVar){ "unf_blur_border", GX2_VAR_TYPE_FLOAT, 1, blurLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fade_out_alpha", GX2_VAR_TYPE_VEC4, 1, fadeOutLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_fract_alpha", GX2_VAR_TYPE_INT, 1, fractalLocation, 0xffffffff }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + modelMatrixLocation = 0; + projectionMatrixLocation = 16; + viewMatrixLocation = 32; + vertexShader.addUniformVar((GX2UniformVar){ "modelMatrix", GX2_VAR_TYPE_MAT4, 1, modelMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "projectionMatrix", GX2_VAR_TYPE_MAT4, 1, projectionMatrixLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "viewMatrix", GX2_VAR_TYPE_MAT4, 1, viewMatrixLocation, 0xffffffff }); + + positionLocation = 0; + colorLocation = 1; + texCoordLocation = 2; + vertexShader.addAttribVar((GX2AttribVar){ "attr_colors", GX2_VAR_TYPE_VEC4, 0, colorLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(2), colorLocation, 2, 0, GX2_ATTRIB_FORMAT_8_8_8_8_UNORM); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! initialize default quad texture vertexes as those are very commonly used + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + colorVtxs = (u8*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciColorVtxsSize); + + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); + + + for(i = 0; i < (int)ciColorVtxsSize; i++) + colorVtxs[i] = 0xff; + + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, colorVtxs, ciColorVtxsSize); +} + +ShaderFractalColor::~ShaderFractalColor() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + if(colorVtxs) + { + free(colorVtxs); + colorVtxs = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/ShaderFractalColor.h b/src/video/shaders/ShaderFractalColor.h new file mode 100644 index 0000000..d3d8355 --- /dev/null +++ b/src/video/shaders/ShaderFractalColor.h @@ -0,0 +1,124 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef SHADER_FRACTAL_COLOR_H_ +#define SHADER_FRACTAL_COLOR_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class ShaderFractalColor : public Shader +{ +private: + ShaderFractalColor(); + virtual ~ShaderFractalColor(); + + static ShaderFractalColor * shaderInstance; + + static const unsigned char cuAttributeCount = 3; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + static const u32 ciColorVtxsSize = 4 * cuColorAttrSize; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + u8 *colorVtxs; + + u32 modelMatrixLocation; + u32 viewMatrixLocation; + u32 projectionMatrixLocation; + u32 positionLocation; + u32 colorLocation; + u32 texCoordLocation; + + u32 blurLocation; + u32 colorIntensityLocation; + u32 fadeOutLocation; + u32 fractalLocation; +public: + static ShaderFractalColor *instance() { + if(!shaderInstance) { + shaderInstance = new ShaderFractalColor(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const u32 & vtxCount = 0, const f32 * posVtxs_in = NULL, const f32 * texCoords_in = NULL, const u8 * colorVtxs_in = NULL) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + VertexShader::setAttributeBuffer(2, vtxCount * cuColorAttrSize, cuColorAttrSize, colorVtxs_in); + } + else { + //! use default quad vertex and texture coordinates if nothing is passed + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + VertexShader::setAttributeBuffer(2, ciColorVtxsSize, cuColorAttrSize, colorVtxs); + } + } + + void setProjectionMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(projectionMatrixLocation, 16, &mtx[0][0]); + } + void setViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(viewMatrixLocation, 16, &mtx[0][0]); + } + void setModelViewMtx(const glm::mat4 & mtx) + { + VertexShader::setUniformReg(modelMatrixLocation, 16, &mtx[0][0]); + } + + void setBlurBorder(const float & blurBorderSize) + { + PixelShader::setUniformReg(blurLocation, 4, &blurBorderSize); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setAlphaFadeOut(const glm::vec4 & vec) + { + PixelShader::setUniformReg(fadeOutLocation, 4, &vec[0]); + } + void setFractalColor(const int & fractalColorEnable) + { + PixelShader::setUniformReg(fractalLocation, 4, &fractalColorEnable); + } +}; + +#endif // SHADER_FRACTAL_COLOR_H_ diff --git a/src/video/shaders/Texture2DShader.cpp b/src/video/shaders/Texture2DShader.cpp new file mode 100644 index 0000000..ad7ac52 --- /dev/null +++ b/src/video/shaders/Texture2DShader.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#include +#include +#include "Texture2DShader.h" + +static const u32 cpVertexShaderProgram[] = +{ + 0x00000000,0x00008009,0x20000000,0x000080a0, + 0x3c200100,0x88060094,0x00400000,0x88042014, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x02290001,0x80000000,0x02041f00,0x900c0020, + 0x00a11f00,0xfc00624f,0xfd041f00,0x900c4060, + 0x02001f80,0x900c0000,0x83f9223e,0x0000803f, + 0xfe081f00,0x00080020,0xfe202081,0x10004040, + 0xfea49f80,0xfd00620f,0xdb0f49c0,0xdb0fc940, + 0xfea01f80,0x9000e06f,0x83f9223e,0x00000000, + 0xfe0c1f80,0x00370000,0xffa01f00,0x80000040, + 0xff101f00,0x800c0060,0x7f0c1f80,0x80370040, + 0x0000103f,0x00000000,0xffa01f00,0x80000000, + 0xff001f00,0x800c0020,0x02c51f01,0x80000040, + 0xfeac9f80,0x80000060,0x0000103f,0x398ee33f, + 0xfea01f00,0x80000000,0x02c19f01,0x9000e02f, + 0x01c41f01,0x9000e04f,0x02c59f80,0x80000060, + 0x398ee33f,0x00000000,0x01c49f01,0x80000020, + 0x02c11f80,0x80000040,0x01e08f00,0xfe04624f, + 0x01c01f81,0x7f08626f,0xfe2c2000,0x10004000, + 0xfe28a080,0x10004020,0xeb825790,0xb6f711be, + 0x7c0e2df2,0x81173cfa +}; + +static const u32 cpVertexShaderRegs[] = { + 0x00000103,0x00000000,0x00000000,0x00000001, + 0xffffff00,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0xffffffff,0xffffffff, + 0xffffffff,0xffffffff,0x00000000,0xfffffffc, + 0x00000002,0x00000000,0x00000001,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x000000ff,0x000000ff,0x000000ff, + 0x000000ff,0x00000000,0x0000000e,0x00000010 +}; + +static const u32 cPixelShaderProgram[] = +{ + 0x20000000,0x00000ca4,0x0b000000,0x00000085, + 0x24000000,0x000050a0,0xb0000000,0x000cc080, + 0x39000000,0x00005ca0,0xb8000000,0x000cc080, + 0x51000000,0x000078a0,0xc0000000,0x000cc080, + 0x70000000,0x000064a0,0xc8000000,0x0008c080, + 0x8a000000,0x00005ca0,0x0e000000,0x01008086, + 0xce000000,0x0000c080,0xa2000000,0x00000ca8, + 0x00800000,0x88062094,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00051f00,0x80060000,0x00011f80,0x80060040, + 0xfec81f80,0xfb802320,0x01041f80,0x8c220000, + 0x00a41f00,0xfc10620f,0x010d1f00,0x900c0021, + 0x00091f00,0x80060040,0x00a01f80,0xfc10626f, + 0x00000040,0x00000000,0xfe080000,0xfe8cc300, + 0xfe088080,0xfe80c320,0x00a11f00,0xfe000200, + 0x00a51f00,0xfe040220,0x00a19f00,0xfe000240, + 0x00a59f00,0xfe040260,0x00a11f81,0xfe002600, + 0x4260e5bc,0xa69bc4bc,0x0ad7a3bc,0x00000000, + 0x00a11f00,0x06004200,0x00a59f00,0x06042220, + 0x00a51f00,0x06044240,0x00a11f01,0x06008260, + 0x00a51f81,0x06048620,0x6f1283bc,0x0ad7a3bc, + 0xa69b44bc,0x00000000,0x00a41f00,0x80000000, + 0x00a01f00,0x80000020,0x00ac1f00,0x80000040, + 0x00a81f00,0x80000060,0x00a19f80,0x06000600, + 0xcac3123c,0x6f1203bc,0x03a41f00,0xfe00620f, + 0x03a01f00,0xfe04622f,0x03ac1f00,0xfe08624f, + 0x03a81f00,0xfe0c626f,0x00a59f80,0x06040620, + 0xcc28913b,0x6f1203bc,0x01a41f00,0xfe00620f, + 0x01a01f00,0xfe04622f,0x01ac1f00,0xfe08624f, + 0x01a81f00,0xfe0c626f,0x00a19f80,0x06002600, + 0xe8eab03c,0x6f1283bb,0x02ac1f00,0xfe084200, + 0x02a81f00,0xfe0c4220,0x02a41f00,0xfe004240, + 0x02a01f00,0xfe044260,0x00a59f80,0x06042620, + 0x92bb353d,0x6f1283bb,0x04a81f00,0x0204620f, + 0x04ac1f00,0x0200662f,0x04a41f00,0x0208624f, + 0x04a01f00,0x020c626f,0x00a19f80,0x06004600, + 0xc4139f3d,0x6f12833b,0x00a41f00,0xfe08620f, + 0x00a01f00,0xfe0c622f,0x00ac1f00,0xfe04624f, + 0x00a81f00,0xfe00626f,0x00a59f80,0x06044620, + 0xb950ed3d,0x6f12833b,0x01a41f00,0xfe00620f, + 0x01a01f00,0xfe04622f,0x01ac1f00,0xfe08624f, + 0x01a81f00,0xfe0c626f,0x00a19f80,0x06002600, + 0xecd7163e,0x6f12033c,0x03a41f00,0xfe000200, + 0x03a01f00,0xfe040220,0x03ac1f00,0xfe082240, + 0x03a81f00,0xfe0c2260,0x00a59f80,0x06042620, + 0x2168233e,0x6f12033c,0x00a11f00,0x06006200, + 0x00a51f00,0x06046220,0x00a19f00,0x06006240, + 0x00a59f00,0x06046260,0x00a11f81,0x0600e600, + 0xa69b443c,0x6f12833c,0x0ad7a33c,0x00000000, + 0x02ac1f00,0x0108620f,0x02a81f00,0x010c622f, + 0x02a41f00,0x0000624f,0x02a01f00,0x0004666f, + 0x00a59f80,0x0604e620,0xecd7163e,0x0ad7a33c, + 0x04a81f00,0xfe04620f,0x04ac1f00,0xfe00622f, + 0x04a41f00,0xfe08624f,0x04a01f00,0xfe0c626f, + 0x00a19f80,0x06008600,0xb950ed3d,0xa69bc43c, + 0x05a41f00,0xfe08620f,0x05a01f00,0xfe0c622f, + 0x05ac1f00,0xfe04624f,0x05a81f00,0xfe00626f, + 0x00a59f80,0x06048620,0xc4139f3d,0xa69bc43c, + 0x03a41f00,0xfe00a200,0x03a01f00,0xfe04a220, + 0x03ac1f00,0xfe086240,0x03a81f00,0xfe0c6260, + 0x00a19f80,0x06006600,0x92bb353d,0x4260e53c, + 0x00a51f80,0x06046220,0x4260e53c,0x00000000, + 0x07ac1f00,0x0308620f,0x07a81f00,0x030c622f, + 0x07a41f00,0x0500624f,0x07a01f80,0x0504626f, + 0xe8eab03c,0x00000000,0x04a81f00,0xfe04620f, + 0x04ac1f00,0xfe00622f,0x04a41f00,0xfe08624f, + 0x04a01f80,0xfe0c626f,0xcac3123c,0x00000000, + 0x06a41f00,0xfe08620f,0x06a01f00,0xfe0c622f, + 0x06ac1f00,0xfe04624f,0x06a81f80,0xfe00626f, + 0xcc28913b,0x00000000,0xfe20a000,0x9000e00f, + 0xfe242000,0x9000e02f,0xfe28a001,0x9000e04f, + 0xfe2c2081,0x9000e06f,0xfe28a081,0x80060020, + 0xfee48f00,0x7f842300,0xfee40f00,0x7f802320, + 0xfee48f01,0x7f8c2340,0xfee40f81,0x08842b60, + 0x00202000,0x90002000,0x0024a000,0x90002020, + 0x00282001,0x90002040,0x002ca081,0x90002060, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x10000000,0x03100df0,0x00008010,0xecdfea0d, + 0x10000000,0x00100df0,0x0000a051,0xecdfea0d, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x10000200,0x02100df0,0x00000011,0xecdfea0d, + 0x10000400,0x04100df0,0x0000b070,0xecdfea0d, + 0x10000000,0x00100df0,0x00008010,0xecdfea0d, + 0x10000100,0x01100df0,0x00008010,0xecdfea0d, + 0x10000600,0x03100df0,0x00008010,0xecdfea0d, + 0x10000200,0x02100df0,0x00008010,0xecdfea0d, + 0x10000100,0x04100df0,0x00008010,0xecdfea0d, + 0x10000300,0x05100df0,0x00008010,0xecdfea0d, + 0x10000300,0x03100df0,0x0000a051,0xecdfea0d, + 0x10000700,0x07100df0,0x00008010,0xecdfea0d, + 0x10000400,0x04100df0,0x00008010,0xecdfea0d, + 0x10000300,0x06100df0,0x00008010,0xecdfea0d, + 0x10000000,0x00100df0,0x00008010,0xecdfea0d, + 0xc8581837,0x22740275,0x281eddcc,0xfa8b9b65 +}; +static const u32 cPixelShaderRegs[] = { + 0x00000109,0x00000002,0x14000001,0x00000000, + 0x00000001,0x00000100,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x0000000f,0x00000001,0x00000010, + 0x00000000 +}; + +Texture2DShader * Texture2DShader::shaderInstance = NULL; + +Texture2DShader::Texture2DShader() + : vertexShader(cuAttributeCount) +{ + //! create pixel shader + pixelShader.setProgram(cPixelShaderProgram, sizeof(cPixelShaderProgram), cPixelShaderRegs, sizeof(cPixelShaderRegs)); + + blurLocation = 0; + colorIntensityLocation = 4; + pixelShader.addUniformVar((GX2UniformVar){ "unf_blur_texture_direction", GX2_VAR_TYPE_VEC3, 1, blurLocation, 0xffffffff }); + pixelShader.addUniformVar((GX2UniformVar){ "unf_color_intensity", GX2_VAR_TYPE_VEC4, 1, colorIntensityLocation, 0xffffffff }); + + samplerLocation = 0; + pixelShader.addSamplerVar((GX2SamplerVar){ "sampl_texture", GX2_SAMPLER_TYPE_2D, samplerLocation }); + + //! create vertex shader + vertexShader.setProgram(cpVertexShaderProgram, sizeof(cpVertexShaderProgram), cpVertexShaderRegs, sizeof(cpVertexShaderRegs)); + + angleLocation = 0; + offsetLocation = 4; + scaleLocation = 8; + vertexShader.addUniformVar((GX2UniformVar){ "unf_angle", GX2_VAR_TYPE_FLOAT, 1, angleLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_offset", GX2_VAR_TYPE_VEC3, 1, offsetLocation, 0xffffffff }); + vertexShader.addUniformVar((GX2UniformVar){ "unf_scale", GX2_VAR_TYPE_VEC3, 1, scaleLocation, 0xffffffff }); + + positionLocation = 0; + texCoordLocation = 1; + vertexShader.addAttribVar((GX2AttribVar){ "attr_position", GX2_VAR_TYPE_VEC3, 0, positionLocation }); + vertexShader.addAttribVar((GX2AttribVar){ "attr_texture_coord", GX2_VAR_TYPE_VEC2, 0, texCoordLocation }); + + //! setup attribute streams + GX2InitAttribStream(vertexShader.getAttributeBuffer(0), positionLocation, 0, 0, GX2_ATTRIB_FORMAT_32_32_32_FLOAT); + GX2InitAttribStream(vertexShader.getAttributeBuffer(1), texCoordLocation, 1, 0, GX2_ATTRIB_FORMAT_32_32_FLOAT); + + //! create fetch shader + fetchShader = new FetchShader(vertexShader.getAttributeBuffer(), vertexShader.getAttributesCount()); + + //! model vertex has to be align and cannot be in unknown regions for GX2 like 0xBCAE1000 + posVtxs = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciPositionVtxsSize); + texCoords = (f32*)memalign(GX2_VERTEX_BUFFER_ALIGNMENT, ciTexCoordsVtxsSize); + + //! defaults for normal square + //! position vertex structure and texture coordinate vertex structure + int i = 0; + posVtxs[i++] = -1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = -1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = 1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + posVtxs[i++] = -1.0f; posVtxs[i++] = 1.0f; posVtxs[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, posVtxs, ciPositionVtxsSize); + + i = 0; + texCoords[i++] = 0.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 1.0f; + texCoords[i++] = 1.0f; texCoords[i++] = 0.0f; + texCoords[i++] = 0.0f; texCoords[i++] = 0.0f; + GX2Invalidate(GX2_INVALIDATE_CPU_ATTRIB_BUFFER, texCoords, ciTexCoordsVtxsSize); +} + +Texture2DShader::~Texture2DShader() +{ + if(posVtxs) + { + free(posVtxs); + posVtxs = NULL; + } + if(texCoords) + { + free(texCoords); + texCoords = NULL; + } + + delete fetchShader; + fetchShader = NULL; +} diff --git a/src/video/shaders/Texture2DShader.h b/src/video/shaders/Texture2DShader.h new file mode 100644 index 0000000..cddeee0 --- /dev/null +++ b/src/video/shaders/Texture2DShader.h @@ -0,0 +1,112 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef __TEXTURE_2D_SHADER_H_ +#define __TEXTURE_2D_SHADER_H_ + +#include "VertexShader.h" +#include "PixelShader.h" +#include "FetchShader.h" + +class Texture2DShader : public Shader +{ +private: + Texture2DShader(); + virtual ~Texture2DShader(); + + static const u32 cuAttributeCount = 2; + static const u32 ciPositionVtxsSize = 4 * cuVertexAttrSize; + static const u32 ciTexCoordsVtxsSize = 4 * cuTexCoordAttrSize; + + static Texture2DShader *shaderInstance; + + FetchShader *fetchShader; + VertexShader vertexShader; + PixelShader pixelShader; + + f32 *posVtxs; + f32 *texCoords; + + u32 angleLocation; + u32 offsetLocation; + u32 scaleLocation; + u32 colorIntensityLocation; + u32 blurLocation; + u32 samplerLocation; + u32 positionLocation; + u32 texCoordLocation; +public: + static Texture2DShader *instance() { + if(!shaderInstance) { + shaderInstance = new Texture2DShader(); + } + return shaderInstance; + } + static void destroyInstance() { + if(shaderInstance) { + delete shaderInstance; + shaderInstance = NULL; + } + } + + void setShaders(void) const + { + fetchShader->setShader(); + vertexShader.setShader(); + pixelShader.setShader(); + } + + void setAttributeBuffer(const f32 * texCoords_in = NULL, const f32 * posVtxs_in = NULL, const u32 & vtxCount = 0) const + { + if(posVtxs_in && texCoords_in && vtxCount) + { + VertexShader::setAttributeBuffer(0, vtxCount * cuVertexAttrSize, cuVertexAttrSize, posVtxs_in); + VertexShader::setAttributeBuffer(1, vtxCount * cuTexCoordAttrSize, cuTexCoordAttrSize, texCoords_in); + } + else { + VertexShader::setAttributeBuffer(0, ciPositionVtxsSize, cuVertexAttrSize, posVtxs); + VertexShader::setAttributeBuffer(1, ciTexCoordsVtxsSize, cuTexCoordAttrSize, texCoords); + } + } + + void setAngle(const float & val) + { + VertexShader::setUniformReg(angleLocation, 4, &val); + } + void setOffset(const glm::vec3 & vec) + { + VertexShader::setUniformReg(offsetLocation, 4, &vec[0]); + } + void setScale(const glm::vec3 & vec) + { + VertexShader::setUniformReg(scaleLocation, 4, &vec[0]); + } + void setColorIntensity(const glm::vec4 & vec) + { + PixelShader::setUniformReg(colorIntensityLocation, 4, &vec[0]); + } + void setBlurring(const glm::vec3 & vec) + { + PixelShader::setUniformReg(blurLocation, 4, &vec[0]); + } + + void setTextureAndSampler(const GX2Texture *texture, const GX2Sampler *sampler) const { + GX2SetPixelTexture(texture, samplerLocation); + GX2SetPixelSampler(sampler, samplerLocation); + } +}; + +#endif // __TEXTURE_2D_SHADER_H_ diff --git a/src/video/shaders/VertexShader.h b/src/video/shaders/VertexShader.h new file mode 100644 index 0000000..18dc0fe --- /dev/null +++ b/src/video/shaders/VertexShader.h @@ -0,0 +1,178 @@ +/**************************************************************************** + * Copyright (C) 2015 Dimok + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + ****************************************************************************/ +#ifndef VERTEX_SHADER_H +#define VERTEX_SHADER_H + +#include +#include "Shader.h" + +class VertexShader : public Shader +{ +public: + VertexShader(u32 numAttr) + : attributesCount( numAttr ) + , attributes( new GX2AttribStream[attributesCount] ) + , vertexShader( (GX2VertexShader*) memalign(0x40, sizeof(GX2VertexShader)) ) + { + if(vertexShader) + { + memset(vertexShader, 0, sizeof(GX2VertexShader)); + vertexShader->shader_mode = GX2_SHADER_MODE_UNIFORM_REGISTER; + } + } + + virtual ~VertexShader() { + delete [] attributes; + + if(vertexShader) + { + if(vertexShader->shader_data) + free(vertexShader->shader_data); + + for(u32 i = 0; i < vertexShader->uniform_blocks_count; i++) + free((void*)vertexShader->uniform_block[i].name); + + if(vertexShader->uniform_block) + free((void*)vertexShader->uniform_block); + + for(u32 i = 0; i < vertexShader->uniform_vars_count; i++) + free((void*)vertexShader->uniform_var[i].name); + + if(vertexShader->uniform_var) + free((void*)vertexShader->uniform_var); + + if(vertexShader->initial_value) + free((void*)vertexShader->initial_value); + + for(u32 i = 0; i < vertexShader->sampler_vars_count; i++) + free((void*)vertexShader->sampler_var[i].name); + + if(vertexShader->sampler_var) + free((void*)vertexShader->sampler_var); + + for(u32 i = 0; i < vertexShader->attribute_vars_count; i++) + free((void*)vertexShader->attribute_var[i].name); + + if(vertexShader->attribute_var) + free((void*)vertexShader->attribute_var); + + if(vertexShader->loops_data) + free((void*)vertexShader->loops_data); + + free(vertexShader); + } + } + + void setProgram(const u32 * program, const u32 & programSize, const u32 * regs, const u32 & regsSize) + { + if(!vertexShader) + return; + + //! this must be moved into an area where the graphic engine has access to and must be aligned to 0x100 + vertexShader->shader_size = programSize; + vertexShader->shader_data = memalign(GX2_SHADER_ALIGNMENT, vertexShader->shader_size); + if(vertexShader->shader_data) + { + memcpy(vertexShader->shader_data, program, vertexShader->shader_size); + GX2Invalidate(GX2_INVALIDATE_CPU_SHADER, vertexShader->shader_data, vertexShader->shader_size); + } + + memcpy(vertexShader->regs, regs, regsSize); + } + + void addUniformVar(const GX2UniformVar & var) + { + if(!vertexShader) + return; + + u32 idx = vertexShader->uniform_vars_count; + + GX2UniformVar* newVar = (GX2UniformVar*) malloc((vertexShader->uniform_vars_count + 1) * sizeof(GX2UniformVar)); + if(newVar) + { + if(vertexShader->uniform_vars_count > 0) + { + memcpy(newVar, vertexShader->uniform_var, vertexShader->uniform_vars_count * sizeof(GX2UniformVar)); + free(vertexShader->uniform_var); + } + vertexShader->uniform_var = newVar; + + memcpy(vertexShader->uniform_var + idx, &var, sizeof(GX2UniformVar)); + vertexShader->uniform_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)vertexShader->uniform_var[idx].name, var.name); + + vertexShader->uniform_vars_count++; + } + } + + void addAttribVar(const GX2AttribVar & var) + { + if(!vertexShader) + return; + + u32 idx = vertexShader->attribute_vars_count; + + GX2AttribVar* newVar = (GX2AttribVar*) malloc((vertexShader->attribute_vars_count + 1) * sizeof(GX2AttribVar)); + if(newVar) + { + if(vertexShader->attribute_vars_count > 0) + { + memcpy(newVar, vertexShader->attribute_var, vertexShader->attribute_vars_count * sizeof(GX2AttribVar)); + free(vertexShader->attribute_var); + } + vertexShader->attribute_var = newVar; + + memcpy(vertexShader->attribute_var + idx, &var, sizeof(GX2AttribVar)); + vertexShader->attribute_var[idx].name = (char*) malloc(strlen(var.name) + 1); + strcpy((char*)vertexShader->attribute_var[idx].name, var.name); + + vertexShader->attribute_vars_count++; + } + } + + static inline void setAttributeBuffer(u32 bufferIdx, u32 bufferSize, u32 stride, const void * buffer) { + GX2SetAttribBuffer(bufferIdx, bufferSize, stride, buffer); + } + + GX2VertexShader *getVertexShader() const { + return vertexShader; + } + + void setShader(void) const { + GX2SetVertexShader(vertexShader); + } + + GX2AttribStream * getAttributeBuffer(u32 idx = 0) const { + if(idx >= attributesCount) { + return NULL; + } + return &attributes[idx]; + } + u32 getAttributesCount() const { + return attributesCount; + } + + static void setUniformReg(u32 location, u32 size, const void * reg) { + GX2SetVertexUniformReg(location, size, reg); + } +protected: + u32 attributesCount; + GX2AttribStream *attributes; + GX2VertexShader *vertexShader; +}; + +#endif // VERTEX_SHADER_H