diff --git a/.gitignore b/.gitignore index 72d4ab69..34b28df5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,50 @@ *.elf *.self *.pkg +*.bin *.o *.a *.d +*.so +*.dll +*.task +*.elf.map +*.fpo* +*.vpo* build/ .idea/ +.vscode/ +common/libspumars/ppu/ppu/ +common/libspumars/spu/spu/ +ppu/sprx/libaudio/ppu/ +ppu/sprx/libcamera/ppu/ +ppu/sprx/libgcm_sys/ppu/ +ppu/sprx/libgem/ppu/ +ppu/sprx/libhttp/ppu/ +ppu/sprx/libhttputil/ppu/ +ppu/sprx/libio/ppu/ +ppu/sprx/libjpgdec/ppu/ +ppu/sprx/liblv2/ppu/ +ppu/sprx/libnet/ppu/ +ppu/sprx/libpngdec/ppu/ +ppu/sprx/libresc/ppu/ +ppu/sprx/libspurs/ppu/ +ppu/sprx/liblv2dbg/ppu/ +ppu/sprx/libnetctl/ppu/ +ppu/sprx/libssl/ppu/ +ppu/sprx/libsysfs/ppu/ +ppu/sprx/libsysmodule/ppu/ +ppu/sprx/libsysutil/ppu/ +ppu/sprx/libusb/ppu/ +ppu/sprx/libvdec/ppu/ +ppu/sprx/libfont/ppu/ +ppu/sprx/libfontFT/ppu/ +tools/generic/bin2s +tools/cgcomp/cgcomp +tools/geohot/make_self +tools/geohot/make_self_npdrm +tools/geohot/package_finalize +tools/ps3load/ps3load +tools/raw2h/raw2h +tools/sprxlinker/sprxlinker +tools/fself/fself diff --git a/Makefile b/Makefile index 11c5821a..b96c7eb9 100644 --- a/Makefile +++ b/Makefile @@ -11,9 +11,9 @@ endif .PHONY: samples all: - @$(MAKE) -C common --no-print-directory @$(MAKE) -C ppu --no-print-directory @$(MAKE) -C spu --no-print-directory + @$(MAKE) -C common --no-print-directory @$(MAKE) -C tools --no-print-directory samples: @@ -33,15 +33,15 @@ install-socat: @$(MAKE) -C tools install-socat --no-print-directory install: - @$(MAKE) -C common install --no-print-directory @$(MAKE) -C ppu install --no-print-directory @$(MAKE) -C spu install --no-print-directory + @$(MAKE) -C common install --no-print-directory @$(MAKE) -C tools install --no-print-directory clean: - @$(MAKE) -C common clean --no-print-directory @$(MAKE) -C ppu clean --no-print-directory @$(MAKE) -C spu clean --no-print-directory + @$(MAKE) -C common clean --no-print-directory @$(MAKE) -C tools clean --no-print-directory @rm -rf doc diff --git a/common/Makefile b/common/Makefile index 8782180b..e6779355 100644 --- a/common/Makefile +++ b/common/Makefile @@ -7,13 +7,16 @@ all: @$(MAKE) -C libsimdmath --no-print-directory @$(MAKE) -C vectormath --no-print-directory + @$(MAKE) -C libspumars --no-print-directory install: @$(MAKE) -C libsimdmath install --no-print-directory @$(MAKE) -C vectormath install --no-print-directory + @$(MAKE) -C libspumars install --no-print-directory clean: @$(MAKE) -C libsimdmath clean --no-print-directory @$(MAKE) -C vectormath clean --no-print-directory + @$(MAKE) -C libspumars clean --no-print-directory .PHONY: all clean install diff --git a/common/libspumars/Makefile b/common/libspumars/Makefile new file mode 100644 index 00000000..43269e1c --- /dev/null +++ b/common/libspumars/Makefile @@ -0,0 +1,19 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +all: + @$(MAKE) -C spu --no-print-directory + @$(MAKE) -C ppu --no-print-directory + +install: + @$(MAKE) -C spu install --no-print-directory + @$(MAKE) -C ppu install --no-print-directory + +clean: + @$(MAKE) -C spu clean --no-print-directory + @$(MAKE) -C ppu clean --no-print-directory + +.PHONY: all clean install diff --git a/common/libspumars/base/common/callback_internal_types.h b/common/libspumars/base/common/callback_internal_types.h new file mode 100644 index 00000000..77f43621 --- /dev/null +++ b/common/libspumars/base/common/callback_internal_types.h @@ -0,0 +1,22 @@ +#ifndef __MARS_CALLBACK_INTERNAL_TYPES_H__ +#define __MARS_CALLBACK_INTERNAL_TYPES_H__ + +#define MARS_CALLBACK_QUEUE_SIZE 128 /* size of 128 bytes */ +#define MARS_CALLBACK_QUEUE_ALIGN 128 /* align to 128 bytes */ +#define MARS_CALLBACK_QUEUE_MAX 54 /* max depth of queue */ + +#define MARS_CALLBACK_QUEUE_FLAG_NONE 0x0 /* no flag set */ +#define MARS_CALLBACK_QUEUE_FLAG_EXIT 0x1 /* exit flag */ +#define MARS_CALLBACK_QUEUE_FLAG_PUSH 0x2 /* push flag */ + +/* 128 byte callback queue structure */ +struct mars_callback_queue { + uint32_t lock; + uint32_t flag; + uint32_t count; + uint32_t head; + uint32_t tail; + uint16_t workload_id[MARS_CALLBACK_QUEUE_MAX]; +} __attribute__((aligned(MARS_CALLBACK_QUEUE_ALIGN))); + +#endif diff --git a/common/libspumars/base/common/kernel_internal_types.h b/common/libspumars/base/common/kernel_internal_types.h new file mode 100644 index 00000000..aa315838 --- /dev/null +++ b/common/libspumars/base/common/kernel_internal_types.h @@ -0,0 +1,95 @@ +#ifndef __KERNEL_INTERNAL_TYPES_H__ +#define __KERNEL_INTERNAL_TYPES_H__ + +#include + +#include "mars/mutex_types.h" + +#include "callback_internal_types.h" +#include "workload_internal_types.h" + +#define MARS_KERNEL_ID_NONE 0xffff + +#define MARS_KERNEL_TICKS_FLAG_SYNC_BEGIN 0x1 +#define MARS_KERNEL_TICKS_FLAG_SYNC_END 0x2 + +#define MARS_KERNEL_DMA_TAG 31 +#define MARS_KERNEL_SPU_EVENT_PORT 63 + +#define MARS_KERNEL_PARAMS_SIZE 128 +#define MARS_KERNEL_PARAMS_ALIGN 128 + +/* mars kernel syscalls */ +struct mars_kernel_syscalls { + uint32_t (*get_ticks)(void); + uint64_t (*get_mars_context_ea)(void); + uint16_t (*get_kernel_id)(void); + uint16_t (*get_workload_id)(void); + struct mars_workload_context * (*get_workload)(void); + struct mars_workload_context * (*get_workload_by_id)(uint16_t id); + + void (*workload_exit)(uint8_t state); + int (*workload_query)(uint16_t id, int query); + int (*workload_wait_set)(uint16_t id); + int (*workload_wait_reset)(void); + int (*workload_signal_set)(uint16_t id); + int (*workload_signal_reset)(void); + int (*workload_schedule_begin)(uint16_t id, uint8_t priority, + struct mars_workload_context **workload); + int (*workload_schedule_end)(uint16_t id, int cancel); + int (*workload_unschedule_begin)(uint16_t id, + struct mars_workload_context **workload); + int (*workload_unschedule_end)(uint16_t id); + + void (*host_signal_send)(uint64_t watch_point_ea); + int (*host_callback_set)(uint64_t callback_ea, + const struct mars_callback_args *in); + int (*host_callback_reset)(struct mars_callback_args *out); + + int (*mutex_lock_get)(uint64_t mutex_ea, struct mars_mutex *mutex); + int (*mutex_unlock_put)(uint64_t mutex_ea, struct mars_mutex *mutex); + + int (*dma_get)(void *ls, uint64_t ea, uint32_t size, uint32_t tag); + int (*dma_put)(const void *ls, uint64_t ea, uint32_t size, + uint32_t tag); + int (*dma_wait)(uint32_t tag); +}; + +/* mars kernel ticks */ +struct mars_kernel_ticks { + uint32_t flag; + uint32_t offset; +}; + +/* mars kernel parameters */ +struct mars_kernel_params { + struct mars_kernel_ticks kernel_ticks; + uint64_t mars_context_ea; + uint64_t workload_queue_ea; + uint64_t callback_queue_ea; + uint16_t kernel_id; + + uint8_t pad[MARS_KERNEL_PARAMS_SIZE - + (sizeof(struct mars_kernel_ticks) + + sizeof(uint64_t)*3 + + sizeof(uint16_t)) + ]; +} __attribute__((aligned(MARS_KERNEL_PARAMS_ALIGN))); + +/* mars kernel buffer */ +union mars_kernel_buffer { + struct mars_callback_queue callback_queue; + struct mars_workload_queue_header workload_queue_header; + struct mars_workload_queue_block workload_queue_block; +}; + +/* mars kernel mutex */ +int mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex); +int mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex); + +/* mars kernel dma */ +int dma_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag); +int dma_put(const void *ls, uint64_t ea, uint32_t size, uint32_t tag); +int dma_wait(uint32_t tag); + +#endif diff --git a/common/libspumars/base/common/workload_internal_types.h b/common/libspumars/base/common/workload_internal_types.h new file mode 100644 index 00000000..13dcde85 --- /dev/null +++ b/common/libspumars/base/common/workload_internal_types.h @@ -0,0 +1,159 @@ +#ifndef __WORKLOAD_INTERNAL_TYPES_H__ +#define __WORKLOAD_INTERNAL_TYPES_H__ + +#include + +#include "mars/callback_types.h" +#include "mars/workload_types.h" + +#define MARS_WORKLOAD_STATE_NONE 0x00 /* workload undefined */ +#define MARS_WORKLOAD_STATE_ADDING 0x01 /* adding now */ +#define MARS_WORKLOAD_STATE_REMOVING 0x02 /* removing now */ +#define MARS_WORKLOAD_STATE_SCHEDULING 0x04 /* scheduling now */ +#define MARS_WORKLOAD_STATE_UNSCHEDULING 0x08 /* unscheduling now */ +#define MARS_WORKLOAD_STATE_READY 0x10 /* ready to schedule */ +#define MARS_WORKLOAD_STATE_WAITING 0x20 /* waiting for sync */ +#define MARS_WORKLOAD_STATE_RUNNING 0x40 /* currently running */ +#define MARS_WORKLOAD_STATE_FINISHED 0x80 /* not allow schedule */ + +#define MARS_WORKLOAD_PRIORITY_MIN 0x00 /* minimum priority */ +#define MARS_WORKLOAD_PRIORITY_MAX 0xff /* maximum priority */ + +#define MARS_WORKLOAD_COUNTER_MIN 0x0000 /* minimum counter */ +#define MARS_WORKLOAD_COUNTER_MAX 0x7fff /* maximum counter */ + +#define MARS_WORKLOAD_SIGNAL_OFF 0x0 /* signal set off */ +#define MARS_WORKLOAD_SIGNAL_ON 0x1 /* signal set on */ + +#define MARS_WORKLOAD_ID_NONE 0xffff /* workload id none */ +#define MARS_WORKLOAD_ID_MAX 799 /* workload id max */ + +#define MARS_WORKLOAD_PER_BLOCK 16 /* wl/block (lock+15) */ +#define MARS_WORKLOAD_NUM_BLOCKS 50 /* total blocks */ +#define MARS_WORKLOAD_MAX 750 /* blocks * wl/block */ + +#define MARS_WORKLOAD_QUEUE_SIZE 198528 /* size 198528 bytes */ +#define MARS_WORKLOAD_QUEUE_ALIGN 128 /* align to 128 bytes */ +#define MARS_WORKLOAD_QUEUE_HEADER_SIZE 128 /* size of 128 bytes */ +#define MARS_WORKLOAD_QUEUE_HEADER_ALIGN 128 /* align to 128 bytes */ +#define MARS_WORKLOAD_QUEUE_BLOCK_SIZE 128 /* size to 128 bytes */ +#define MARS_WORKLOAD_QUEUE_BLOCK_ALIGN 128 /* align to 128 bytes */ + +#define MARS_WORKLOAD_QUEUE_FLAG_NONE 0x0 /* no flag set */ +#define MARS_WORKLOAD_QUEUE_FLAG_EXIT 0x1 /* exit flag */ + +#define MARS_WORKLOAD_BLOCK_PRIORITY_MIN MARS_WORKLOAD_PRIORITY_MIN +#define MARS_WORKLOAD_BLOCK_PRIORITY_MAX MARS_WORKLOAD_PRIORITY_MAX + +#define MARS_WORKLOAD_BLOCK_COUNTER_MIN 0x00 +#define MARS_WORKLOAD_BLOCK_COUNTER_MAX 0x3f + +#define MARS_WORKLOAD_BLOCK_READY_OFF 0x0 +#define MARS_WORKLOAD_BLOCK_READY_ON 0x1 + +#define MARS_WORKLOAD_BLOCK_WAITING_OFF 0x0 +#define MARS_WORKLOAD_BLOCK_WAITING_ON 0x1 +/* + * MARS workload queue header block bits (16-bits) + * ------------------------------------------ + * |[15.....8]|[7.....2]|[ 1 ]|[ 0 ]| + * ------------------------------------------ + * | 8-bits | 6-bits | 1-bit | 1-bit | + * ------------------------------------------ + * | PRIORITY | COUNTER | READY | WAITING | + * ------------------------------------------ + */ +#define MARS_BITS_SHIFT_BLOCK_PRIORITY 8 +#define MARS_BITS_SHIFT_BLOCK_COUNTER 2 +#define MARS_BITS_SHIFT_BLOCK_READY 1 +#define MARS_BITS_SHIFT_BLOCK_WAITING 0 + +#define MARS_BITS_MASK_BLOCK_PRIORITY 0x000000000000ff00ULL +#define MARS_BITS_MASK_BLOCK_COUNTER 0x00000000000000fcULL +#define MARS_BITS_MASK_BLOCK_READY 0x0000000000000002ULL +#define MARS_BITS_MASK_BLOCK_WAITING 0x0000000000000001ULL + +/* + * MARS workload queue block workload bits (64-bits) + * ------------------------------------------------------------------ + * |[63....56]|[55....48]|[47....33]|[ 32 ]|[31.....16]|[15......0]| + * ------------------------------------------------------------------ + * | 8-bits | 8-bits | 15-bits | 1-bit | 16-bits | 16-bits | + * ------------------------------------------------------------------ + * | STATE | PRIORITY | COUNTER | SIGNAL | WAIT_ID | KERNEL_ID | + * ------------------------------------------------------------------ + */ +#define MARS_BITS_SHIFT_WORKLOAD_STATE 56 +#define MARS_BITS_SHIFT_WORKLOAD_PRIORITY 48 +#define MARS_BITS_SHIFT_WORKLOAD_COUNTER 33 +#define MARS_BITS_SHIFT_WORKLOAD_SIGNAL 32 +#define MARS_BITS_SHIFT_WORKLOAD_WAIT_ID 16 +#define MARS_BITS_SHIFT_WORKLOAD_KERNEL_ID 0 + +#define MARS_BITS_MASK_WORKLOAD_STATE 0xff00000000000000ULL +#define MARS_BITS_MASK_WORKLOAD_PRIORITY 0x00ff000000000000ULL +#define MARS_BITS_MASK_WORKLOAD_COUNTER 0x0000fffe00000000ULL +#define MARS_BITS_MASK_WORKLOAD_SIGNAL 0x0000000100000000ULL +#define MARS_BITS_MASK_WORKLOAD_WAIT_ID 0x00000000ffff0000ULL +#define MARS_BITS_MASK_WORKLOAD_KERNEL_ID 0x000000000000ffffULL + +#define MARS_HOST_SIGNAL_EXIT 0x0 /* host exit flag */ + +#define MARS_WORKLOAD_MODULE_SIZE 64 +#define MARS_WORKLOAD_MODULE_ALIGN 16 + +#define MARS_WORKLOAD_CALLBACK_SIZE 64 +#define MARS_WORKLOAD_CALLBACK_ALIGN 16 + +#define MARS_BITS_GET(bits, name) \ + ((*(bits)&MARS_BITS_MASK_##name)>>MARS_BITS_SHIFT_##name) + +#define MARS_BITS_SET(bits, name, val) \ + (*bits) = ((*(bits)&~MARS_BITS_MASK_##name) | \ + ((uint64_t)(val)< + +#define MARS_CALLBACK_ARGS_SIZE 48 +#define MARS_CALLBACK_ARGS_ALIGN 16 + +#ifdef __cplusplus +extern "C" { +#endif + +struct mars_callback_args +{ + union + { + uint8_t u8[48]; + uint16_t u16[24]; + uint32_t u32[12]; + uint64_t u64[6]; + } type; +}__attribute__((aligned(MARS_CALLBACK_ARGS_ALIGN))); + +typedef int (*mars_callback)(const struct mars_callback_args *in, struct mars_callback_args *out); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/common/mars/error.h b/common/libspumars/include/common/mars/error.h new file mode 100644 index 00000000..7f46dbd3 --- /dev/null +++ b/common/libspumars/include/common/mars/error.h @@ -0,0 +1,25 @@ +#ifndef __MARS_ERROR_H__ +#define __MARS_ERROR_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + MARS_SUCCESS = 0, /**< successful with no errors */ + MARS_ERROR_NULL, /**< null pointer passed in */ + MARS_ERROR_PARAMS, /**< invalid parameter specified */ + MARS_ERROR_INTERNAL, /**< internal library error */ + MARS_ERROR_MEMORY, /**< out of memory */ + MARS_ERROR_ALIGN, /**< bad memory alignment */ + MARS_ERROR_LIMIT, /**< some limit exceeded */ + MARS_ERROR_STATE, /**< something is in an invalid state */ + MARS_ERROR_FORMAT, /**< invalid format specified */ + MARS_ERROR_BUSY /**< operation returned due to being busy */ +}; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/common/mars/mutex_types.h b/common/libspumars/include/common/mars/mutex_types.h new file mode 100644 index 00000000..7e656a39 --- /dev/null +++ b/common/libspumars/include/common/mars/mutex_types.h @@ -0,0 +1,34 @@ +#ifndef __MARS_MUTEX_TYPES_H__ +#define __MARS_MUTEX_TYPES_H__ + +#include + +#define MARS_MUTEX_SIZE 128 +#define MARS_MUTEX_ALIGN 128 +#define MARS_MUTEX_ALIGN_MASK 0x7f +#define MARS_MUTEX_LOCKED 0x1 +#define MARS_MUTEX_UNLOCKED 0x0 + +#ifdef __cplusplus +extern "C" { +#endif + +struct mars_mutex_status +{ + uint8_t lock; + uint8_t pad; + uint8_t current_id; + uint8_t next_id; +}; + +struct mars_mutex +{ + struct mars_mutex_status status; + uint8_t pad[124]; +} __attribute__((aligned(MARS_MUTEX_ALIGN))); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/common/mars/task_barrier_types.h b/common/libspumars/include/common/mars/task_barrier_types.h new file mode 100644 index 00000000..cb99bf45 --- /dev/null +++ b/common/libspumars/include/common/mars/task_barrier_types.h @@ -0,0 +1,33 @@ +#ifndef __MARS_TASK_BARRIER_TYPES_H__ +#define __MARS_TASK_BARRIER_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file + * \ingroup group_mars_task_barrier + * \brief [host/MPU] MARS Task Barrier Types + */ + +/** + * \ingroup group_mars_task_barrier + * \brief Maximum tasks allowed for single barrier + */ +#define MARS_TASK_BARRIER_WAIT_MAX 25 + +/** + * \ingroup group_mars_task_barrier + * \brief MARS task barrier structure + * + * An instance of this structure must be created when using any of the + * MARS task barrier API. + */ +struct mars_task_barrier; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/common/mars/task_event_flag_types.h b/common/libspumars/include/common/mars/task_event_flag_types.h new file mode 100644 index 00000000..1a80b058 --- /dev/null +++ b/common/libspumars/include/common/mars/task_event_flag_types.h @@ -0,0 +1,67 @@ +#ifndef __MARS_TASK_EVENT_FLAG_TYPES_H__ +#define __MARS_TASK_EVENT_FLAG_TYPES_H__ + +/** + * \file + * \ingroup group_mars_task_event_flag + * \brief [host/MPU] MARS Task Event Flag Types + */ + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag direction from PPU to SPU + */ +#define MARS_TASK_EVENT_FLAG_HOST_TO_MPU 0x10 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag direction from SPU to PPU + */ +#define MARS_TASK_EVENT_FLAG_MPU_TO_HOST 0x11 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag direction from SPU to SPU + */ +#define MARS_TASK_EVENT_FLAG_MPU_TO_MPU 0x12 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag clear mode automatic + */ +#define MARS_TASK_EVENT_FLAG_CLEAR_AUTO 0x20 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag clear mode manual + */ +#define MARS_TASK_EVENT_FLAG_CLEAR_MANUAL 0x21 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag mask mode bitwise OR + */ +#define MARS_TASK_EVENT_FLAG_MASK_OR 0x30 + +/** + * \ingroup group_mars_task_event_flag + * \brief Event flag mask mode bitwise AND + */ +#define MARS_TASK_EVENT_FLAG_MASK_AND 0x31 + +/** + * \ingroup group_mars_task_event_flag + * \brief Maximum tasks allowed to wait on a single event flag + */ +#define MARS_TASK_EVENT_FLAG_WAIT_MAX 15 + +/** + * \ingroup group_mars_task_event_flag + * \brief MARS task event flag structure + * + * An instance of this structure must be created when using any of the + * MARS event flag API. + */ +struct mars_task_event_flag; + +#endif diff --git a/common/libspumars/include/common/mars/task_queue_types.h b/common/libspumars/include/common/mars/task_queue_types.h new file mode 100644 index 00000000..decbb2bf --- /dev/null +++ b/common/libspumars/include/common/mars/task_queue_types.h @@ -0,0 +1,49 @@ +#ifndef __MARS_TASK_QUEUE_TYPES_H__ +#define __MARS_TASK_QUEUE_TYPES_H__ + +/** + * \file + * \ingroup group_mars_task_queue + * \brief [host/MPU] MARS Task Queue Types + */ + +/** + * \ingroup group_mars_task_queue + * \brief Queue direction from PPU to SPU + */ +#define MARS_TASK_QUEUE_HOST_TO_MPU 0x10 + +/** + * \ingroup group_mars_task_queue + * \brief Queue direction from SPU to PPU + */ +#define MARS_TASK_QUEUE_MPU_TO_HOST 0x11 + +/** + * \ingroup group_mars_task_queue + * \brief Queue direction from SPU to SPU + */ +#define MARS_TASK_QUEUE_MPU_TO_MPU 0x12 + +/** + * \ingroup group_mars_task_queue + * \brief Maximum tasks allowed to wait on a queue + */ +#define MARS_TASK_QUEUE_WAIT_MAX 18 + +/** + * \ingroup group_mars_task_queue + * \brief Maximum size allowed for queue entry + */ +#define MARS_TASK_QUEUE_ENTRY_SIZE_MAX 16384 + +/** + * \ingroup group_mars_task_queue + * \brief MARS task queue structure + * + * An instance of this structure must be created when using any of the + * MARS queue API. + */ +struct mars_task_queue; + +#endif diff --git a/common/libspumars/include/common/mars/task_semaphore_types.h b/common/libspumars/include/common/mars/task_semaphore_types.h new file mode 100644 index 00000000..9994be3c --- /dev/null +++ b/common/libspumars/include/common/mars/task_semaphore_types.h @@ -0,0 +1,25 @@ +#ifndef __MARS_TASK_SEMAPHORE_TYPES_H__ +#define __MARS_TASK_SEMAPHORE_TYPES_H__ + +/** + * \file + * \ingroup group_mars_task_semaphore + * \brief [host/MPU] MARS Task Semaphore Types + */ + +/** + * \ingroup group_mars_task_semaphore + * \brief Maximum task accesses allowed for single semaphore + */ +#define MARS_TASK_SEMAPHORE_WAIT_MAX 54 + +/** + * \ingroup group_mars_task_semaphore + * \brief MARS task semaphore structure + * + * An instance of this structure must be created when using any of the + * MARS semaphore API. + */ +struct mars_task_semaphore; + +#endif diff --git a/common/libspumars/include/common/mars/task_types.h b/common/libspumars/include/common/mars/task_types.h new file mode 100644 index 00000000..38f144ea --- /dev/null +++ b/common/libspumars/include/common/mars/task_types.h @@ -0,0 +1,36 @@ +#ifndef __MARS_TASK_TYPES_H__ +#define __MARS_TASK_TYPES_H__ + +#include + +#include + +#define MARS_TASK_BASE_ADDR 0x4000 +#define MARS_TASK_CONTEXT_SAVE_SIZE_MAX 0x3c000 +#define MARS_TASK_NAME_LEN_MAX 21 + +#ifdef __cplusplus +extern "C" { +#endif + + +struct mars_task_id { + uint64_t mars_context_ea; + uint16_t workload_id; + uint8_t name[MARS_TASK_NAME_LEN_MAX + 1]; +}; + +struct mars_task_args { + union { + uint8_t u8[16]; + uint16_t u16[8]; + uint32_t u32[4]; + uint64_t u64[2]; + } type; +}; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/common/mars/workload_types.h b/common/libspumars/include/common/mars/workload_types.h new file mode 100644 index 00000000..a9bae3ed --- /dev/null +++ b/common/libspumars/include/common/mars/workload_types.h @@ -0,0 +1,38 @@ +#ifndef __MARS_WORKLOAD_TYPES_H__ +#define __MARS_WORKLOAD_TYPES_H__ + +#include + +#define MARS_WORKLOAD_MODULE_BASE_ADDR 0x2a00 +#define MARS_WORKLOAD_MODULE_NAME_LEN_MAX 23 +#define MARS_WORKLOAD_RESERVED_SIZE 128 +#define MARS_WORKLOAD_CONTEXT_SIZE 256 +#define MARS_WORKLOAD_CONTEXT_ALIGN 128 + +#ifdef __cplusplus +extern "C" { +#endif + +struct mars_workload_context +{ + uint8_t reserved[MARS_WORKLOAD_RESERVED_SIZE]; + uint8_t data[MARS_WORKLOAD_CONTEXT_SIZE - MARS_WORKLOAD_RESERVED_SIZE]; +} __attribute__((aligned(MARS_WORKLOAD_CONTEXT_ALIGN))); + +enum mars_workload_query +{ + MARS_WORKLOAD_QUERY_IS_MODULE_CACHED = 0, /**< module cached? */ + MARS_WORKLOAD_QUERY_IS_CONTEXT_CACHED, /**< context cached? */ + MARS_WORKLOAD_QUERY_IS_INITIALIZED, /**< is initialized? */ + MARS_WORKLOAD_QUERY_IS_READY, /**< is ready? */ + MARS_WORKLOAD_QUERY_IS_WAITING, /**< is waiting? */ + MARS_WORKLOAD_QUERY_IS_RUNNING, /**< is running? */ + MARS_WORKLOAD_QUERY_IS_FINISHED, /**< is finished? */ + MARS_WORKLOAD_QUERY_IS_SIGNAL_SET /**< has signal set? */ +}; + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/base.h b/common/libspumars/include/ppu/mars/base.h new file mode 100644 index 00000000..2084060f --- /dev/null +++ b/common/libspumars/include/ppu/mars/base.h @@ -0,0 +1,261 @@ +#ifndef __MARS_BASE_H__ +#define __MARS_BASE_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_base + * \brief [host] Allocates memory in host storage. + * + * \param[in] size - size of memory block to allocate + * \return + * void * - pointer to allocated memory block + */ +void *mars_malloc(size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Re-allocates memory in host storage. + * + * \param[in] ptr - ptr to memory block to re-allocate + * \param[in] size - size of memory block to resize to + * \return + * void * - pointer to re-allocated memory block + */ +void *mars_realloc(void *ptr, size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Allocates memory on the stack + * + * \param[in] boundary - memory address will be a multiple of boundary + * \param[in] size - size of memory block to allocate + * \return + * void * - pointer to allocated memory block + */ +#define mars_alloca_align(boundary, size) \ + ( (void *)( ( (uintptr_t)alloca((size) + (boundary) - 1) + \ + (boundary) - 1) & \ + ~(uintptr_t)((boundary) - 1) ) ) + +/** + * \ingroup group_mars_base + * \brief [host] Frees memory allocated in host storage. + * + * \param[in] ptr - ptr to memory block to free + */ +void mars_free(void *ptr); + +/** + * \ingroup group_mars_base + * \brief [host] Allocates memory in shared storage accessible from MPU. + * + * \param[in] boundary - memory address will be a multiple of boundary + * \param[in] size - size of memory block to allocate + * \return + * uint64_t - 64-bit address of allocated memory block + */ +uint64_t mars_ea_memalign(size_t boundary, size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Frees memory allocated in shared storage. + * + * \param[in] ea - 64-bit address of allocated memory block to free + */ +void mars_ea_free(uint64_t ea); + +/** + * \ingroup group_mars_base + * \brief [host] Copy memory block from shared memory to host memory. + * + * \param[in] ea - 64-bit address of source + * \param[in] ptr - pointer to destination + * \param[in] size - size of memory block to copy + */ +void mars_ea_get(uint64_t ea, void *ptr, size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Get 8-bit integer value from shared memory + * + * \param[in] ea - 64-bit address of source + * + * \return + * uint8_t - 8-bit result, no guarantee that it is loaded atomically + */ +uint8_t mars_ea_get_uint8(uint64_t ea); + +/** + * \ingroup group_mars_base + * \brief [host] Get 16-bit integer value from shared memory + * + * \param[in] ea - 64-bit address of source + * + * \return + * uint16_t - 16-bit result, no guarantee that it is loaded atomically + */ +uint16_t mars_ea_get_uint16(uint64_t ea); + +/** + * \ingroup group_mars_base + * \brief [host] Get 32-bit integer value from shared memory atomically + * + * \param[in] ea - 64-bit address of source + * + * \return + * uint32_t - 32-bit result + */ + +uint32_t mars_ea_get_uint32(uint64_t ea); + +/** + * \ingroup group_mars_base + * \brief [host] Get 64-bit integer value from shared memory + * + * \param[in] ea - 64-bit address of source + * + * \return + * uint64_t - 64-bit result, no guarantee that it is loaded atomically + */ +uint64_t mars_ea_get_uint64(uint64_t ea); + +/** + * \ingroup group_mars_base + * \brief [host] Copy memory block from host memory to shared memory. + * + * \param[in] ea - 64-bit address of destination + * \param[in] ptr - pointer to source + * \param[in] size - size of memory block to copy + */ +void mars_ea_put(uint64_t ea, const void *ptr, size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Put 8-bit integer value to shared memory atomically + * + * \param[in] ea - 64-bit address of destination + * \param[in] value - 8-bit value to be stored in shared memory, no guarantee that it is stored atomically + */ +void mars_ea_put_uint8(uint64_t ea, uint8_t value); + +/** + * \ingroup group_mars_base + * \brief [host] Put 16-bit integer value to shared memory atomically + * + * \param[in] ea - 64-bit address of destination + * \param[in] value - 16-bit value to be stored in shared memory, no guarantee that it is stored atomically + */ +void mars_ea_put_uint16(uint64_t ea, uint16_t value); + +/** + * \ingroup group_mars_base + * \brief [host] Put 32-bit integer value to shared memory atomically + * + * \param[in] ea - 64-bit address of destination + * \param[in] value - 32-bit value to be stored in shared memory + */ +void mars_ea_put_uint32(uint64_t ea, uint32_t value); + +/** + * \ingroup group_mars_base + * \brief [host] Put 64-bit integer value to shared memory atomically + * + * \param[in] ea - 64-bit address of destination + * \param[in] value - 64-bit value to be stored in shared memory, no guarantee that it is stored atomically + */ +void mars_ea_put_uint64(uint64_t ea, uint64_t value); + +/** + * \ingroup group_mars_base + * \brief [host] Enable read access to data in specified memory block from MPU + * + * \param[in] ptr - pointer to source + * \param[in] size - size of memory block + * + * \return + * uint64_t - 64-bit address of memory block + */ +uint64_t mars_ea_map(void *ptr, size_t size); + +/** + * \ingroup group_mars_base + * \brief [host] Disable data access enabled by mars_ea_map + * + * \param[in] ea - 64-bit address of memory block + * \param[in] size - size of memory block + */ +void mars_ea_unmap(uint64_t ea, size_t size); + +/* test_cond: + * MARS_SUCCESS: the condition is satisfied + * <0: the condition is not satisfied + * >0: error code + */ +int mars_ea_cond_wait(uint64_t watch_point_ea, + int (*test_cond)(uint32_t , void *), + void *test_cond_param); + +int mars_ea_cond_signal(uint64_t watch_point_ea, int broadcast); + +#ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY +# define mars_ea_work_area_get(ea, boundary, size) mars_alloca_align(boundary, size) +#else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + /* work area is unnecessary for non-discrete shared memory model */ +# define mars_ea_work_area_get(ea, boundary, size) mars_ea_to_ptr(ea) +#endif /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + +/** + * \ingroup group_mars_base + * \brief [host] Memory barrier + */ +void mars_ea_sync(void); + +/** + * \ingroup group_mars_base + * \brief [host] Converts a 64-bit address to pointer. + * + * \param[in] ea - 64-bit address + * \return + * void * - pointer value + */ +static inline void *mars_ea_to_ptr(uint64_t ea) +{ + return (void *)(uintptr_t)ea; +} + +/** + * \ingroup group_mars_base + * \brief [host] Converts a pointer to 64-bit address. + * + * \param[in] ptr - pointer value + * \return + * uint64_t - 64-bit address + */ +static inline uint64_t mars_ptr_to_ea(const void *ptr) +{ + return (uint64_t)(const uintptr_t)ptr; +} + +/** + * \ingroup group_mars_base + * \brief [host/MPU] Returns tick counter value. + * + * \note Counter's frequency depends on runtime environment. + * + * \return + * uint32_t - 32-bit tick counter value + */ +uint32_t mars_get_ticks(void); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/context.h b/common/libspumars/include/ppu/mars/context.h new file mode 100644 index 00000000..5b3495e4 --- /dev/null +++ b/common/libspumars/include/ppu/mars/context.h @@ -0,0 +1,95 @@ +#ifndef __MARS_CONTEXT_H__ +#define __MARS_CONTEXT_H__ + +#include + +/** + * \ingroup group_mars_context + * \brief MARS context structure + * + * An instance of this structure must be created and initialized before + * using any of the MARS API. + */ +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_context + * \brief [host] Creates a single MARS context. + * + * This function creates a single MARS context. A MARS context must be + * created before any of the MARS functionality can be used. This will + * create the MPU contexts that are each loaded with and run the MARS kernel. + * The MARS kernel on each MPU will continue to run until the MARS context + * is destroyed through \ref mars_context_destroy. + * + * Key Parameters: + * \n \n + * \e num_mpus + * - Specify total number of MPUs to be used by the MARS context + * - If 0 is specified, MARS will use the maximum number of MPUs available in + * the system. + * + * \e shared + * - Specify 1 to share the context with other libraries linked into the + * application that also utilize MARS. + * - Specify 0 to create an independent MARS context that is not shared with + * other libraries linked into the application that also utilize MARS. + * - Sharing a single MARS context within an application with other libraries + * will maximize the MARS benefits of MPU utilization. + * + * \note If there are multiple MARS contexts created in the system, then + * each MARS context will suffer the large over head of MPU context switches. + * + * \param[out] mars - address of pointer to MARS context + * \param[in] num_mpus - number of mpus requested by MARS context + * \param[in] spu_prio - priority of SPU thread group + * \param[in] ppuPriority - priority of MARS handler PPU thread + * \return + * MARS_SUCCESS - successfully created MARS context + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_LIMIT - no more available MPUs or system threads + * \n MARS_ERROR_PARAMS - more MPUs requested than there are available + * \n MARS_ERROR_MEMORY - not enough memory + * \n MARS_ERROR_INTERNAL - some internal error occurred + */ +int mars_context_create(struct mars_context **mars, uint32_t num_mpus, uint32_t spu_prio, uint32_t ppu_prio); + +/** + * \ingroup group_mars_context + * \brief [host] Destroys a single MARS context. + * + * This function destroys a single MARS context that was previously + * created by \ref mars_context_create. In order to successfully destroy + * a MARS context, all workloads added to the workload queue must be + * completed and destroyed so that the workload queue is empty. + * + * \param[in] mars - pointer to MARS context + * \return + * MARS_SUCCESS - successfully destroyed MARS context + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_STATE - workload queue is not empty + */ +int mars_context_destroy(struct mars_context *mars); + +/** + * \ingroup group_mars_context + * \brief [host] Returns number of MPUs allocated for MARS context. + * + * This function returns the number of MPUs allocated for the MARS context. + * + * \param[in] mars - pointer to MARS context + * \return + * non-zero - number of MPUs + * \n 0 - invalid MARS context + */ +uint32_t mars_context_get_num_mpus(struct mars_context *mars); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/mutex.h b/common/libspumars/include/ppu/mars/mutex.h new file mode 100644 index 00000000..92d35a1e --- /dev/null +++ b/common/libspumars/include/ppu/mars/mutex.h @@ -0,0 +1,130 @@ +#ifndef __MARS_MUTEX_H__ +#define __MARS_MUTEX_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_mutex + * \brief [host] Creates a mutex. + * + * This function creates a mutex instance that can be locked or unlocked + * from both host and MPU to restrict concurrent accesses. + * + * \param[in] mutex_ea - ea of mutex instance + * \return + * MARS_SUCCESS - successfully created mutex + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_MEMORY - instance not aligned properly + */ +int mars_mutex_create(uint64_t *mutex_ea); + +/** + * \ingroup group_mars_mutex + * \brief [host] Destroys a mutex. + * + * This function destroys a mutex instance. + * + * \param[in] mutex_ea - ea of mutex instance + * \return + * MARS_SUCCESS - successfully destroyed mutex + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_ALIGN - instance not aligned properly + */ +int mars_mutex_destroy(uint64_t mutex_ea); + +/** + * \ingroup group_mars_mutex + * \brief [host] Resets a mutex. + * + * This function resets a mutex instance and forces it into an unlocked state + * regardless of whether it is locked or unlocked. + * + * \param[in] mutex_ea - ea of mutex instance + * \return + * MARS_SUCCESS - successfully reset mutex + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_ALIGN - instance not aligned properly + */ +int mars_mutex_reset(uint64_t mutex_ea); + +/** + * \ingroup group_mars_mutex + * \brief [host] Locks a mutex. + * + * This function locks a mutex and blocks other requests to lock it. + * + * \param[in] mutex_ea - ea of mutex instance + * \return + * MARS_SUCCESS - successfully locked mutex + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_ALIGN - instance not aligned properly + */ +int mars_mutex_lock(uint64_t mutex_ea); + +/** + * \ingroup group_mars_mutex + * \brief [host] Unlocks a mutex. + * + * This function unlocks a previously locked mutex to allow other lock requests. + * + * \param[in] mutex_ea - ea of mutex instance + * \return + * MARS_SUCCESS - successfully unlocked mutex + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_ALIGN - instance not aligned properly + * \n MARS_ERROR_STATE - instance not in locked state + */ +int mars_mutex_unlock(uint64_t mutex_ea); + +/** + * \ingroup group_mars_mutex + * \brief [host] Locks a mutex. + * + * This function locks a mutex and blocks other requests to lock it. + * It also loads the mutex instance from the effective address specified + * into the local mutex instance. + * + * \note This call should only be used when MARS_ENABLE_DISCRETE_SHARED_MEMORY + * is enabled. Otherwise, the mutex parameter is ignored and the function + * behaves the same as \ref mars_mutex_lock. + * + * \param[in] mutex_ea - ea of mutex instance to lock + * \param[in] mutex - pointer to local mutex instance + * \return + * MARS_SUCCESS - successfully locked mutex + * \n MARS_ERROR_NULL - ea is 0 or mutex is NULL + * \n MARS_ERROR_ALIGN - ea or mutex not aligned properly + */ +int mars_mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex); + +/** + * \ingroup group_mars_mutex + * \brief [host] Unlocks a mutex. + * + * This function unlocks a previously locked mutex to allow other lock requests. + * It also stores the local mutex instance into the effective address specified. + * + * \note This call should only be used when MARS_ENABLE_DISCRETE_SHARED_MEMORY + * is enabled. Otherwise, the mutex parameter is ignored and the function + * behaves the same as \ref mars_mutex_unlock. + * + * \param[in] mutex_ea - ea of mutex instance to unlock + * \param[in] mutex - pointer to local mutex instance + * \return + * MARS_SUCCESS - successfully unlocked mutex + * \n MARS_ERROR_NULL - ea is 0 or mutex is NULL + * \n MARS_ERROR_ALIGN - ea or mutex not aligned properly + * \n MARS_ERROR_STATE - instance not in locked state + */ +int mars_mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task.h b/common/libspumars/include/ppu/mars/task.h new file mode 100644 index 00000000..1c7437bc --- /dev/null +++ b/common/libspumars/include/ppu/mars/task.h @@ -0,0 +1,132 @@ +#ifndef __MARS_TASK_H__ +#define __MARS_TASK_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task + * \brief [host] Creates a MARS task. + * + * This function creates a single task and adds it the MARS context's + * workload queue. + * Upon success, a valid task id will be returned. + * You must call \ref mars_task_schedule in order for it to be scheduled for + * execution by the kernel. + * The task is in the finished state upon creation and may be destroyed by + * \ref mars_task_destroy without ever being scheduled for execution. + * + * Key Parameters: + * \n \n + * \e name + * - The name is optional, but if specified to other than NULL its + * length must not exceed \ref MARS_TASK_NAME_LEN_MAX. + * - An empty string will be treated the same as passing NULL, and will return + * NULL if \ref mars_task_get_name is called on the task. + * - The name does need to be kept allocated after this function returns. + + * \e elf_image + * - The address of MPU program elf image in host storage that will be run + * by this task. + * - The elf image must remain allocated until the task is destroyed. + + * \e context_save_size + * - If 0 is specified, then no context save area will be allocated for the task + * and therefore the task must be a run-complete task. + * - A run-complete task will run and occupy an MPU until it has completed + * running and exits. + * - A run-complete task cannot context switch, and therefore cannot call + * functions that will enter that task into a wait state. + * - If \ref MARS_TASK_CONTEXT_SAVE_SIZE_MAX is specified, the maximum size + * context save area required will be allocated and all of the MPU storage area + * used by the task will be saved and restored. + * - Advanced users can specify a size between 0 and + * \ref MARS_TASK_CONTEXT_SAVE_SIZE_MAX in order to minimize memory usage for + * the context save area. + * - The size specified must be large enough to hold all of the task program's + * text, data, heap, stack and non-volatile registers 80-127. + * + * \param[in] mars - pointer to MARS context + * \param[out] id - address of pointer to task id instance + * \param[in] name - name of task + * \param[in] elf_image - address of MPU program elf image + * \param[in] context_save_size - [ 0 ~ \ref MARS_TASK_CONTEXT_SAVE_SIZE_MAX ] + * \return + * MARS_SUCCESS - successfully created MARS task + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad params specified + * \n MARS_ERROR_MEMORY - not enough memory + * \n MARS_ERROR_LIMIT - task queue is currently full + */ +int mars_task_create(struct mars_context *mars, + struct mars_task_id *id, + const char *name, + const void *elf_image, + uint32_t context_save_size); + +/** + * \ingroup group_mars_task + * \brief [host] Destroys a MARS task. + * + * This function destroys a task created by \ref mars_task_create. + * The task will only be destroyed if the task is in the finished state. + * Once this function returns successfully and the task is destroyed, the task + * id is no longer valid. + * To guarantee the task has finished before calling this function, you should + * wait for task completion by calling \ref mars_task_wait or + * \ref mars_task_try_wait. + * + * \param[in] id - pointer to task id instance + * \return + * MARS_SUCCESS - successfully destroyed MARS task + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + */ +int mars_task_destroy(struct mars_task_id *id); + +/** + * \ingroup group_mars_task + */ +int mars_task_schedule(const struct mars_task_id *id, + const struct mars_task_args *args, + uint8_t priority); + +/** + * \ingroup group_mars_task + */ +int mars_task_unschedule(const struct mars_task_id *id, int32_t exit_code); + +/** + * \ingroup group_mars_task + */ +int mars_task_wait(const struct mars_task_id *id, int32_t *exit_code); + +/** + * \ingroup group_mars_task + */ +int mars_task_try_wait(const struct mars_task_id *id, int32_t *exit_code); + +/** + * \ingroup group_mars_task + */ +uint32_t mars_task_get_ticks(void); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task_barrier.h b/common/libspumars/include/ppu/mars/task_barrier.h new file mode 100644 index 00000000..35cac4de --- /dev/null +++ b/common/libspumars/include/ppu/mars/task_barrier.h @@ -0,0 +1,78 @@ +#ifndef __MARS_TASK_BARRIER_H__ +#define __MARS_TASK_BARRIER_H__ + +#include +#include + +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_barrier + * \brief [host] Creates a task barrier. + * + * This function will allocate an instance of the task barrier. + * The barrier allows for tasks within the barrier group to wait until all + * tasks arrive at some synchronization point and notify the barrier. + * All tasks included in the barrier group should call the notify and wait in + * pairs. + * + * Key Parameters: + * \n \n + * \e total + * - Specify total number of tasks that will be associated with this barrier. + * - Total must be a value between 1 and \ref MARS_TASK_BARRIER_WAIT_MAX. + * + * \param[in] mars - pointer to MARS context + * \param[out] barrier_ea - ea of barrier instance + * \param[in] total - number of notifies before barrier released + * \return + * MARS_SUCCESS - successfully created barrier + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - total is 0 or exceeds allowed limit + */ +int mars_task_barrier_create(struct mars_context *mars, + uint64_t *barrier_ea, + uint32_t total); + + +/** + * \ingroup group_mars_task_barrier + * \brief [host] Initialize a task barrier. + * + * This function will initialize a task barrier to a new number + * of notifies before barrier release. + * + * \param[in] barrier_ea - ea of barrier instance + * \param[in] total - number of notifies before barrier released + * \return + * MARS_SUCCESS - successfully destroyed barrier + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - total is 0 or exceeds allowed limit + */ +int mars_task_barrier_initialize(uint64_t barrier_ea, + uint32_t total); +/** + * \ingroup group_mars_task_barrier + * \brief [host] Destroys a task barrier. + * + * This function will free any resources allocated during creation of the task + * barrier. + * + * \param[in] barrier_ea - ea of barrier instance + * \return + * MARS_SUCCESS - successfully destroyed barrier + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_STATE - tasks still waiting + */ +int mars_task_barrier_destroy(uint64_t barrier_ea); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task_event_flag.h b/common/libspumars/include/ppu/mars/task_event_flag.h new file mode 100644 index 00000000..b08bc474 --- /dev/null +++ b/common/libspumars/include/ppu/mars/task_event_flag.h @@ -0,0 +1,96 @@ +#ifndef __MARS_TASK_EVENT_FLAG_H__ +#define __MARS_TASK_EVENT_FLAG_H__ + +#include +#include + +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_event_flag + * \brief [host] Creates a task event flag. + * + * This function will allocate an instance of the task event flag. + * The event flag allows for tasks to wait on specific events. + * The event flag should be used in pairs with calls to set an event flag and + * wait for an event flag. + * + * Key Parameters: + * \n \n + * \e direction + * - Specify the communication direction of the event flag. + * - Must be one of \ref MARS_TASK_EVENT_FLAG_HOST_TO_MPU, + * \ref MARS_TASK_EVENT_FLAG_MPU_TO_HOST, \ref MARS_TASK_EVENT_FLAG_MPU_TO_MPU. + * + * \e clear_mode + * - Specify when the event flag is cleared. + * - Specify \ref MARS_TASK_EVENT_FLAG_CLEAR_AUTO to have event flag bits + * cleared automatically when a task waiting on the event flag bits has been + * notified of the event. + * - Specify \ref MARS_TASK_EVENT_FLAG_CLEAR_MANUAL to have the event flag bits + * remain set until the user manually clears them through + * \ref mars_task_event_flag_clear. + * + * \param[in] mars - pointer to MARS context + * \param[out] event_flag_ea - ea of event flag instance + * \param[in] direction - direction of the event flag + * \param[in] clear_mode - behavior of how the event flag is cleared + * \return + * MARS_SUCCESS - successfully created event flag + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid direction or clear mode specified + */ +int mars_task_event_flag_create(struct mars_context *mars, + uint64_t *event_flag_ea, + uint8_t direction, + uint8_t clear_mode); + +/** + * \ingroup group_mars_task_event_flag + * \brief [host] Destroys a task event flag. + * + * This function will free any resources allocated during creation of the task + * event flag. + * + * \param[in] event_flag_ea - ea of event flag instance + * \return + * MARS_SUCCESS - successfully destroyed event flag + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_STATE - tasks still waiting + */ +int mars_task_event_flag_destroy(uint64_t event_flag_ea); + +/** + * \ingroup group_mars_task_event_flag + */ +int mars_task_event_flag_clear(uint64_t event_flag_ea, uint32_t bits); + +/** + * \ingroup group_mars_task_event_flag + */ +int mars_task_event_flag_set(uint64_t event_flag_ea, uint32_t bits); + +/** + * \ingroup group_mars_task_event_flag + */ +int mars_task_event_flag_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits); + +/** + * \ingroup group_mars_task_event_flag + */ +int mars_task_event_flag_try_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task_queue.h b/common/libspumars/include/ppu/mars/task_queue.h new file mode 100644 index 00000000..a405be85 --- /dev/null +++ b/common/libspumars/include/ppu/mars/task_queue.h @@ -0,0 +1,120 @@ +#ifndef __MARS_TASK_QUEUE_H__ +#define __MARS_TASK_QUEUE_H__ + +#include +#include + +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_queue + * \brief [host] Creates a task queue. + * + * This function will allocate an instance of the task queue. + * The queue allows for tasks to wait until data is available from a FIFO + * data queue. + * The queue should be used in pairs with various calls to push and pop the + * the queue + * + * Key Parameters: + * \n \n + * \e size + * - Specify the size of each data item in the queue. + * - The size needs to be a multiple of 16 bytes and no larger than + * \ref MARS_TASK_QUEUE_ENTRY_SIZE_MAX. + * + * \e depth + * - Specify the depth of the total queue. + * - The number specified here is the total number of data items the queue + * can hold at a time. + * - The size of the total queue is \e size * \e depth. + * + * \e direction + * - Specify the communication direction of the queue. + * - Must be one of \ref MARS_TASK_QUEUE_HOST_TO_MPU, + * \ref MARS_TASK_QUEUE_MPU_TO_HOST, \ref MARS_TASK_QUEUE_MPU_TO_MPU. + * + * \param[in] mars - pointer to MARS context + * \param[out] queue_ea - address of 64-bit address of queue instance + * \param[in] size - size of each data item in data buffer + * \param[in] depth - maximum number of data entries in data buffer + * \param[in] direction - direction of the event flag + * \return + * MARS_SUCCESS - successfully created queue + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - size is not multiple of 16 bytes or is greater + * than 16KB maximum + * \n MARS_ERROR_PARAMS - invalid direction specified + * \n MARS_ERROR_MEMORY - not enough memory for queue buffer allocation + */ +int mars_task_queue_create(struct mars_context *mars, + uint64_t *queue_ea, + uint32_t size, + uint32_t depth, + uint8_t direction); + +/** + * \ingroup group_mars_task_queue + * \brief [host] Destroys a task queue. + * + * This function will free any resources allocated during creation of the task + * queue. + * + * \param[in] queue_ea - ea of queue instance + * \return + * MARS_SUCCESS - successfully destroyed queue + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_STATE - tasks still waiting + */ +int mars_task_queue_destroy(uint64_t queue_ea); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_count(uint64_t queue_ea, uint32_t *count); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_clear(uint64_t queue_ea); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_push(uint64_t queue_ea, const void *data); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_try_push(uint64_t queue_ea, const void *data); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_pop(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_try_pop(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_peek(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + */ +int mars_task_queue_try_peek(uint64_t queue_ea, void *data); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task_semaphore.h b/common/libspumars/include/ppu/mars/task_semaphore.h new file mode 100644 index 00000000..3112f53e --- /dev/null +++ b/common/libspumars/include/ppu/mars/task_semaphore.h @@ -0,0 +1,60 @@ +#ifndef __MARS_TASK_SEMAPHORE_H__ +#define __MARS_TASK_SEMAPHORE_H__ + +#include +#include + +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_semaphore + * \brief [host] Creates a task semaphore. + * + * This function will allocate an instance of the task semaphore. + * The semaphore allows for tasks to wait until a semaphore can be obtained. + * The semaphore should be used in pairs with calls to acquire and release. + * + * Key Parameters: + * \n \n + * \e count + * - Specify the total number of entities that can have access to the semaphore + * simultaneously. + * - Must not be greater than \ref MARS_TASK_SEMAPHORE_WAIT_MAX. + * + * \param[in] mars - pointer to MARS context + * \param[out] semaphore_ea - ea of semaphore instance + * \param[in] count - initial number of task accesses allowed + * \return + * MARS_SUCCESS - successfully created semaphore + * \n MARS_ERROR_NULL - null pointer is specified + * \n MARS_ERROR_PARAMS - count exceeds allowed limit + */ +int mars_task_semaphore_create(struct mars_context *mars, + uint64_t *semaphore_ea, + int32_t count); + +/** + * \ingroup group_mars_task_semaphore + * \brief [host] Destroys a task semaphore. + * + * This function will free any resources allocated during creation of the task + * semaphore. + * + * \param[in] semaphore_ea - ea of semaphore instance + * \return + * MARS_SUCCESS - successfully destroyed semaphore + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_STATE - tasks still waiting + */ +int mars_task_semaphore_destroy(uint64_t semaphore_ea); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/task_signal.h b/common/libspumars/include/ppu/mars/task_signal.h new file mode 100644 index 00000000..4381de24 --- /dev/null +++ b/common/libspumars/include/ppu/mars/task_signal.h @@ -0,0 +1,20 @@ +#ifndef __MARS_TASK_SIGNAL_H__ +#define __MARS_TASK_SIGNAL_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_signal + */ +int mars_task_signal_send(struct mars_task_id *id); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/ppu/mars/workload_queue.h b/common/libspumars/include/ppu/mars/workload_queue.h new file mode 100644 index 00000000..4860f0c5 --- /dev/null +++ b/common/libspumars/include/ppu/mars/workload_queue.h @@ -0,0 +1,330 @@ +#ifndef __MARS_WORKLOAD_QUEUE_H__ +#define __MARS_WORKLOAD_QUEUE_H__ + +#include +#include + +struct mars_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Returns whether or not specified query is satisfied. + * + * \note Query type \ref MARS_WORKLOAD_QUERY_IS_MODULE_CACHED and + * \ref MARS_WORKLOAD_QUERY_IS_CONTEXT_CACHED are only valid queries for the + * MPU-side call to \ref mars_module_workload_query. + * Calling \ref mars_workload_queue_query with these queries will always return + * 0. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[in] query - query type + * \return + * int - non-zero if query satisfied + */ +int mars_workload_queue_query(struct mars_context *mars, + uint16_t id, + int query); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Begins adding workload to workload queue. + * + * This function will begin the process to add a workload to the workload queue. + * This only initiates the add operation. + * This function must be completed with a matching call to + * \ref mars_workload_queue_add_end to guarantee the completion of the add + * operation. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * The workload adding process is not completed until the matching call to + * \ref mars_workload_queue_add_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * \param[in] mars - address of pointer to MARS context + * \param[out] id - pointer to return workload id + * \param[out] workload_ea - address of pointer to workload context ea + * \param[in] module_elf - pointer to workload module elf image + * \param[in] module_name - name of module + * \return + * MARS_SUCCESS - workload adding started + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or module specified + * \n MARS_ERROR_LIMIT - workload queue is full + */ +int mars_workload_queue_add_begin(struct mars_context *mars, + uint16_t *id, + uint64_t *workload_ea, + const void *module_elf, + const char *module_name); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Ends adding of specified workload. + * + * This function will complete a add operation previously initiated with + * \ref mars_workload_queue_add_begin. + * This function must be called in pair for each call to + * \ref mars_workload_queue_add_begin to guarantee the completion of the + * initiated add operation. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload to end add + * \param[in] cancel - cancels the add operation + * \return + * MARS_SUCCESS - workload adding complete + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - workload adding not started + */ +int mars_workload_queue_add_end(struct mars_context *mars, + uint16_t id, + int cancel); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Begins removing workload from workload queue. + * + * This function will begin the process to remove a workload from the workload + * queue. + * This only initiates the remove operation. + * This function must be completed with a matching call to + * \ref mars_workload_queue_remove_end to guarantee the completion of the remove + * operation. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * The workload removing process is not completed until the matching call to + * \ref mars_workload_queue_remove_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload to begin remove + * \param[out] workload_ea - address of pointer to workload context ea + * \return + * MARS_SUCCESS - workload removing started + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context specified + * \n MARS_ERROR_STATE - specified workload not added or finished + */ +int mars_workload_queue_remove_begin(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Ends removing of specified workload. + * + * This function will complete a remove operation previously initiated with + * \ref mars_workload_queue_remove_begin. + * This function must be called in pair for each call to + * \ref mars_workload_queue_remove_begin to guarantee the completion of the + * initiated remove operation. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[in] cancel - cancels the remove operation + * \return + * MARS_SUCCESS - workload removing complete + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - workload removing not started + */ +int mars_workload_queue_remove_end(struct mars_context *mars, + uint16_t id, + int cancel); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Begins scheduling of specified workload. + * + * This function will begin scheduling the workload specified. + * This only initiates the scheduling of the workload. + * This function must be completed with a matching call to + * \ref mars_workload_queue_schedule_end to guarantee the completion of the + * scheduling. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * The workload scheduling process is not completed until the matching call to + * \ref mars_workload_queue_schedule_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[in] priority - scheduling priority of workload + * \param[out] workload_ea - address of pointer to workload context ea + * \return + * MARS_SUCCESS - workload scheduling started + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - specified workload not added or finished + */ +int mars_workload_queue_schedule_begin(struct mars_context *mars, + uint16_t id, uint8_t priority, + uint64_t *workload_ea); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Ends scheduling of specified workload. + * + * This function will complete a schedule operation previously initiated with + * \ref mars_workload_queue_schedule_begin. + * This function must be called in pair for each call to + * \ref mars_workload_queue_schedule_begin to guarantee the completion of the + * initiated schedule operation. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[in] cancel - cancels the schedule operation + * \return + * MARS_SUCCESS - workload scheduling complete + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - workload scheduling not started + */ +int mars_workload_queue_schedule_end(struct mars_context *mars, + uint16_t id, + int cancel); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Begins unscheduling of specified workload. + * + * This function will begin unscheduling the workload specified. + * This only initiates the unscheduling of the workload. + * This function must be completed with a matching call to + * \ref mars_workload_queue_unschedule_end to guarantee the completion of the + * unscheduling. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * The workload unscheduling process is not completed until the matching call to + * \ref mars_workload_queue_unschedule_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * When a workload is unscheduled, it will be put into a finished state and any + * entities waiting on the workload to finish will be resumed. + * + * If a scheduled workload is unscheduled before execution, the workload will + * not be executed until a subsequent scheduling request is made. + * + * If the workload is currently in a waiting state, calling unschedule will + * finish the workload and will not be resumed from the waiting state. + * + * If the workload is currently in a running state, calling unschedule will + * immediately put the workload into a finished state. However, execution of the + * workload will only be suspended when the workload yields, waits, or finishes. + * + * \note + * Trying to unschedule a workload that has not yet been scheduled, or has + * already finished a previously scheduled execution will return an error. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[out] workload_ea - address of pointer to workload context ea + * \return + * MARS_SUCCESS - workload aborted + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - workload is not scheduled or has finished + */ +int mars_workload_queue_unschedule_begin(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Ends unscheduling of specified workload. + * + * This function will complete an unschedule operation previously initiated with + * \ref mars_workload_queue_unschedule_begin. + * This function must be called in pair for each call to + * \ref mars_workload_queue_unschedule_begin to guarantee the completion of the + * initiated unschedule operation. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \return + * MARS_SUCCESS - workload unscheduling complete + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - workload unscheduling not started + */ +int mars_workload_queue_unschedule_end(struct mars_context *mars, + uint16_t id); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Waits for specified workload to finish. + * + * This function will block and wait until the specified workload finishes. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[out] workload_ea - address of pointer to workload context ea + * \return + * MARS_SUCCESS - workload is finished + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - invalid workload specified + */ +int mars_workload_queue_wait(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Waits for specified workload to finish. + * + * This function will check whether the workload specified is finished or not + * and return immediately without blocking. + * + * If workload_ea is not NULL, the ea of the workload will be returned. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \param[out] workload_ea - address of pointer to workload context ea + * \return + * MARS_SUCCESS - workload is finished + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - invalid workload specified + * \n MARS_ERROR_BUSY - workload has not yet finished + */ +int mars_workload_queue_try_wait(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea); + +/** + * \ingroup group_mars_workload_queue + * \brief [host] Sends signal to specified workload. + * + * This function will send a signal to the specified workload. + * + * \param[in] mars - address of pointer to MARS context + * \param[in] id - id of workload + * \return + * MARS_SUCCESS - signalled workload + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - invalid mars context or workload id specified + * \n MARS_ERROR_STATE - invalid workload specified + */ +int mars_workload_queue_signal_send(struct mars_context *mars, + uint16_t id); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/module.h b/common/libspumars/include/spu/mars/module.h new file mode 100644 index 00000000..46a70cb9 --- /dev/null +++ b/common/libspumars/include/spu/mars/module.h @@ -0,0 +1,408 @@ +#ifndef __MARS_MODULE_H__ +#define __MARS_MODULE_H__ + +#include + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Entry point for workload module. + * + * This function is the main entry point for the workload module. All workload + * modules will need to have a definition of this function. This function is + * called from the MARS kernel when a workload context that specifies this + * workload module is scheduled for execution. + * + * \note Returning from this function is equivalent to calling + * \ref mars_module_workload_finish. + */ +void mars_module_main(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets tick counter value. + * + * \note Counter's frequency depends on runtime environment. + * + * \return + * uint32_t - 32-bit tick counter value + */ +uint32_t mars_module_get_ticks(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets ea of MARS context. + * + * \return + * uint64_t - ea of MARS context + */ +uint64_t mars_module_get_mars_context_ea(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets id of kernel that the module is being executed on. + * + * \return + * uint16_t - id of MARS kernel + */ +uint16_t mars_module_get_kernel_id(void); + + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets id of current workload context. + * + * \return + * uint16_t - id of workload + */ +uint16_t mars_module_get_workload_id(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets pointer to current workload context. + * + * \return + * struct mars_workload_context * - pointer to current workload context + */ +struct mars_workload_context *mars_module_get_workload(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Gets pointer to workload context specified by id. + * + * \param[in] id - id of workload + * \return + * struct mars_workload_context * - pointer to specified workload context + */ +struct mars_workload_context *mars_module_get_workload_by_id(uint16_t id); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Returns whether or not specified query is satisfied. + * + * \param[in] id - id of workload + * \param[in] query - query type + * \return + * int - non-zero if query satisfied + + */ +int mars_module_workload_query(uint16_t id, int query); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Sets calling workload to wait for completion of specified workload. + * + * \note This function only sets the id of workload to wait for completion. + * The caller should also \ref mars_module_workload_wait immediately after this + * call so the calling workload yields execution and enters the waiting state. + * + * \param[in] id - id of workload + * \return + * MARS_SUCCESS - id of workload to wait for set + * \n MARS_ERROR_PARAMS - invalid workload id specified + */ +int mars_module_workload_wait_set(uint16_t id); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Sets calling workload to not wait for completion of any workloads. + * + * \return + * MARS_SUCCESS - id of workload to wait for reset + * \n MARS_ERROR_PARAMS - invalid workload id specified + */ +int mars_module_workload_wait_reset(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Sets signal for specified workload. + * + * \param[in] id - id of workload + * \return + * MARS_SUCCESS - signal set + * \n MARS_ERROR_PARAMS - invalid workload id specified + */ +int mars_module_workload_signal_set(uint16_t id); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Resets signal for specified workload. + * + * \return + * MARS_SUCCESS - signal reset + * \n MARS_ERROR_PARAMS - invalid workload id specified + */ +int mars_module_workload_signal_reset(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Begins scheduling of specified workload. + * + * This function will begin scheduling the workload specified. + * This only initiates the scheduling of the workload. + * This function must be completed with a matching call to + * \ref mars_module_workload_schedule_end to guarantee the completion of the + * scheduling. + * + * The workload scheduling process is not complete until the matching call to + * \ref mars_module_workload_schedule_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * \param[in] id - id of workload + * \param[in] priority - scheduling priority of workload + * \param[out] workload - address of pointer to workload context + * \return + * MARS_SUCCESS - workload scheduling started + * \n MARS_ERROR_PARAMS - invalid workload id specified + * \n MARS_ERROR_STATE - specified workload not added or finished + */ +int mars_module_workload_schedule_begin(uint16_t id, uint8_t priority, + struct mars_workload_context **workload); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Ends scheduling of specified workload. + * + * This function will complete a schedule operation previously initiated with + * \ref mars_module_workload_schedule_begin. + * This function must be called in pair for each call to + * \ref mars_module_workload_schedule_begin to guarantee the completion of the + * initiated schedule operation. + * + * \param[in] id - id of workload + * \param[in] cancel - cancels the schedule operation + * \return + * MARS_SUCCESS - workload scheduling complete + * \n MARS_ERROR_PARAMS - invalid workload id specified + * \n MARS_ERROR_STATE - workload scheduling not started + */ +int mars_module_workload_schedule_end(uint16_t id, int cancel); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Begins unscheduling of specified workload. + * + * This function will begin unscheduling the workload specified. + * This only initiates the unscheduling of the workload. + * This function must be completed with a matching call to + * \ref mars_module_workload_unschedule_end to guarantee the completion of the + * unscheduling. + * + * The workload unscheduling process is not complete until the matching call to + * \ref mars_module_workload_unschedule_end is made. + * The user should make any necessary updates to the returned workload context + * in between this begin call and the end call. + * + * When a workload is unscheduled, it will be put into a finished state and any + * entities waiting on the workload to finish will be resumed. + * + * If a scheduled workload is unscheduled before execution, the workload will + * not be executed until a subsequent scheduling request is made. + * + * If the workload is currently in a waiting state, calling unschedule will + * finish the workload and will not be resumed from the waiting state. + * + * If the workload is currently in a running state, calling unschedule will + * immediately put the workload into a finished state. However, execution of the + * workload will only be suspended when the workload yields, waits, or finishes. + * + * \note + * Trying to unschedule a workload that has not yet been scheduled, or has + * already finished a previously scheduled execution will return an error. + * + * \param[in] id - id of workload + * \param[out] workload - address of pointer to workload context + * \return + * MARS_SUCCESS - workload unscheduling started + * \n MARS_ERROR_PARAMS - invalid workload id specified + * \n MARS_ERROR_STATE - workload is not scheduled or has finished + */ +int mars_module_workload_unschedule_begin(uint16_t id, + struct mars_workload_context **workload); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Ends unscheduling of specified workload. + * + * This function will complete an unschedule operation previously initiated with + * \ref mars_module_workload_unschedule_begin. + * This function must be called in pair for each call to + * \ref mars_module_workload_unschedule_begin to guarantee the completion of the + * initiated unschedule operation. + * + * \return + * MARS_SUCCESS - workload unscheduling complete + * \n MARS_ERROR_PARAMS - invalid workload id specified + * \n MARS_ERROR_STATE - workload unscheduling not started + */ +int mars_module_workload_unschedule_end(uint16_t id); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Returns execution to kernel with workload in wait state. + * + * This function will yield execution of the calling workload module and return + * execution back to the kernel. The workload currently being processed will be + * put into a waiting state. + * + * \note This function will exit the workload module and is not re-entrant. + */ +void mars_module_workload_wait(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Returns execution to kernel with workload in ready state. + * + * This function will yield execution of the calling workload module and return + * execution back to the kernel. The workload currently being processed will be + * put into a ready state. + * + * \note This function will exit the workload module and is not re-entrant. + */ +void mars_module_workload_yield(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Returns execution to kernel with workload in finished state. + * + * This function will yield execution of the calling workload module and return + * execution back to the kernel. The workload currently being processed will be + * put into a finished state. + * + * \note This function will exit the workload module and is not re-entrant. + */ +void mars_module_workload_finish(void); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Notify host a particular 32-bit area is modified. + * + * \param[in] watch_point_ea - ea of modified area + * + */ +void mars_module_host_signal_send(uint64_t watch_point_ea); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Request host to call registered callback. + * + * \param[in] callback_ea - ea of function of type \ref mars_callback + * \param[in] in - pointer to input args in MPU storage + * + * \return + * MARS_SUCCESS - callback requested to host + */ +int mars_module_host_callback_set(uint64_t callback_ea, + const struct mars_callback_args *in); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Resets a host callback request and requests result. + * + * \param[out] out - pointer to output args to store result + * + * \return + * MARS_SUCCESS - callback request reset + */ +int mars_module_host_callback_reset(struct mars_callback_args *out); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Locks a mutex. + * + * This function locks a mutex and blocks other requests to lock it. + * It also loads the mutex instance from the effective address specified + * into the local mutex instance. + * + * \param[in] mutex_ea - ea of mutex instance to lock + * \param[in] mutex - pointer to local mutex instance + * \return + * MARS_SUCCESS - successfully locked mutex + * \n MARS_ERROR_NULL - ea is 0 or mutex is NULL + * \n MARS_ERROR_ALIGN - ea or mutex not aligned properly + */ +int mars_module_mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Unlocks a mutex. + * + * This function unlocks a previously locked mutex to allow other lock requests. + * It also stores the local mutex instance into the effective address specified. + * + * \param[in] mutex_ea - ea of mutex instance to unlock + * \param[in] mutex - pointer to local mutex instance + * \return + * MARS_SUCCESS - successfully unlocked mutex + * \n MARS_ERROR_NULL - ea is 0 or mutex is NULL + * \n MARS_ERROR_ALIGN - ea or mutex not aligned properly + * \n MARS_ERROR_STATE - instance not in locked state + */ +int mars_module_mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] DMA transfer from host storage to MPU storage. + * + * This function begins a DMA transfer request from host storage to MPU storage. + * Transfer completion is not guaranteed until calling \ref mars_module_dma_wait + * with the corresponding tag used to request the transfer. + * + * \param[in] ls - address of MPU storage to transfer to + * \param[in] ea - ea of host storage to transfer from + * \param[in] size - size of dma transfer + * \param[in] tag - tag of dma transfer + * \return + * MARS_SUCCESS - successfully tranferred data + * \n MARS_ERROR_PARAMS - invalid tag specified + * \n MARS_ERROR_ALIGN - ls or ea not aligned properly + */ +int mars_module_dma_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] DMA transfer from MPU storage to host storage. + * + * This function begins a DMA transfer request from MPU storage to host storage. + * Transfer completion is not guaranteed until calling \ref mars_module_dma_wait + * with the corresponding tag used to request the transfer. + * + * \param[in] ls - address of MPU storage to transfer to + * \param[in] ea - ea of host storage to transfer from + * \param[in] size - size of dma transfer + * \param[in] tag - tag of dma transfer + * \return + * MARS_SUCCESS - successfully tranferred data + * \n MARS_ERROR_PARAMS - invalid tag specified + * \n MARS_ERROR_ALIGN - ls or ea not aligned properly + */ +int mars_module_dma_put(const void *ls, uint64_t ea, uint32_t size, + uint32_t tag); + +/** + * \ingroup group_mars_workload_module + * \brief [MPU] Waits for completion of requested DMA transfer. + * + * This function waits until completion of all previously started DMA transfer + * requests with the same tag. + * + * \param[in] tag - tag of dma transfer + * \return + * MARS_SUCCESS - successfully waited for transfer completion + * \n MARS_ERROR_PARAMS - invalid tag specified + */ +int mars_module_dma_wait(uint32_t tag); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task.h b/common/libspumars/include/spu/mars/task.h new file mode 100644 index 00000000..f1b2d7ec --- /dev/null +++ b/common/libspumars/include/spu/mars/task.h @@ -0,0 +1,315 @@ +#ifndef __MARS_TASK_H__ +#define __MARS_TASK_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task + * \brief [MPU] Entry point for task. + * + * This function is the main entry point for the task program. All task + * programs will need to have a definition of this function. The arguments + * passed into this function are specified during task scheduling through + * the call to \ref mars_task_schedule. + * + * \note If NULL was specified for \e args when calling \ref mars_task_schedule, + * the contents of args are undefined. + * + * \param[in] args - pointer to task args structure in MPU storage + * \return + * user specified + */ +int mars_task_main(const struct mars_task_args *args); + +/** + * \ingroup group_mars_task + * \brief [MPU] Exits and terminates task. + * + * This function causes the task to exit and terminate execution. Calling this + * function will cause the task to enter the finished state, and will no + * longer be scheduled to run. This function does not need to be called when + * returning from \ref mars_task_main since it is called automatically. + * + * \note This function is a scheduling call and will put the caller task into a + * finished state. + * + * Key Parameters: + * \n \n + * \e exit_code + * - The value passed into here can be obtained when calling \ref mars_task_wait + * or \ref mars_task_try_wait. + * + * \param[out] exit_code - value to be returned to the task wait call + */ +void mars_task_exit(int32_t exit_code); + +/** + * \ingroup group_mars_task + * \brief [MPU] Yields caller task so other workloads can run. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function causes the task to yield and allow other workloads to be + * scheduled to run if available. The task's context state is saved and the + * kernel will reschedule the next available workload. If there are no other + * workloads to be scheduled, the task that called to yield will be rescheduled + * for resumed execution. + * + * \note This function is a scheduling call and may cause a task switch and put + * the caller task into a ready state. + * + * \return + * MARS_SUCCESS - successfully yielded task + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_yield(void); + +/** + * \ingroup group_mars_task + * \brief [host/MPU] Schedules a MARS task for execution. + * + * This function schedules the task specified for execution. + * The actual time of execution is determined by the scheduler. + * Once the task is scheduled for execution by this function, it may not be + * scheduled for execution until previous execution has finished. + * You can wait for task completion by calling \ref mars_task_wait or + * \ref mars_task_try_wait. + * + * You can call this function with a valid task id returned by + * \ref mars_task_create as many times as you want after each scheduled + * execution has completed. The task id is valid until the task is destroyed by + * \ref mars_task_destroy. + * + * Key Parameters: + * \n \n + * \e args + * - The task args (\ref mars_task_args) are optional, and only + * need to be passed in if the task executable expects it. + * - If NULL is specified the task args passed into the task executable's main + * function will not be initialized. + * - The args does need to be kept allocated after this function returns. + * + * \e priority + * - This is the priority of the task between 0 to 255, 0 being the lowest + * priority and 255 being the highest priority. + * - Tasks with higher priority will be prioritized during scheduling if both + * tasks are ready to run at the time of scheduling. + * + * \param[in] id - pointer to task id to schedule + * \param[in] args - pointer to task args to pass into task main + * \param[in] priority - priority of scheduling for the task + * \return + * MARS_SUCCESS - successfully scheduled MARS task for execution + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + */ +int mars_task_schedule(const struct mars_task_id *id, + const struct mars_task_args *args, + uint8_t priority); + +/** + * \ingroup group_mars_task + * \brief [host/MPU] Unschedules a MARS task from being executed. + * + * This function unschedules a previously scheduled task. + * + * When a task is unscheduled, it will behave as if the task has completed + * execution. The user is responsible for specifying a unique exit code when + * unscheduling tasks to handle the condition accordingly. + * + * If a scheduled task is unscheduled before execution, the workload will + * not be executed until a subsequent scheduling request is made. + * + * If the task is currently in a waiting state, calling unschedule will + * finish the workload and will not be resumed from the waiting state. + * + * If the task is currently in a running state, calling unschedule will + * immediately put the task into a finished state. However, execution of the + * task will only be suspended when the task yields, waits, or exits. + * + * \note + * Trying to unschedule a task that has not yet been scheduled, or has + * already finished a previously scheduled execution will return an error. + * + * Key Parameters: + * \n \n + * \e exit_code + * - The value passed into here can be obtained when calling \ref mars_task_wait + * or \ref mars_task_try_wait. + * + * \param[in] id - pointer to task id to abort + * \param[out] exit_code - value to be returned to the task wait call + * \return + * MARS_SUCCESS - successfully scheduled MARS task for execution + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + */ +int mars_task_unschedule(const struct mars_task_id *id, int32_t exit_code); + +/** + * \ingroup group_mars_task + * \brief [host/MPU] Waits for task completion. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will block until the scheduled task specified is finished. + * + * Any number of host threads or tasks can wait for a specific task to complete + * execution as long as it holds the task's id. However, the task being waited + * on should not be re-scheduled until all wait calls for the task have + * returned. Otherwise it is not guaranteed that all wait calls will return + * after the completion of the initial schedule call. + * + * Key Parameters: + * \n \n + * \e exit_code + * - Pass in a pointer to store the task exit code. + * - If NULL is specified, no exit code can be obtained when the task + * completes and returns. + * + * \note This function is a scheduling call and may cause a task switch and put + * the caller task into a waiting state. + * + * \param[in] id - pointer to task id to wait for + * \param[out] exit_code - pointer to variable to store task exit code + * \return + * MARS_SUCCESS - task execution finished + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_wait(const struct mars_task_id *id, int32_t *exit_code); + +/** + * \ingroup group_mars_task + * \brief [host/MPU] Waits for a task completion. + * + * This function will check whether the scheduled task specified is finished + * or not and return immediately without blocking. + * + * Key Parameters: + * \n \n + * \e exit_code + * - Pass in a pointer to store the task exit code. + * - If NULL is specified, no exit code can be obtained when the task + * completes and returns. + * + * \param[in] id - pointer to task id to wait for + * \param[out] exit_code - pointer to variable to store task exit code + * \return + * MARS_SUCCESS - task execution finished + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + * \n MARS_ERROR_BUSY - task has not yet finished execution + */ +int mars_task_try_wait(const struct mars_task_id *id, int32_t *exit_code); + +/** + * \ingroup group_mars_task + * \brief [MPU] Calls the specified host callback. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will block until the requested host callback function returns. + * + * Key Parameters: + * \n \n + * \e callback_ea + * - Pass in the EA of the host callback function you want called. This function + * should be of type \ref mars_callback. + * - If an invalid EA is specified, the resulting behavior is undetermined. + * + * \e in + * - Pass in a pointer to an initialized callback argument structure instance. + * - If NULL is specified, a pointer to an uninitialized callback argument + * structure will be passed into the host callback function. + * + * \e out + * - Pass in a pointer to a callback argument structure instance, which can be + * initialized by the host callback function. + * - If NULL is specified, the output argument structure initialized by the host + * callback function will not be returned to the caller. + * + * \param[in] callback_ea - ea of host callback of type \ref mars_callback + * \param[in] in - pointer to args, passed into to host callback + * \param[out] out - pointer to args, initialized by host callback + * \return + * MARS_SUCCESS - host callback successful + * \n MARS_ERROR_LIMIT - host callback queue is full + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_call_host(uint64_t callback_ea, + const struct mars_callback_args *in, + struct mars_callback_args *out); + +/** + * \ingroup group_mars_task + * \brief [host/MPU] Gets tick counter value. + * + * \note Counter's frequency depends on runtime environment. + * + * \return + * uint32_t - 32-bit tick counter value + */ +uint32_t mars_task_get_ticks(void); + +/** + * \ingroup group_mars_task + * \brief [MPU] Gets id of kernel that the task is being executed on. + * + * \note The kernel id refers to an index of the MPU it is being executed on and + * will range from 0 to (# of MPUs initiialized for MARS context) - 1. + * + * \return + * uint16_t - id of MARS kernel + */ +uint16_t mars_task_get_kernel_id(void); + +/** + * \ingroup group_mars_task + * \brief [MPU] Gets id of caller task. + * + * \return + * const struct mars_task_id * - pointer to task id in MPU storage + */ +const struct mars_task_id *mars_task_get_id(void); + +/** + * \ingroup group_mars_task + * \brief [MPU] Gets name of caller task. + * + * \return + * const char * - pointer to task name in MPU storage + */ +const char *mars_task_get_name(void); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task_barrier.h b/common/libspumars/include/spu/mars/task_barrier.h new file mode 100644 index 00000000..b30f2866 --- /dev/null +++ b/common/libspumars/include/spu/mars/task_barrier.h @@ -0,0 +1,117 @@ +#ifndef __MARS_TASK_BARRIER_H__ +#define __MARS_TASK_BARRIER_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_barrier + * \brief [MPU] Notifies a task barrier. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function notifies the barrier that the caller task has reached the + * synchronization point. Once a task reaches the synchronization point and + * notifies the barrier, it may handle other processing before calling the + * required \ref mars_task_barrier_wait. + * + * If all tasks from the previous barrier cycle have not reached the + * synchronization point and notified/waited on the barrier yet, the caller task + * will enter a waiting state until the previous barrier cycle is released. + * + * \param[in] barrier_ea - ea of initialized barrier instance + * \return + * MARS_SUCCESS - successfully notified barrier + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_LIMIT - maximum number of tasks already waiting + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_barrier_notify(uint64_t barrier_ea); + +/** + * \ingroup group_mars_task_barrier + * \brief [MPU] Notifies a task barrier. + * + * This function notifies the barrier that the caller task has reached the + * synchronization point. Once a task reaches the synchronization point and + * notifies the barrier, it may handle other processing before calling the + * required \ref mars_task_barrier_wait. + * + * If all tasks from the previous barrier cycle have not reached the + * synchronization point and notified the barrier yet, this function will + * return immediately with \ref MARS_ERROR_BUSY. + * + * \param[in] barrier_ea - ea of initialized barrier instance + * \return + * MARS_SUCCESS - successfully notified barrier + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_BUSY - previous waits have not completed + */ +int mars_task_barrier_try_notify(uint64_t barrier_ea); + +/** + * \ingroup group_mars_task_barrier + * \brief [MPU] Waits on a task barrier. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function should be called after the caller task has previously called + * \ref mars_task_barrier_notify. This function should be called when the task + * that reached the synchronization point is ready to wait for others to arrive + * at the synchronization point. + * + * If not all tasks associated with the barrier have reached the synchronization + * point and notified the barrier at the time of this call, the caller task will + * enter a waiting state until all notifications are received from the other + * tasks and the barrier is released. + * + * \param[in] barrier_ea - ea of initialized barrier instance + * \return + * MARS_SUCCESS - barrier is released + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_LIMIT - maximum number of tasks already waiting + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_barrier_wait(uint64_t barrier_ea); + +/** + * \ingroup group_mars_task_barrier + * \brief [MPU] Waits on a task barrier. + * + * This function should be called after the caller task has previously called + * \ref mars_task_barrier_notify. This function should be called when the task + * that reached the synchronization point is ready to wait for others to arrive + * at the synchronization point. + * + * If not all tasks associated with the barrier have reached the synchronization + * point and notified the barrier at the time of this call, this function will + * return immediately with \ref MARS_ERROR_BUSY. + * + * \param[in] barrier_ea - ea of initialized barrier instance + * \return + * MARS_SUCCESS - barrier is released + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not properly aligned + * \n MARS_ERROR_BUSY - not all notifications arrived yet + */ +int mars_task_barrier_try_wait(uint64_t barrier_ea); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task_event_flag.h b/common/libspumars/include/spu/mars/task_event_flag.h new file mode 100644 index 00000000..1e6ec743 --- /dev/null +++ b/common/libspumars/include/spu/mars/task_event_flag.h @@ -0,0 +1,158 @@ +#ifndef __MARS_TASK_EVENT_FLAG_H__ +#define __MARS_TASK_EVENT_FLAG_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_event_flag + * \brief [host/MPU] Clears the bits specified in the task event flag. + * + * This function will clear all bits currently set in the event flag. + * Tasks waiting on some events will remain in the waiting state. + * + * Key Parameters: + * \n \n + * \e bits + * - Specify only the bits you want to be cleared from the event flag bits. + * + * \param[in] event_flag_ea - ea of initialized event flag instance + * \param[in] bits - bits to clear + * \return + * MARS_SUCCESS - successfully cleared event flag bits + * \n MARS_ERROR_NULL - ea is 0\n + * \n MARS_ERROR_ALIGN - ea not aligned properly + */ +int mars_task_event_flag_clear(uint64_t event_flag_ea, uint32_t bits); + +/** + * \ingroup group_mars_task_event_flag + * \brief [host/MPU] Sets the bits specified in the task event flag. + * + * This function will set the bits specified. The bits are OR'd with bits + * already set in the event flag at the time of this call. + * If there are any tasks in the waiting state, and this call satisfies the + * release condition of those tasks, all those tasks will be returned to the + * ready state. + * + * Key Parameters: + * \n \n + * \e bits + * - Specify only the bits you want to set in the event flag bits. + * + * \param[in] event_flag_ea - ea of initialized event flag instance + * \param[in] bits - bits to set + * \return + * MARS_SUCCESS - successfully cleared event flag bits + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_STATE - invalid direction + */ +int mars_task_event_flag_set(uint64_t event_flag_ea, uint32_t bits); + +/** + * \ingroup group_mars_task_event_flag + * \brief [host/MPU] Waits on a task event flag. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This call will put the task into a waiting state until the specified event + * flag condition is met. + * + * Key Parameters: + * \n \n + * \e mask + * - Specify only the bits you want to test against in the event flag bits set. + * - Whether the test condition is satisfied or not will depend on \e mask_mode. + * + * \e mask_mode + * - Specify how to test the mask bits against the event flag bits set. + * - Specify \ref MARS_TASK_EVENT_FLAG_MASK_OR (\e mask | event flag bits), so + * the condition is satisfied if any bits specified in \e mask is set in the + * event flag bits. + * - Specify \ref MARS_TASK_EVENT_FLAG_MASK_AND (\e mask & event flag bits) so + * the condition is satisfied if all bits specified in \e mask are set in the + * event flag bits. + * + * \e bits + * - Specify a pointer to a variable where the event flag bits can be returned. + * - The resulting bits will be the state of bits in the event flag prior to any + * automatic clearing of bits (if \ref MARS_TASK_EVENT_FLAG_CLEAR_AUTO was + * specified at creation). + * - The returned bits are only valid when MARS_SUCCESS is returned. + * + * \param[in] event_flag_ea - ea of initialized event flag instance + * \param[in] mask - bit mask to test event flag bits against + * \param[in] mask_mode - specifies how to mask bits (AND, OR) + * \param[out] bits - pointer of instance to return bits state + * \return + * MARS_SUCCESS - successfully received event + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_PARAMS - invalid mask_mode + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_event_flag_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits); + +/** + * \ingroup group_mars_task_event_flag + * \brief [host/MPU] Waits on a task event flag. + * + * This call will test to see if the specified event flag condition is met + * returns immediately with \ref MARS_ERROR_BUSY if it did not. + * + * Key Parameters: + * \n \n + * \e mask + * - Specify only the bits you want to test against in the event flag bits set. + * - Whether the test condition is satisfied or not will depend on \e mask_mode. + * + * \e mask_mode + * - Specify how to test the mask bits against the event flag bits set. + * - Specify \ref MARS_TASK_EVENT_FLAG_MASK_OR (\e mask | event flag bits), so + * the condition is satisfied if any bits specified in \e mask is set in the + * event flag bits. + * - Specify \ref MARS_TASK_EVENT_FLAG_MASK_AND (\e mask & event flag bits) so + * the condition is satisfied if all bits specified in \e mask are set in the + * event flag bits. + * + * \e bits + * - Specify a pointer to a variable where the event flag bits can be returned. + * - The resulting bits will be the state of bits in the event flag prior to any + * automatic clearing of bits (if \ref MARS_TASK_EVENT_FLAG_CLEAR_AUTO was + * specified at creation). + * - The returned bits are only valid when MARS_SUCCESS is returned. + * + * \param[in] event_flag_ea - ea of initialized event flag instance + * \param[in] mask - bit mask to test event flag bits against + * \param[in] mask_mode - specifies how to mask bits (AND, OR) + * \param[out] bits - pointer of instance to return bits state + * \return + * MARS_SUCCESS - successfully received event + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_PARAMS - invalid mask_mode + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_BUSY - event not yet received + */ +int mars_task_event_flag_try_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task_queue.h b/common/libspumars/include/spu/mars/task_queue.h new file mode 100644 index 00000000..c2c251ca --- /dev/null +++ b/common/libspumars/include/spu/mars/task_queue.h @@ -0,0 +1,554 @@ +#ifndef __MARS_TASK_QUEUE_H__ +#define __MARS_TASK_QUEUE_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Returns the number of data items in the task queue. + * + * This function will return the total number of data items in the queue at the + * time of the call. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] count - pointer to variable to store return count + * \return + * MARS_SUCCESS - successfully returned count + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + */ +int mars_task_queue_count(uint64_t queue_ea, uint32_t *count); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Clears the data items in the task queue. + * + * This function will clear all data items currently in the queue. + * Entities waiting to pop data from the queue will remain waiting. + * Entities waiting to push data into the queue will resume. + * + * \param[in] queue_ea - ea of initialized queue instance + * \return + * MARS_SUCCESS - successfully cleared queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + */ +int mars_task_queue_clear(uint64_t queue_ea); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pushes the data specified into the task queue. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will push the data specified into the queue. + * The entity waiting longest to pop data from the queue can resume. + * + * If the queue is full at the time of this call, this function will cause the + * caller task to enter a waiting state until there is room in the queue to push + * the data. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to user data to copy into the queue. + * - The size of data should be equal to the size specified at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] data - address of data to be pushed into queue + * \return + * MARS_SUCCESS - successfully pushed data into queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_push(uint64_t queue_ea, const void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins push operation on a task queue. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will begin pushing the data specified into the queue. + * This only initiates the memory transfer of data into the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_push_end to guarantee the completion of the push. + * + * If the queue is full at the time of this call, this function will cause the + * caller task to enter a waiting state until there is room in the queue to push + * the data. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to user data to copy into the queue. + * - The size of data should be equal to the size specified at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \e tag + * - Specify a memory transfer tag value between 0-31. + * - Multiple push operations can be initiated concurrently, and each can be + * waited for independently if different memory tranfer tags are specified. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] data - address of data to be pushed into queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully pushed data into queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_push_begin(uint64_t queue_ea, const void *data, + uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Completes push operation on a task queue. + * + * This function will complete a push operation initiated with + * \ref mars_task_queue_push_begin or \ref mars_task_queue_try_push_begin. + * This function must be called in pair for each call to + * \ref mars_task_queue_push_begin or \ref mars_task_queue_try_push_begin to + * guarantee the completion of the initiated push operation. + * + * Key Parameters: + * \n \n + * \e tag + * - Specify the memory transfer tag specified at push operation initialization. + * - If multiple push operations were initiated concurrently, this call must + * wait for all memory transfers initiated with the same tag to complete. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully pushed data into queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_push_end(uint64_t queue_ea, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pushes the data specified into the task queue. + * + * This function will push the data specified into the queue. + * The entity waiting longest to pop data from the queue can resume. + * + * If the queue is full at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to user data to copy into the queue. + * - The size of data should be equal to the size specified at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] data - address of data to be pushed into queue + * \return + * MARS_SUCCESS - successfully pushed data into queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_BUSY - queue is full + * \n MARS_ERROR_STATE - invalid direction + */ +int mars_task_queue_try_push(uint64_t queue_ea, const void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins push operation on a task queue. + * + * This function will begin pushing the data specified into the queue. + * This only initiates the memory transfer of data into the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_push_end to guarantee the completion of the push. + * + * If the queue is full at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to user data to copy into the queue. + * - The size of data should be equal to the size specified at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \e tag + * - Specify a memory transfer tag value between 0-31. + * - Multiple push operations can be initiated concurrently, and each can be + * waited for independently if different memory tranfer tags are specified. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] data - address of data to be pushed into queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully pushed data into queue + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_BUSY - queue is full + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_try_push_begin(uint64_t queue_ea, const void *data, + uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pops data from a task queue. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will pop data from the queue. + * + * If the queue is empty at the time of this call, this function will cause the + * caller task to enter a waiting state until there is data in the queue to + * pop. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_pop(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins pop operation on a task queue. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will begin popping data from the queue. + * This only initiates the memory transfer of data from the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_pop_end to guarantee the completion of the pop. + * + * If the queue is empty at the time of this call, this function will cause the + * caller task to enter a waiting state until there is data in the queue to + * pop. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_pop_begin(uint64_t queue_ea, void *data, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Completes pop operation on a task queue. + * + * This function will complete a pop operation initiated with + * \ref mars_task_queue_pop_begin or \ref mars_task_queue_try_pop_begin. + * This function must be called in pair for each call to + * \ref mars_task_queue_pop_begin or \ref mars_task_queue_try_pop_begin to + * guarantee the completion of the initiated pop operation. + * + * Key Parameters: + * \n \n + * \e tag + * - Specify the memory transfer tag specified at pop operation initialization. + * - If multiple pop operations were initiated concurrently, this call must + * wait for all memory transfers initiated with the same tag to complete. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_pop_end(uint64_t queue_ea, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pops data from a task queue. + * + * This function will pop data from the queue. + * + * If the queue is empty at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address for data to be popped from queue + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_BUSY - queue is empty + * \n MARS_ERROR_STATE - invalid direction + */ +int mars_task_queue_try_pop(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins pop operation on a task queue. + * + * This function will begin popping data from the queue. + * This only initiates the memory transfer of data from the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_pop_end to guarantee the completion of the pop. + * + * If the queue is empty at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address for data to be popped from queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_BUSY - queue is empty + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_try_pop_begin(uint64_t queue_ea, void *data, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pops data from a task queue without removing it. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will retrieve data from the queue without removing it from the + * queue. + * + * If the queue is empty at the time of this call, this function will cause the + * caller task to enter a waiting state until there is data in the queue to + * be retrieved. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_peek(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins peek operation on a task queue. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will begin retriveing data from the queue without removing the + * data from the queue. + * This only initiates the memory transfer of data from the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_peek_end to guarantee the completion of the peek. + * + * If the queue is empty at the time of this call, this function will cause the + * caller task to enter a waiting state until there is data in the queue to + * be retrived. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_LIMIT - exceeded limit of max waiting tasks + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_queue_peek_begin(uint64_t queue_ea, void *data, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Completes peek operation on a task queue. + * + * This function will complete a peek operation initiated with + * \ref mars_task_queue_peek_begin or \ref mars_task_queue_try_peek_begin. + * This function must be called in pair for each call to + * \ref mars_task_queue_peek_begin or \ref mars_task_queue_try_peek_begin to + * guarantee the completion of the initiated peek operation. + * + * Key Parameters: + * \n \n + * \e tag + * - Specify the memory transfer tag specified at peek operation initialization. + * - If multiple peek operations were initiated concurrently, this call must + * wait for all memory transfers initiated with the same tag to complete. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_peek_end(uint64_t queue_ea, uint32_t tag); + +/** + * \ingroup group_mars_task_queue + * \brief [host/MPU] Pops data from a task queue without removing it. + * + * This function will retrieve data from the queue without removing it from the + * queue. + * + * If the queue is empty at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * . + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_BUSY - queue is empty + * \n MARS_ERROR_STATE - invalid direction + */ +int mars_task_queue_try_peek(uint64_t queue_ea, void *data); + +/** + * \ingroup group_mars_task_queue + * \brief [MPU] Begins peek operation on a task queue. + * + * This function will begin retriveing data from the queue without removing the + * data from the queue. + * This only initiates the memory transfer of data from the queue. + * This function must be completed with a matching call to + * \ref mars_task_queue_peek_end to guarantee the completion of the peek. + * + * If the queue is empty at the time of this call, this function will return + * immedately with \ref MARS_ERROR_BUSY. + * + * Key Parameters: + * \n \n + * \e data + * - Specify the pointer to some allocated memory to copy the popped data. + * - The size of the allocated memory area should be equal to the size specified + * at queue creation. + * - Note: In the Cell B.E. processor, data must be aligned to 16-bytes. + * + * \param[in] queue_ea - ea of initialized queue instance + * \param[out] data - address of data to be popped from queue + * \param[in] tag - tag identifier for memory transfer + * \return + * MARS_SUCCESS - successfully popped data from queue + * \n MARS_ERROR_NULL - ea or data is 0 + * \n MARS_ERROR_ALIGN - ea or data not aligned properly + * \n MARS_ERROR_BUSY - queue is empty + * \n MARS_ERROR_STATE - invalid direction + * \n MARS_ERROR_PARAMS - invalid tag + */ +int mars_task_queue_try_peek_begin(uint64_t queue_ea, void *data, uint32_t tag); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task_semaphore.h b/common/libspumars/include/spu/mars/task_semaphore.h new file mode 100644 index 00000000..526ba3b3 --- /dev/null +++ b/common/libspumars/include/spu/mars/task_semaphore.h @@ -0,0 +1,58 @@ +#ifndef __MARS_TASK_SEMAPHORE_H__ +#define __MARS_TASK_SEMAPHORE_H__ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_semaphore + * \brief [MPU] Acquires a task semaphore. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will attempt to acquire the semaphore. + * If the total number of current accesses of the semaphore is greater than or + * equal to the total allowed specified at semaphore creation, the caller task + * will enter a waiting state until some other tasks release the semaphore and + * becomes available for acquiring. + * + * \param[in] semaphore_ea - ea of initialized semaphore instance + * \return + * MARS_SUCCESS - successfully acquired semaphore + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + * \n MARS_ERROR_LIMIT - maximum number of tasks already waiting + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_semaphore_acquire(uint64_t semaphore_ea); + +/** + * \ingroup group_mars_task_semaphore + * \brief [MPU] Releases a task semaphore. + * + * This function will release a previously acquired semaphore. + * If their are other tasks currently waiting to acquire a semaphore, calling + * this function will resume a waiting task to allow it to acquire the + * semaphore. + * + * \param[in] semaphore_ea - ea of initialized semaphore instance + * \return + * MARS_SUCCESS - successfully released semaphore + * \n MARS_ERROR_NULL - ea is 0 + * \n MARS_ERROR_ALIGN - ea not aligned properly + */ +int mars_task_semaphore_release(uint64_t semaphore_ea); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/include/spu/mars/task_signal.h b/common/libspumars/include/spu/mars/task_signal.h new file mode 100644 index 00000000..9376c19a --- /dev/null +++ b/common/libspumars/include/spu/mars/task_signal.h @@ -0,0 +1,73 @@ +#ifndef __MARS_TASK_SIGNAL_H__ +#define __MARS_TASK_SIGNAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \ingroup group_mars_task_signal + * \brief [host/MPU] Sends a signal to the specified task. + * + * This function sends a signal to the task specified. If the task had + * previously called \ref mars_task_signal_wait and was in the waiting state, + * this function will cause that task to switch to a ready state and scheduled + * to run accordingly. If the task has not yet called + * \ref mars_task_signal_wait, the tasks's signal buffer will be set and the + * same order of events will occur as previously explained once + * \ref mars_task_signal_wait is called. The task signal buffer depth is 1. + * Therefore if the signal buffer is already set when a another signal is + * received, it has no effect. + * + * \param[in] id - pointer to task id of task to signal + * \return + * MARS_SUCCESS - successfully yielded task + * \n MARS_ERROR_NULL - null pointer specified + * \n MARS_ERROR_PARAMS - bad task id specified + * \n MARS_ERROR_STATE - task is in an invalid state + */ +int mars_task_signal_send(struct mars_task_id *id); + +/** + * \ingroup group_mars_task_signal + * \brief [MPU] Waits and yields caller task until receiving signal. + * (Task Switch Call) + * + * \note The [MPU] call may result in a task switch and put this + * task into the waiting state. Understand all the limitations before calling + * a Task Switch Call (See \ref sec_7_5). + * + * This function will cause the task to enter a waiting state until some other + * entity calls \ref mars_task_signal_send to this task to return it to the + * ready state. The task will not be scheduled to run until it receives the + * signal and returned to the ready state. Once the task receives the signal and + * this function returns MARS_SUCCESS, the signal buffer is cleared. + * + * \return + * MARS_SUCCESS - successfully yielded task + * \n MARS_ERROR_FORMAT - no context save area specified + */ +int mars_task_signal_wait(void); + +/** + * \ingroup group_mars_task_signal + * \brief [MPU] Waits for task until receiving signal. + * + * This function will check the state of a task to see if some other entity + * has called \ref mars_task_signal_send to this task and returns immediately + * with the result. Once the task receives the signal and this function returns + * MARS_SUCCESS, the signal buffer is cleared. + * + * \return + * MARS_SUCCESS - successfully yielded task + * \n MARS_ERROR_BUSY - signal not yet received + */ +int mars_task_signal_try_wait(void); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/ppu/Makefile b/common/libspumars/ppu/Makefile new file mode 100644 index 00000000..12e4a476 --- /dev/null +++ b/common/libspumars/ppu/Makefile @@ -0,0 +1,119 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +BUILD := build + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPS := $(BASEDIR)/deps +export LIBS := $(BASEDIR)/lib + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBS)/$(PLATFORM) +export DEPSDIR := $(DEPS)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +LIBRARY := $(LIBDIR)/libspumars + +KERNELMODULE := $(BASEDIR)/../spu/lib/mars_kernel.elf +TASKMODULE := $(BASEDIR)/../spu/lib/mars_task_module.elf + +#--------------------------------------------------------------------------------- +INCLUDES := -I$(BASEDIR) \ + -I$(BASEDIR)/../include/common \ + -I$(BASEDIR)/../include/ppu \ + -I$(BASEDIR)/../base/common \ + -I$(BASEDIR)/../task/common \ + -I$(BASEDIR)/../../../ppu/include + +CFLAGS := -O2 -mregnames -Wall -mcpu=cell $(MACHDEP) -DLIBSPUMARS_INTERNAL $(INCLUDES) -Wa,-mcell +ASFLAGS := $(MACHDEP) -mregnames -mcpu=cell -D__ASSEMBLY__ -Wa,-mcell $(INCLUDES) + +#--------------------------------------------------------------------------------- +VPATH := $(BASEDIR) \ + $(BASEDIR)/base/lib \ + $(BASEDIR)/task/lib + +#--------------------------------------------------------------------------------- +OBJS := alloc.o ea_cell.o workload_queue.o context.o \ + mpu_cell.o mutex_cell.o cond_cell.o callback_cell.o \ + host_mutex_psl1ght.o mars_kernel.o \ + task.o task_signal.o task_semaphore.o task_queue.o \ + task_event_flag.o task_barrier.o mars_task_module.o + +all: ppu + +#--------------------------------------------------------------------------------- +ppu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBS)/ppu ] || mkdir -p $(LIBS)/ppu + @[ -d $(DEPS)/ppu ] || mkdir -p $(DEPS)/ppu + @[ -d ppu ] || mkdir -p ppu + @$(MAKE) PLATFORM=ppu lib -C ppu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install-header: +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/ppu/include ] || mkdir -p $(PSL1GHT)/ppu/include + @cp -frv $(CURDIR)/../include/common/mars $(PSL1GHT)/ppu/include + @cp -frv $(CURDIR)/../include/ppu/mars $(PSL1GHT)/ppu/include + +#--------------------------------------------------------------------------------- +install: all install-header +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/ppu/lib ] || mkdir -p $(PSL1GHT)/ppu/lib + @cp -frv $(CURDIR)/lib/ppu/*.a $(PSL1GHT)/ppu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: $(OBJS) + +mars_kernel.c: $(KERNELMODULE) + @echo generating ... $(notdir $@) + @echo '__attribute__((aligned(128))) const unsigned char mars_kernel_entry[] = {' > $@.tmp + @od -v -A n -t x1 $(KERNELMODULE) | \ + sed -e '/^$$/d' -e 's/ */,0x/g' -e 's/^,//' -e 's/ *$$/,/' -e 's/,0x,$$//' >> $@.tmp + @echo '};' >> $@.tmp + @mv -f $@.tmp $@ + +mars_task_module.c: $(TASKMODULE) + @echo generating ... $(notdir $@) + @echo '__attribute__((aligned(128))) const unsigned char mars_task_module_entry[] = {' > $@.tmp + @od -v -A n -t x1 $(TASKMODULE) | \ + sed -e '/^$$/d' -e 's/ */,0x/g' -e 's/^,//' -e 's/ *$$/,/' -e 's/,0x,$$//' >> $@.tmp + @echo '};' >> $@.tmp + @mv -f $@.tmp $@ + +#--------------------------------------------------------------------------------- + +.PHONY: lib ppu install + +#--------------------------------------------------------------------------------- +lib: mars_kernel.c mars_task_module.c $(LIBRARY).a +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf ppu + @rm -rf $(DEPS) + @rm -rf $(LIBS) + +-include $(DEPSDIR)/*.d diff --git a/common/libspumars/ppu/base/lib/alloc.c b/common/libspumars/ppu/base/lib/alloc.c new file mode 100644 index 00000000..6e2f6520 --- /dev/null +++ b/common/libspumars/ppu/base/lib/alloc.c @@ -0,0 +1,18 @@ +#include + +#include + +void *mars_malloc(size_t size) +{ + return malloc(size); +} + +void *mars_realloc(void *ptr, size_t size) +{ + return realloc(ptr, size); +} + +void mars_free(void *ptr) +{ + free(ptr); +} diff --git a/common/libspumars/ppu/base/lib/callback_cell.c b/common/libspumars/ppu/base/lib/callback_cell.c new file mode 100644 index 00000000..a7a5c3af --- /dev/null +++ b/common/libspumars/ppu/base/lib/callback_cell.c @@ -0,0 +1,272 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "callback_internal_types.h" +#include "kernel_internal_types.h" +#include "workload_internal_types.h" + +#include "context_internal.h" + +static inline uint64_t get_workload_ea(uint64_t queue_ea, int workload_id) +{ + uint64_t context_ea = + mars_ea_get_uint64(queue_ea + + offsetof(struct mars_workload_queue_header, + context_ea)); + int context_index = + workload_id - (workload_id / MARS_WORKLOAD_PER_BLOCK) - 1; + + return context_ea + context_index * MARS_WORKLOAD_CONTEXT_SIZE; +} + +static void callback_process(struct mars_context *mars, uint16_t workload_id) +{ + uint64_t workload_callback_ea; + struct mars_workload_callback *workload_callback; + struct mars_callback_args out; + + /* busy loop until workload is put into wait state */ + while (!mars_workload_queue_query(mars, workload_id, + MARS_WORKLOAD_QUERY_IS_WAITING)) { + } + + /* get ea of workload callback structure */ + workload_callback_ea = + get_workload_ea(mars->workload_queue_ea, workload_id) + + MARS_WORKLOAD_MODULE_SIZE; + + /* prepare work area for queue */ + workload_callback = + mars_ea_work_area_get(workload_callback_ea, + MARS_WORKLOAD_CALLBACK_ALIGN, + MARS_WORKLOAD_CALLBACK_SIZE); + + /* get workload callback structure from ea */ + mars_ea_get(workload_callback_ea, workload_callback, + MARS_WORKLOAD_CALLBACK_SIZE); + + /* call the callback and store the return value */ + workload_callback->callback_ret = + ((mars_callback) + mars_ea_to_ptr(workload_callback->callback_ea)) + (&workload_callback->callback_args, &out); + + /* copy output args back into callback structure */ + workload_callback->callback_args = out; + + /* update workload data on ea */ + mars_ea_put(workload_callback_ea, workload_callback, + MARS_WORKLOAD_CALLBACK_SIZE); +} + +static int callback_queue_pop(uint64_t queue_ea, uint16_t *workload_id) +{ + struct mars_callback_queue *queue; + + /* prepare work area for queue */ + queue = mars_ea_work_area_get(queue_ea, + MARS_CALLBACK_QUEUE_ALIGN, + MARS_CALLBACK_QUEUE_SIZE); + + /* lock the queue */ + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + + /* queue is empty (false signal?) */ + if (!queue->count) { + mars_mutex_unlock(queue_ea); + return MARS_ERROR_STATE; + } + + /* get workload id from head of queue */ + *workload_id = queue->workload_id[queue->head]; + + /* decrement count */ + queue->count--; + + /* increment head */ + queue->head++; + + /* wrap head to front of queue if necessary */ + if (queue->head == MARS_CALLBACK_QUEUE_MAX) + queue->head = 0; + + /* if queue is empty reset the queue flag */ + if (!queue->count) + queue->flag = MARS_CALLBACK_QUEUE_FLAG_NONE; + + /* unlock the queue */ + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + return MARS_SUCCESS; +} + +static int callback_queue_state(uint32_t flag, void *param) +{ + (void)param; + + /* exit flag is set so return */ + switch (flag) { + case MARS_CALLBACK_QUEUE_FLAG_EXIT: + return MARS_ERROR_STATE; + case MARS_CALLBACK_QUEUE_FLAG_PUSH: + return MARS_SUCCESS; + default: + return -1; + } +} + +static void callback_handler_thread(void *arg) +{ + struct mars_context *mars = (struct mars_context *)arg; + uint64_t queue_ea = mars->callback_queue_ea; + uint16_t workload_id; + int ret; + + while (1) { + /* wait until kernel requests callback processing */ + ret = mars_ea_cond_wait( + queue_ea + offsetof(struct mars_callback_queue, flag), + callback_queue_state, NULL); + if (ret != MARS_SUCCESS) + break; + + /* pop the workload id requesting callback */ + ret = callback_queue_pop(queue_ea, &workload_id); + if (ret != MARS_SUCCESS) + continue; + + /* process the callback requested by workload */ + callback_process(mars, workload_id); + + /* signal the workload for completion of callback */ + mars_workload_queue_signal_send(mars, workload_id); + } + + sysThreadExit(0); +} + +int mars_callback_queue_create(struct mars_context *mars, uint32_t ppu_prio) +{ + int ret; + int i; + uint64_t queue_ea; + struct mars_callback_queue *queue; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (mars->callback_queue_ea) + return MARS_ERROR_STATE; + + /* allocate queue instance */ + queue_ea = mars_ea_memalign(MARS_CALLBACK_QUEUE_ALIGN, + MARS_CALLBACK_QUEUE_SIZE); + if (!queue_ea) + return MARS_ERROR_MEMORY; + + /* prepare work area for queue */ + queue = mars_ea_work_area_get(queue_ea, + MARS_CALLBACK_QUEUE_ALIGN, + MARS_CALLBACK_QUEUE_SIZE); + + /* initialize queue structure */ + queue->flag = MARS_CALLBACK_QUEUE_FLAG_NONE; + queue->count = 0; + queue->head = 0; + queue->tail = 0; + + for (i = 0; i < MARS_CALLBACK_QUEUE_MAX; i++) + queue->workload_id[i] = MARS_WORKLOAD_ID_NONE; + + /* update queue on EA */ + mars_ea_put(queue_ea, queue, MARS_CALLBACK_QUEUE_SIZE); + + /* reset mutex portion of queue header */ + mars_mutex_reset(queue_ea); + + /* sync EA */ + mars_ea_sync(); + + /* set the host callback queue instance in the mars context */ + mars->callback_queue_ea = queue_ea; + + /* create the host callback handler thread */ + ret = sysThreadCreate(&mars->callback_handler, callback_handler_thread, mars, ppu_prio, 4096, THREAD_JOINABLE, "mars_callback_handler"); + if (ret) { + mars_ea_free(queue_ea); + return MARS_ERROR_INTERNAL; + } + + return MARS_SUCCESS; +} + +int mars_callback_queue_destroy(struct mars_context *mars) +{ + int ret; + uint64_t ret_val; + uint64_t queue_ea; + struct mars_callback_queue *queue; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->callback_queue_ea) + return MARS_ERROR_PARAMS; + + queue_ea = mars->callback_queue_ea; + + /* prepare work area for queue */ + queue = mars_ea_work_area_get(mars->callback_queue_ea, + MARS_CALLBACK_QUEUE_ALIGN, + MARS_CALLBACK_QUEUE_SIZE); + + /* get queue from ea */ + mars_ea_get(queue_ea, queue, MARS_CALLBACK_QUEUE_SIZE); + + /* make sure queue is empty */ + if (queue->count) + return MARS_ERROR_STATE; + + /* join the host callback handler thread */ + ret = sysThreadJoin(mars->callback_handler, &ret_val); + if (ret) + return MARS_ERROR_INTERNAL; + + /* free host callback queue instance */ + mars_ea_free(queue_ea); + + /* set the workload queue to NULL for error checking */ + mars->callback_queue_ea = 0; + + return MARS_SUCCESS; +} + +int mars_callback_queue_exit(struct mars_context *mars) +{ + uint64_t queue_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->callback_queue_ea) + return MARS_ERROR_PARAMS; + + queue_ea = mars->callback_queue_ea; + + /* set callback queue exit flag */ + mars_ea_put_uint32( + queue_ea + offsetof(struct mars_callback_queue, flag), + MARS_CALLBACK_QUEUE_FLAG_EXIT); + + /* signal callback handler to wake up from wait */ + mars_ea_cond_signal( + queue_ea + offsetof(struct mars_callback_queue, flag), 1); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/base/lib/cond_cell.c b/common/libspumars/ppu/base/lib/cond_cell.c new file mode 100644 index 00000000..0bf8d6d3 --- /dev/null +++ b/common/libspumars/ppu/base/lib/cond_cell.c @@ -0,0 +1,58 @@ +#include +#include + +#include + +#include +#include + +#include +#include + +static sys_cond_t eaCond; +static sys_mutex_t eaCondMutex; + +static void __mars_ea_cond_init() __attribute__((constructor(105))); +static void __mars_ea_cond_init() +{ + sys_cond_attr_t cattr; + sys_mutex_attr_t mattr; + + sysCondAttrInitialize(cattr); + sysMutexAttrInitialize(mattr); + + sysMutexCreate(&eaCondMutex, &mattr); + sysCondCreate(&eaCond, eaCondMutex, &cattr); +} + +int mars_ea_cond_wait(uint64_t watch_point_ea, + int (*test_cond)(uint32_t , void *), + void *test_cond_param) +{ + volatile int ret; + + sysMutexLock(eaCondMutex, 0); + do { + volatile uint32_t val = (volatile uint32_t)mars_ea_get_uint32(watch_point_ea); + + ret = (volatile int)(*test_cond)(val, test_cond_param); + if (ret >= 0) + break; + + sysCondWait(eaCond, 0); + } while(ret < 0); + sysMutexUnlock(eaCondMutex); + + return ret; +} + +int mars_ea_cond_signal(uint64_t watch_point_ea, int broadcast) +{ + sysMutexLock(eaCondMutex, 0); + if(broadcast) + sysCondBroadcast(eaCond); + else + sysCondSignal(eaCond); + sysMutexUnlock(eaCondMutex); + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/base/lib/context.c b/common/libspumars/ppu/base/lib/context.c new file mode 100644 index 00000000..80d9a734 --- /dev/null +++ b/common/libspumars/ppu/base/lib/context.c @@ -0,0 +1,339 @@ +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "callback_internal_types.h" +#include "kernel_internal_types.h" +#include "workload_internal_types.h" + +#include "context_internal.h" + +uint32_t mars_get_ticks(void) +{ + return __mftb() & 0xffffffff; +} + +static void kernel_ticks_sync(uint64_t kernel_ticks_ea) +{ + uint64_t flag_ea = + kernel_ticks_ea + offsetof(struct mars_kernel_ticks, flag); + uint64_t offset_ea = + kernel_ticks_ea + offsetof(struct mars_kernel_ticks, offset); + + /* wait until kernel sets the sync begin flag */ + do { + } while (mars_ea_get_uint32(flag_ea) != + MARS_KERNEL_TICKS_FLAG_SYNC_BEGIN); + + mars_ea_sync(); + + mars_ea_put_uint32(offset_ea, mars_get_ticks()); + + mars_ea_sync(); + + /* set the sync end flag so kernel can finish sync */ + mars_ea_put_uint32(flag_ea, MARS_KERNEL_TICKS_FLAG_SYNC_END); +} + +static int kernel_params_init(struct mars_context *mars, uint64_t params_ea, + uint16_t kernel_id) +{ + struct mars_kernel_params *params = + mars_ea_work_area_get(params_ea, + MARS_KERNEL_PARAMS_ALIGN, + MARS_KERNEL_PARAMS_SIZE); + + if (!params) + return MARS_ERROR_MEMORY; + + /* zero kernel params */ + memset(params, 0, MARS_KERNEL_PARAMS_SIZE); + + params->kernel_id = kernel_id; + params->mars_context_ea = mars_ptr_to_ea(mars); + params->workload_queue_ea = mars->workload_queue_ea; + params->callback_queue_ea = mars->callback_queue_ea; + + /* update params on EA */ + mars_ea_put(params_ea, params, MARS_KERNEL_PARAMS_SIZE); + mars_ea_sync(); + + return MARS_SUCCESS; +} + +static int mpu_context_create(struct mars_context *mars, uint32_t num_mpus, uint32_t spu_prio, uint32_t ppu_prio) +{ + int ret; + uint16_t i; + mars_mpu_context_t *mpu = mars->mpu_context; + + mpu->num_spu = num_mpus; + mpu->spu_prio = spu_prio; + mpu->ppu_prio = ppu_prio; + + ret = mars_mpu_create(mpu, num_mpus, spu_prio, ppu_prio); + if(ret != MARS_SUCCESS) + return ret; + + /* create threads for mpu context */ + for (i = 0; i < num_mpus; i++) { + uint64_t params_ea = mars->kernel_params_ea + + MARS_KERNEL_PARAMS_SIZE * i; + + /* initialize kernel params for current mpu context */ + ret = kernel_params_init(mars, params_ea, i); + if (ret != MARS_SUCCESS) + return ret; + + /* run current mpu context */ + ret = mars_mpu_initialize(mpu, params_ea, i); + if (ret != MARS_SUCCESS) + return ret; + + /* increment mars context mpu context count */ + mars->mpu_context_count++; + } + mars_mpu_run(mpu); + + for(i = 0; i < num_mpus; i++) { + uint64_t params_ea = mars->kernel_params_ea + + MARS_KERNEL_PARAMS_SIZE * i; + /* sync kernel ticks for current mpu context */ + kernel_ticks_sync(params_ea + + offsetof(struct mars_kernel_params, kernel_ticks)); + } + + return MARS_SUCCESS; +} + +static int mpu_context_destroy(struct mars_context *mars) +{ + int ret; + + /* wait for mpu context */ + ret = mars_mpu_wait_all(mars->mpu_context); + if (ret != MARS_SUCCESS) + return ret; + + return MARS_SUCCESS; +} + +static int system_sanity_check(void) +{ + if ((MARS_CALLBACK_ARGS_SIZE != + sizeof(struct mars_callback_args)) || + (MARS_CALLBACK_QUEUE_SIZE != + sizeof(struct mars_callback_queue)) || + (MARS_KERNEL_PARAMS_SIZE != + sizeof(struct mars_kernel_params)) || + (MARS_MUTEX_SIZE != + sizeof(struct mars_mutex)) || + (MARS_WORKLOAD_CALLBACK_SIZE != + sizeof(struct mars_workload_callback)) || + (MARS_WORKLOAD_CONTEXT_SIZE != + sizeof(struct mars_workload_context)) || + (MARS_WORKLOAD_MODULE_SIZE != + sizeof(struct mars_workload_module)) || + (MARS_WORKLOAD_QUEUE_SIZE != + sizeof(struct mars_workload_queue)) || + (MARS_WORKLOAD_QUEUE_HEADER_SIZE != + sizeof(struct mars_workload_queue_header)) || + (MARS_WORKLOAD_QUEUE_BLOCK_SIZE != + sizeof(struct mars_workload_queue_block))) + return MARS_ERROR_INTERNAL; + + return MARS_SUCCESS; +} + +int mars_context_create(struct mars_context **mars_ret, uint32_t num_mpus, uint32_t spu_prio, uint32_t ppu_prio) +{ + int ret; + uint32_t num_mpus_max; + struct mars_context *mars = NULL; + + /* check function params */ + if (!mars_ret) + return MARS_ERROR_NULL; + + /* check number of mpus to use */ + ret = mars_mpu_max(&num_mpus_max); + if (ret != MARS_SUCCESS) + return ret; + if (!num_mpus_max) + return MARS_ERROR_LIMIT; + if (num_mpus > num_mpus_max) + return MARS_ERROR_PARAMS; + if (!num_mpus) + num_mpus = num_mpus_max; + + /* system sanity check */ + ret = system_sanity_check(); + if (ret != MARS_SUCCESS) + return ret; + + /* lock mutex */ + ret = mars_host_mutex_lock(&mars_shared_context_lock); + if (ret != MARS_SUCCESS) + return ret; + + /* allocate context */ + mars = mars_malloc(sizeof(struct mars_context)); + if (!mars) { + ret = MARS_ERROR_MEMORY; + goto error; + } + + /* zero context */ + memset(mars, 0, sizeof(struct mars_context)); + + /* increment reference count */ + mars->reference_count++; + + /* allocate kernel params */ + mars->kernel_params_ea = mars_ea_memalign( + MARS_KERNEL_PARAMS_ALIGN, + MARS_KERNEL_PARAMS_SIZE * num_mpus_max); + if (!mars->kernel_params_ea) { + ret = MARS_ERROR_MEMORY; + goto error_malloc_kernel_params; + } + + /* allocate mpu context thread array */ + mars->mpu_context = (mars_mpu_context_t *)mars_malloc(sizeof(mars_mpu_context_t)); + if (!mars->mpu_context) { + ret = MARS_ERROR_MEMORY; + goto error_malloc_mpu_context; + } + + /* create workload queue */ + ret = mars_workload_queue_create(mars); + if (ret != MARS_SUCCESS) + goto error_workload_queue_create; + + /* create callback queue */ + ret = mars_callback_queue_create(mars, ppu_prio); + if (ret != MARS_SUCCESS) + goto error_callback_queue_create; + + /* create mpu contexts */ + ret = mpu_context_create(mars, num_mpus, spu_prio, ppu_prio); + if (ret != MARS_SUCCESS) + goto error_mpu_context_create; + + /* return mars context pointer */ + *mars_ret = mars; + + /* unlock mutex */ + ret = mars_host_mutex_unlock(&mars_shared_context_lock); + if (ret != MARS_SUCCESS) + goto error_shared_context_unlock; + + return MARS_SUCCESS; + +error_shared_context_unlock: + mpu_context_destroy(mars); +error_mpu_context_create: + mars_callback_queue_exit(mars); + mars_callback_queue_destroy(mars); +error_callback_queue_create: + mars_workload_queue_exit(mars); + mars_workload_queue_destroy(mars); +error_workload_queue_create: + mars_free(mars->mpu_context); +error_malloc_mpu_context: + mars_ea_free(mars->kernel_params_ea); +error_malloc_kernel_params: + mars_free(mars); +error: + mars_host_mutex_unlock(&mars_shared_context_lock); + + return ret; +} + +int mars_context_destroy(struct mars_context *mars) +{ + int ret; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + + /* lock mutex */ + ret = mars_host_mutex_lock(&mars_shared_context_lock); + if (ret != MARS_SUCCESS) + return ret; + + /* decrement reference count */ + mars->reference_count--; + + /* reference count is not 0 so return */ + if (mars->reference_count) + goto done; + + /* shutdown the workload queue so mpu context threads exit */ + ret = mars_workload_queue_exit(mars); + if (ret != MARS_SUCCESS) + return ret; + + /* shutdown the callback queue so callback handler threads exit */ + ret = mars_callback_queue_exit(mars); + if (ret != MARS_SUCCESS) + return ret; + + /* destroy mpu contexts */ + if (mars->mpu_context_count) { + ret = mpu_context_destroy(mars); + if (ret != MARS_SUCCESS) + goto error; + } + + /* destroy callback queue */ + if (mars->callback_queue_ea) { + ret = mars_callback_queue_destroy(mars); + if (ret != MARS_SUCCESS) + goto error; + } + + /* destroy workload queue */ + if (mars->workload_queue_ea) { + ret = mars_workload_queue_destroy(mars); + if (ret != MARS_SUCCESS) + goto error; + } + + /* free allocated memory */ + mars_free(mars->mpu_context); + mars_ea_free(mars->kernel_params_ea); + mars_free(mars); + +done: + /* unlock mutex */ + ret = mars_host_mutex_unlock(&mars_shared_context_lock); + if (ret != MARS_SUCCESS) + return ret; + + return MARS_SUCCESS; + +error: + mars_host_mutex_unlock(&mars_shared_context_lock); + + return ret; +} + +uint32_t mars_context_get_num_mpus(struct mars_context *mars) +{ + /* check function params */ + if (!mars) + return 0; + + return mars->mpu_context_count; +} diff --git a/common/libspumars/ppu/base/lib/context_internal.h b/common/libspumars/ppu/base/lib/context_internal.h new file mode 100644 index 00000000..57b7746c --- /dev/null +++ b/common/libspumars/ppu/base/lib/context_internal.h @@ -0,0 +1,62 @@ +#ifndef __MARS_CONTEXT_INTERNAL_H__ +#define __MARS_CONTEXT_INTERNAL_H__ + +#include +#include +#include +#include +#include + +#define MARS_SHARED_CONTEXT_MAX 16 + +typedef struct { + uint32_t num_spu; + uint32_t spu_prio; + uint32_t ppu_prio; + sys_event_queue_t spu_ppu_event_queue; + sys_ppu_thread_t ppu_handler_thread; + sys_spu_group_t spu_thread_group; + sys_spu_thread_t *spu_threads; + sysSpuImage spu_image; +} mars_mpu_context_t; + +typedef sys_mutex_t mars_host_mutex_t; +typedef sys_ppu_thread_t mars_callback_t; + +struct mars_context { + /* parameters for the MARS kernel */ + uint64_t kernel_params_ea; + /* workload queue where workloads are added */ + uint64_t workload_queue_ea; + /* callback queue where host callback requests are added */ + uint64_t callback_queue_ea; + /* reference count */ + uint32_t reference_count; + /* num of mpu context threads */ + uint32_t mpu_context_count; + /* array of mpu contexts */ + mars_mpu_context_t *mpu_context; + /* callback handler */ + mars_callback_t callback_handler; +}; + +int mars_mpu_max(uint32_t *num); +int mars_mpu_run(mars_mpu_context_t *mpu); +int mars_mpu_initialize(mars_mpu_context_t *mpu, uint64_t params_ea, uint32_t idx); +int mars_mpu_create(mars_mpu_context_t *mpu, uint32_t num_mpus, uint32_t spu_prio, uint32_t ppu_prio); +int mars_mpu_wait_all(mars_mpu_context_t *mpu); + +int mars_workload_queue_create(struct mars_context *mars); +int mars_workload_queue_destroy(struct mars_context *mars); +int mars_workload_queue_exit(struct mars_context *mars); + +int mars_callback_queue_create(struct mars_context *mars, uint32_t ppu_prio); +int mars_callback_queue_destroy(struct mars_context *mars); +int mars_callback_queue_exit(struct mars_context *mars); + +int mars_host_mutex_lock(mars_host_mutex_t *mutex); +int mars_host_mutex_unlock(mars_host_mutex_t *mutex); + +extern mars_host_mutex_t mars_shared_context_lock; + +#endif diff --git a/common/libspumars/ppu/base/lib/ea_cell.c b/common/libspumars/ppu/base/lib/ea_cell.c new file mode 100644 index 00000000..9c591186 --- /dev/null +++ b/common/libspumars/ppu/base/lib/ea_cell.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include + +#include + +#include "numa_internal.h" + +/* These functions must not be called */ +static uint64_t numa_ea_memalign(size_t boundary, size_t size) +{ + (void)boundary; + (void)size; + + return 0; +} + +static void numa_ea_free(uint64_t ea) +{ + (void)ea; +} + +uint64_t mars_ea_memalign(size_t boundary, size_t size) +{ + if (mars_numa_enabled()) + return numa_ea_memalign(boundary, size); + else + return mars_ptr_to_ea(memalign(boundary, size)); +} + +void mars_ea_free(uint64_t ea) +{ + if (mars_numa_enabled()) + numa_ea_free(ea); + else + free(mars_ea_to_ptr(ea)); +} + +/* copy data from EA to host */ +void mars_ea_get(uint64_t ea, void *mem, size_t size) +{ + const void *src = mars_ea_to_ptr(ea); + if (src != mem) + memcpy(mem, src, size); +} + +/* get uint8 value from EA */ +uint8_t mars_ea_get_uint8(uint64_t ea) +{ + return *(uint8_t *)mars_ea_to_ptr(ea); +} + +/* get uint16 value from EA */ +uint16_t mars_ea_get_uint16(uint64_t ea) +{ + return *(uint16_t *)mars_ea_to_ptr(ea); +} + +/* get uint32 value from EA */ +uint32_t mars_ea_get_uint32(uint64_t ea) +{ + return *(uint32_t *)mars_ea_to_ptr(ea); +} + +/* get uint64 value from EA */ +uint64_t mars_ea_get_uint64(uint64_t ea) +{ + return *(uint64_t *)mars_ea_to_ptr(ea); +} + +/* copy data from host to EA */ +void mars_ea_put(uint64_t ea, const void *mem, size_t size) +{ + void *dst = mars_ea_to_ptr(ea); + if (dst != mem) + memcpy(dst, mem, size); +} + +/* put uint8 value to EA */ +void mars_ea_put_uint8(uint64_t ea, uint8_t value) +{ + *(uint8_t *)mars_ea_to_ptr(ea) = value; +} + +/* put uint16 value to EA */ +void mars_ea_put_uint16(uint64_t ea, uint16_t value) +{ + *(uint16_t *)mars_ea_to_ptr(ea) = value; +} + +/* put uint32 value to EA */ +void mars_ea_put_uint32(uint64_t ea, uint32_t value) +{ + *(uint32_t *)mars_ea_to_ptr(ea) = value; +} + +/* put uint64 value to EA */ +void mars_ea_put_uint64(uint64_t ea, uint64_t value) +{ + *(uint64_t *)mars_ea_to_ptr(ea) = value; +} + +/* map readonly area on host memory to EA */ +uint64_t mars_ea_map(void *ptr, size_t size) +{ +#ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY + uint64_t copy_ea; + + copy_ea = mars_ea_memalign(16, size); /* FIXME: 16 -> any macro */ + if (!copy_ea) + return 0; + + mars_ea_put(copy_ea, ptr, size); + mars_ea_sync(); + + return copy_ea; +#else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + (void)size; + return mars_ptr_to_ea(ptr); +#endif /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ +} + +/* unmap area mapped by mars_ea_map */ +void mars_ea_unmap(uint64_t ea, size_t size) +{ + (void)size; + +#ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY + mars_ea_free(ea); +#else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + (void)ea; +#endif /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ +} + +/* sync EA */ +void mars_ea_sync(void) +{ + __lwsync(); +} diff --git a/common/libspumars/ppu/base/lib/elf.h b/common/libspumars/ppu/base/lib/elf.h new file mode 100644 index 00000000..b54dfc68 --- /dev/null +++ b/common/libspumars/ppu/base/lib/elf.h @@ -0,0 +1,2459 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef __ELF_H__ +#define __ELF_H__ + +//#include + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 10 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + long int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +/* Keep this the last entry. */ +#define R_68K_NUM 23 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +/* Keep this the last entry. */ +#define R_SPARC_NUM 80 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ +#define HWCAP_SPARC_ULTRA3 32 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +/* Keep this the last entry. */ +#define R_MIPS_NUM 38 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +#define DT_MIPS_NUM 0x32 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* Keep this the last entry. */ +#define R_PPC_NUM 95 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* Keep this the last entry. */ +#define R_PPC64_NUM 107 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ + +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ + +#define R_X86_64_NUM 24 + +#endif /* elf.h */ diff --git a/common/libspumars/ppu/base/lib/host_mutex_psl1ght.c b/common/libspumars/ppu/base/lib/host_mutex_psl1ght.c new file mode 100644 index 00000000..dae7b1e2 --- /dev/null +++ b/common/libspumars/ppu/base/lib/host_mutex_psl1ght.c @@ -0,0 +1,39 @@ +#include <_ansi.h> +#include <_syslist.h> +#include +#include + +#include + +#include + +#include "context_internal.h" + +sys_mutex_t mars_shared_context_lock; + +static void __mars_shared_context_lock_init() __attribute__((constructor(105))); +static void __mars_shared_context_lock_init() +{ + sys_mutex_attr_t attr; + + sysMutexAttrInitialize(attr); + sysMutexCreate(&mars_shared_context_lock, &attr); +} + +int mars_host_mutex_lock(mars_host_mutex_t *mutex) +{ + int ret = sysMutexLock(*mutex, 0); + if(ret) + return MARS_ERROR_INTERNAL; + + return MARS_SUCCESS; +} + +int mars_host_mutex_unlock(mars_host_mutex_t *mutex) +{ + int ret = sysMutexUnlock(*mutex); + if(ret) + return MARS_ERROR_INTERNAL; + + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/base/lib/mpu_cell.c b/common/libspumars/ppu/base/lib/mpu_cell.c new file mode 100644 index 00000000..5db45d0b --- /dev/null +++ b/common/libspumars/ppu/base/lib/mpu_cell.c @@ -0,0 +1,163 @@ +#include + +#include +#include +#include + +#include +#include + +#include "context_internal.h" +#include "workload_internal_types.h" +#include "kernel_internal_types.h" +#include "numa_internal.h" + +#define NUM_OF_SPU 6 + +extern const unsigned char mars_kernel_entry[]; + +/* This function must not be called */ +static int numa_mpu_max(void) +{ + return -1; +} + +static void mpu_mars_handler_entry(void *arg) +{ + int ret; + mars_mpu_context_t *mpu = (mars_mpu_context_t*)arg; + + for(;;) { + uint64_t ea; + sys_event_t event; + + ret = sysEventQueueReceive(mpu->spu_ppu_event_queue, &event, 0); + if(ret != 0) + sysThreadExit(-1); + + ea = ((uint64_t)(event.data_2&0x00ffffff)<<32)|event.data_3; + if(ea == MARS_HOST_SIGNAL_EXIT) + break; + + mars_ea_cond_signal(ea, 1); + } + sysThreadExit(0); +} + + +int mars_mpu_max(uint32_t *num) +{ + int mpu_max; + + if (mars_numa_enabled()) + mpu_max = numa_mpu_max(); + else + mpu_max = NUM_OF_SPU; + + if (mpu_max < 0) + return MARS_ERROR_INTERNAL; + + *num = mpu_max; + + return MARS_SUCCESS; +} + +int mars_mpu_create(mars_mpu_context_t *mpu, uint32_t num_mpus, uint32_t spu_prio, uint32_t ppu_prio) +{ + int ret; + sysSpuThreadGroupAttribute attr; + sys_event_queue_attr_t event_queue_attr = { SYS_EVENT_QUEUE_PRIO, SYS_EVENT_QUEUE_PPU, "" }; + + sysSpuThreadGroupAttributeInitialize(attr); + + mpu->spu_threads = (sys_spu_thread_t*)mars_malloc(sizeof(sys_spu_thread_t)*num_mpus); + if(!mpu->spu_threads) + return MARS_ERROR_MEMORY; + + ret = sysSpuImageImport(&mpu->spu_image,mars_kernel_entry,SPU_IMAGE_PROTECT); + if(ret) + goto error_kernel_image_import; + + ret = sysSpuThreadGroupCreate(&mpu->spu_thread_group, num_mpus, spu_prio, &attr); + if(ret) + goto error_thread_group_create; + + ret = sysEventQueueCreate(&mpu->spu_ppu_event_queue, &event_queue_attr, SYS_EVENT_QUEUE_KEY_LOCAL, 127); + if(ret) + goto error_event_queue_create; + + ret = sysThreadCreate(&mpu->ppu_handler_thread, mpu_mars_handler_entry, mpu, ppu_prio, 4096, THREAD_JOINABLE, "mpu_mars_handler"); + if(ret) + goto error_ppu_thread_create; + + return MARS_SUCCESS; + +error_ppu_thread_create: + sysEventQueueDestroy(mpu->spu_ppu_event_queue, 0); +error_event_queue_create: + sysSpuThreadGroupDestroy(mpu->spu_thread_group); +error_thread_group_create: + sysSpuImageClose(&mpu->spu_image); +error_kernel_image_import: + free(mpu->spu_threads); + return MARS_ERROR_INTERNAL; +} + +int mars_mpu_run(mars_mpu_context_t *mpu) +{ + return sysSpuThreadGroupStart(mpu->spu_thread_group); +} + +int mars_mpu_initialize(mars_mpu_context_t *mpu, uint64_t params_ea, uint32_t idx) +{ + int ret; + sysSpuThreadArgument arg; + sysSpuThreadAttribute attr; + + sysSpuThreadArgumentInitialize(arg); + sysSpuThreadAttributeInitialize(attr); + + arg.arg0 = params_ea; + ret = sysSpuThreadInitialize(&mpu->spu_threads[idx],mpu->spu_thread_group,idx,&mpu->spu_image,&attr,&arg); + if(ret) { + return MARS_ERROR_INTERNAL; + } + + ret = sysSpuThreadConnectEvent(mpu->spu_threads[idx],mpu->spu_ppu_event_queue,SPU_THREAD_EVENT_USER,MARS_KERNEL_SPU_EVENT_PORT); + if(ret) { + return MARS_ERROR_INTERNAL; + } + sysSpuPrintfAttachThread(mpu->spu_threads[idx]); + + return MARS_SUCCESS; +} + +int mars_mpu_wait_all(mars_mpu_context_t *mpu) +{ + int ret, i; + u64 ret_val; + u32 status, cause; + + for(i=0;i < mpu->num_spu;i++) { + sysSpuPrintfDetachThread(mpu->spu_threads[i]); + } + + ret = sysThreadJoin(mpu->ppu_handler_thread, &ret_val); + if(ret || ret_val) + return MARS_ERROR_INTERNAL; + + ret = sysSpuThreadGroupJoin(mpu->spu_thread_group, &cause, &status); + if(ret) + return MARS_ERROR_INTERNAL; + + ret = sysSpuThreadGroupDestroy(mpu->spu_thread_group); + if(ret) + return MARS_ERROR_INTERNAL; + + ret = sysSpuImageClose(&mpu->spu_image); + if(ret) + return MARS_ERROR_INTERNAL; + + free(mpu->spu_threads); + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/base/lib/mutex_cell.c b/common/libspumars/ppu/base/lib/mutex_cell.c new file mode 100644 index 00000000..c4a0bd92 --- /dev/null +++ b/common/libspumars/ppu/base/lib/mutex_cell.c @@ -0,0 +1,159 @@ +#include +#include + +#include + +#include +#include +#include + +union mars_mutex_header { + struct mars_mutex_status status; + uint32_t bits; +}; + +static void init_status(struct mars_mutex_status *status) +{ + status->lock = MARS_MUTEX_UNLOCKED; + status->current_id = 0; + status->next_id = 0; +} + + +int mars_mutex_create(uint64_t *mutex_ea_ret) +{ + struct mars_mutex *mutex; + uint64_t mutex_ea; + + if (!mutex_ea_ret) + return MARS_ERROR_NULL; + + mutex_ea = mars_ea_memalign(MARS_MUTEX_ALIGN, MARS_MUTEX_SIZE); + if (!mutex_ea) + return MARS_ERROR_MEMORY; + + mutex = mars_ea_to_ptr(mutex_ea); + + init_status(&mutex->status); + __lwsync(); + + *mutex_ea_ret = mutex_ea; + + return MARS_SUCCESS; +} + +int mars_mutex_destroy(uint64_t mutex_ea) +{ + if (!mutex_ea) + return MARS_ERROR_NULL; + + mars_ea_free(mutex_ea); + + return MARS_SUCCESS; +} + +int mars_mutex_reset(uint64_t mutex_ea) +{ + struct mars_mutex *mutex = mars_ea_to_ptr(mutex_ea); + + if (!mutex_ea) + return MARS_ERROR_NULL; + + init_status(&mutex->status); + __lwsync(); + + return MARS_SUCCESS; +} + +int mars_mutex_lock(uint64_t mutex_ea) +{ + struct mars_mutex *mutex = mars_ea_to_ptr(mutex_ea); + union mars_mutex_header header; + uint8_t id; + int retry; + + if (!mutex_ea) + return MARS_ERROR_NULL; + + do { + header.bits = __lwarx(&mutex->status); + + /* get my id */ + id = header.status.next_id++; + if ((retry = !__stwcx(&mutex->status, header.bits))) + sysThreadYield(); //sched_yield(); + } while (retry); + + do { + header.bits = __lwarx(&mutex->status); + + if (header.status.lock == MARS_MUTEX_LOCKED || + header.status.current_id != id) { + /* wait until mutex is released */ + sysThreadYield(); //sched_yield(); + retry = 1; + } + else { + /* get lock */ + header.status.lock = MARS_MUTEX_LOCKED; + header.status.current_id++; + retry = !__stwcx(&mutex->status, header.bits); + } + } while (retry); + + __isync(); + + return MARS_SUCCESS; +} + +int mars_mutex_unlock(uint64_t mutex_ea) +{ + struct mars_mutex *mutex = mars_ea_to_ptr(mutex_ea); + union mars_mutex_header header; + + if (!mutex_ea) + return MARS_ERROR_NULL; + if (mutex->status.lock != MARS_MUTEX_LOCKED) + return MARS_ERROR_STATE; + + __lwsync(); + + do { + header.bits = __lwarx(&mutex->status); + header.status.lock = MARS_MUTEX_UNLOCKED; + } while (!__stwcx(&mutex->status, header.bits)); + + return MARS_SUCCESS; +} + +int mars_mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex) +{ +#ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY + int ret; + ret = mars_mutex_lock(mutex_ea); + if (ret != MARS_SUCCESS) + return ret; + mars_ea_get(mutex_ea, mutex, MARS_MUTEX_SIZE); + return MARS_SUCCESS; +#else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + (void)mutex; /* ignored */ + return mars_mutex_lock(mutex_ea); +#endif /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ +} + +int mars_mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex) +{ +#ifdef MARS_ENABLE_DISCRETE_SHARED_MEMORY + int ret; + mars_ea_put( + mutex_ea + offsetof(struct mars_mutex, pad), + mutex->pad, sizeof(mutex->pad)); + ret = mars_mutex_unlock(mutex_ea); + if (ret == MARS_SUCCESS) + mutex->status.lock = MARS_MUTEX_UNLOCKED; + return ret; +#else /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ + (void)mutex; /* ignored */ + return mars_mutex_unlock(mutex_ea); +#endif /* !MARS_ENABLE_DISCRETE_SHARED_MEMORY */ +} diff --git a/common/libspumars/ppu/base/lib/numa_internal.h b/common/libspumars/ppu/base/lib/numa_internal.h new file mode 100644 index 00000000..42bbec27 --- /dev/null +++ b/common/libspumars/ppu/base/lib/numa_internal.h @@ -0,0 +1,9 @@ +#ifndef __MARS_NUMA_INTERNAL_H__ +#define __MARS_NUMA_INTERNAL_H__ + +static inline int mars_numa_enabled(void) +{ + return 0; +} + +#endif diff --git a/common/libspumars/ppu/base/lib/workload_queue.c b/common/libspumars/ppu/base/lib/workload_queue.c new file mode 100644 index 00000000..647e93ed --- /dev/null +++ b/common/libspumars/ppu/base/lib/workload_queue.c @@ -0,0 +1,878 @@ +#include + +#include +#include +#include +#include + +#include "elf.h" +#include "context_internal.h" +#include "kernel_internal_types.h" +#include "workload_internal_types.h" + +static inline uint64_t get_workload_ea(uint64_t queue_ea, uint16_t workload_id) +{ + uint64_t context_ea = + mars_ea_get_uint64(queue_ea + + offsetof(struct mars_workload_queue_header, + context_ea)); + int context_index = + workload_id - (workload_id / MARS_WORKLOAD_PER_BLOCK) - 1; + + return context_ea + context_index * MARS_WORKLOAD_CONTEXT_SIZE; +} + +static inline uint64_t get_block_ea(uint64_t queue_ea, int block) +{ + return queue_ea + + offsetof(struct mars_workload_queue, block) + + MARS_WORKLOAD_QUEUE_BLOCK_SIZE * block; +} + +static inline uint64_t get_block_bits_ea(uint64_t block_ea, int index) +{ + return block_ea + + offsetof(struct mars_workload_queue_block, bits) + + sizeof(uint64_t) * index; +} + +static int change_bits(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea, + int (*check_bits)(uint64_t bits, uint64_t param), + uint64_t check_bits_param, + uint64_t (*set_bits)(uint64_t bits, uint64_t param), + uint64_t set_bits_param, + void (*callback)(struct mars_context *mars, uint16_t id)) +{ + int block; + int index; + uint64_t queue_ea; + uint64_t block_ea; + uint64_t bits_ea; + uint64_t bits; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->workload_queue_ea) + return MARS_ERROR_PARAMS; + if (id > MARS_WORKLOAD_ID_MAX || !(id % MARS_WORKLOAD_PER_BLOCK)) + return MARS_ERROR_PARAMS; + + queue_ea = mars->workload_queue_ea; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* prepare work area for queue block */ + block_ea = get_block_ea(queue_ea, block); + + mars_mutex_lock(block_ea); + + /* get bits from workload queue block */ + bits_ea = get_block_bits_ea(block_ea, index); + bits = mars_ea_get_uint64(bits_ea); + + /* check for valid state */ + if (!(*check_bits)(bits, check_bits_param)) { + mars_mutex_unlock(block_ea); + return MARS_ERROR_STATE; + } + + /* reset workload queue bits and set state to new state */ + bits = (*set_bits)(bits, set_bits_param); + + /* store new bits into queue block */ + mars_ea_put_uint64(bits_ea, bits); + + /* if callback requested call it */ + if (callback) + (*callback)(mars, id); + + mars_mutex_unlock(block_ea); + + /* if requested set workload context pointer to return */ + if (workload_ea) + *workload_ea = get_workload_ea(queue_ea, id); + + return MARS_SUCCESS; +} + +static int check_state_bits(uint64_t bits, uint64_t state) +{ + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == state); +} + +static int check_state_bits_not(uint64_t bits, uint64_t state) +{ + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) != state); +} + +static uint64_t set_state_bits(uint64_t bits, uint64_t state) +{ + MARS_BITS_SET(&bits, WORKLOAD_STATE, state); + + return bits; +} + +static int change_state( + struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea, + unsigned int old_state, + unsigned int new_state, + void (*callback)(struct mars_context *mars, uint16_t id)) +{ + return change_bits(mars, id, workload_ea, + check_state_bits, old_state, + set_state_bits, new_state, + callback); +} + +static void init_header(uint64_t queue_ea) +{ + int block; + uint16_t bits = 0; + struct mars_workload_queue *queue; + + /* prepare work area for queue header */ + queue = mars_ea_work_area_get(queue_ea, + MARS_WORKLOAD_QUEUE_HEADER_ALIGN, + MARS_WORKLOAD_QUEUE_HEADER_SIZE); + + /* initialize workload queue header */ + queue->header.flag = MARS_WORKLOAD_QUEUE_FLAG_NONE; + queue->header.queue_ea = queue_ea; + queue->header.context_ea = + queue_ea + offsetof(struct mars_workload_queue, context); + + /* create initial bit pattern of workload queue header */ + MARS_BITS_SET(&bits, BLOCK_PRIORITY, MARS_WORKLOAD_BLOCK_PRIORITY_MIN); + MARS_BITS_SET(&bits, BLOCK_COUNTER, MARS_WORKLOAD_BLOCK_COUNTER_MAX); + MARS_BITS_SET(&bits, BLOCK_READY, MARS_WORKLOAD_BLOCK_READY_OFF); + MARS_BITS_SET(&bits, BLOCK_WAITING, MARS_WORKLOAD_BLOCK_WAITING_OFF); + + for (block = 0; block < MARS_WORKLOAD_NUM_BLOCKS; block++) + queue->header.bits[block] = bits; + + /* update queue header on EA */ + mars_ea_put(queue_ea, queue, MARS_WORKLOAD_QUEUE_HEADER_SIZE); + + /* reset mutex portion of queue header */ + mars_mutex_reset(queue_ea); +} + +static void init_block(uint64_t block_ea, uint64_t initial_bits) +{ + int index; + struct mars_workload_queue_block *block = + mars_ea_work_area_get(block_ea, + MARS_WORKLOAD_QUEUE_BLOCK_ALIGN, + MARS_WORKLOAD_QUEUE_BLOCK_SIZE); + + for (index = 1; index < MARS_WORKLOAD_PER_BLOCK; index++) + block->bits[index] = initial_bits; + + /* update queue block on EA */ + mars_ea_put(block_ea, block, MARS_WORKLOAD_QUEUE_BLOCK_SIZE); + + /* reset mutex portion of queue block */ + mars_mutex_reset(block_ea); +} + +static void init_blocks(uint64_t queue_ea) +{ + int block; + uint64_t bits = 0; + + /* create initial bit pattern of workload queue blocks */ + MARS_BITS_SET(&bits, WORKLOAD_STATE, MARS_WORKLOAD_STATE_NONE); + + /* other bits are set by mars_workload_queue_schedule_begin properly */ + + /* initialize workload queue blocks */ + for (block = 0; block < MARS_WORKLOAD_NUM_BLOCKS; block++) { + uint64_t block_ea = get_block_ea(queue_ea, block); + + init_block(block_ea, bits); + } +} + +int mars_workload_queue_create(struct mars_context *mars) +{ + uint64_t queue_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (mars->workload_queue_ea) + return MARS_ERROR_STATE; + + /* allocate workload instance */ + queue_ea = mars_ea_memalign(MARS_WORKLOAD_QUEUE_ALIGN, + MARS_WORKLOAD_QUEUE_SIZE); + if (!queue_ea) + return MARS_ERROR_MEMORY; + + /* initialize workload queue header */ + init_header(queue_ea); + + /* initialize workload queue blocks */ + init_blocks(queue_ea); + + /* sync EA */ + mars_ea_sync(); + + /* set the workload queue instance in the mars context */ + mars->workload_queue_ea = queue_ea; + + return MARS_SUCCESS; +} + +static int is_block_empty(uint64_t block_ea) +{ + int index; + struct mars_workload_queue_block *block = + mars_ea_work_area_get(block_ea, + MARS_WORKLOAD_QUEUE_BLOCK_ALIGN, + MARS_WORKLOAD_QUEUE_BLOCK_SIZE); + + /* get the workload queue block from shared memory */ + mars_ea_get(block_ea, block, sizeof(struct mars_workload_queue_block)); + + /* check status */ + for (index = 1; index < MARS_WORKLOAD_PER_BLOCK; index++) { + if (MARS_BITS_GET(&block->bits[index], WORKLOAD_STATE) != + MARS_WORKLOAD_STATE_NONE) + return MARS_ERROR_STATE; + } + + return MARS_SUCCESS; +} + +int mars_workload_queue_destroy(struct mars_context *mars) +{ + int block; + uint64_t queue_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->workload_queue_ea) + return MARS_ERROR_PARAMS; + + queue_ea = mars->workload_queue_ea; + + /* check for any workloads left in workload queue */ + for (block = 0; block < MARS_WORKLOAD_NUM_BLOCKS; block++) { + uint64_t block_ea = get_block_ea(queue_ea, block); + int ret = is_block_empty(block_ea); + if (ret != MARS_SUCCESS) + return ret; + } + + /* free workload queue instance */ + mars_ea_free(queue_ea); + + /* set the workload queue to NULL for error checking */ + mars->workload_queue_ea = 0; + + return MARS_SUCCESS; +} + +int mars_workload_queue_exit(struct mars_context *mars) +{ + uint64_t queue_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->workload_queue_ea) + return MARS_ERROR_PARAMS; + + queue_ea = mars->workload_queue_ea; + + mars_mutex_lock(queue_ea); + + mars_ea_put_uint32(queue_ea + + offsetof(struct mars_workload_queue_header, flag), + MARS_WORKLOAD_QUEUE_FLAG_EXIT); + + mars_mutex_unlock(queue_ea); + + return MARS_SUCCESS; +} + +int mars_workload_queue_query(struct mars_context *mars, + uint16_t id, + int query) +{ + int block; + int index; + uint64_t queue_ea; + uint64_t block_ea; + uint64_t bits_ea; + uint64_t bits; + + /* check function params */ + if (!mars) + return 0; + if (!mars->workload_queue_ea) + return 0; + if (id > MARS_WORKLOAD_ID_MAX || !(id % MARS_WORKLOAD_PER_BLOCK)) + return 0; + + queue_ea = mars->workload_queue_ea; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* prepare work area for queue block */ + block_ea = get_block_ea(queue_ea, block); + + mars_mutex_lock(block_ea); + + /* get bits from workload queue block */ + bits_ea = get_block_bits_ea(block_ea, index); + bits = mars_ea_get_uint64(bits_ea); + + mars_mutex_unlock(block_ea); + + switch (query) { + case MARS_WORKLOAD_QUERY_IS_INITIALIZED: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) != + MARS_WORKLOAD_STATE_NONE); + case MARS_WORKLOAD_QUERY_IS_READY: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == + MARS_WORKLOAD_STATE_READY); + case MARS_WORKLOAD_QUERY_IS_WAITING: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == + MARS_WORKLOAD_STATE_WAITING); + case MARS_WORKLOAD_QUERY_IS_RUNNING: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == + MARS_WORKLOAD_STATE_RUNNING); + case MARS_WORKLOAD_QUERY_IS_FINISHED: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == + MARS_WORKLOAD_STATE_FINISHED); + case MARS_WORKLOAD_QUERY_IS_SIGNAL_SET: + return (MARS_BITS_GET(&bits, WORKLOAD_SIGNAL) == + MARS_WORKLOAD_SIGNAL_ON); + } + + return 0; +} + +static int alloc_block(uint64_t block_ea) +{ + int ret = -1; + int index; + struct mars_workload_queue_block *block = + mars_ea_work_area_get(block_ea, + MARS_WORKLOAD_QUEUE_BLOCK_ALIGN, + MARS_WORKLOAD_QUEUE_BLOCK_SIZE); + + mars_mutex_lock(block_ea); + + /* get the workload queue block from shared memory */ + mars_ea_get(block_ea, block, MARS_WORKLOAD_QUEUE_BLOCK_SIZE); + + /* check status */ + for (index = 1; index < MARS_WORKLOAD_PER_BLOCK; index++) { + uint64_t bits = block->bits[index]; + if (MARS_BITS_GET(&bits, WORKLOAD_STATE) == + MARS_WORKLOAD_STATE_NONE) { + MARS_BITS_SET(&bits, WORKLOAD_STATE, + MARS_WORKLOAD_STATE_ADDING); + MARS_BITS_SET(&bits, WORKLOAD_KERNEL_ID, + MARS_KERNEL_ID_NONE); + mars_ea_put_uint64(get_block_bits_ea(block_ea, index), + bits); + ret = index; + break; + } + } + + mars_mutex_unlock(block_ea); + + return ret; +} + +static int add_workload_module(uint64_t workload_ea, + const void *workload_module_elf, + const char *workload_module_name) +{ + int ret, i; + int text_found = 0; + int data_found = 0; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + struct mars_workload_module *workload_module; + + /* get work area for workload module */ + workload_module = mars_ea_work_area_get(workload_ea, + MARS_WORKLOAD_MODULE_ALIGN, + MARS_WORKLOAD_MODULE_SIZE); + + memset(workload_module, 0, MARS_WORKLOAD_MODULE_SIZE); + + /* process elf header information */ + ehdr = (Elf32_Ehdr *)workload_module_elf; + phdr = (Elf32_Phdr *)((void *)ehdr + ehdr->e_phoff); + + /* elf is not executable */ + if (ehdr->e_type != ET_EXEC) + return MARS_ERROR_FORMAT; + + for (i = 0; i < ehdr->e_phnum; i++) { + /* readonly text segment */ + if (phdr->p_type == PT_LOAD && + phdr->p_flags == PF_R + PF_X && + phdr->p_align == 0x80) { + /* make sure base addr is what we expect */ + if (text_found || + phdr->p_vaddr != MARS_WORKLOAD_MODULE_BASE_ADDR || + phdr->p_memsz != phdr->p_filesz) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + /* initialize the workload module text info */ + workload_module->text_ea = mars_ea_map((void *)ehdr + + phdr->p_offset, + phdr->p_filesz); + if (!workload_module->text_ea) { + ret = MARS_ERROR_MEMORY; + goto error; + } + + workload_module->text_vaddr = phdr->p_vaddr; + workload_module->text_size = phdr->p_filesz; + + /* make sure we only find 1 text segment */ + text_found = 1; + /* read-write data segment */ + } else if (phdr->p_type == PT_LOAD && + phdr->p_flags == PF_R + PF_W && + phdr->p_align == 0x80) { + if (data_found) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + workload_module->data_ea = mars_ea_map((void *)ehdr + + phdr->p_offset, + phdr->p_filesz); + if (!workload_module->data_ea) { + ret = MARS_ERROR_MEMORY; + goto error; + } + + workload_module->data_vaddr = phdr->p_vaddr; + workload_module->data_size = phdr->p_filesz; + workload_module->bss_size = phdr->p_memsz - + phdr->p_filesz; + + /* make sure we only find 1 data segment */ + data_found = 1; + } + + /* increment program header */ + phdr = (void *)phdr + ehdr->e_phentsize; + } + + /* make sure text and data segment is found */ + if (!text_found || !data_found) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + /* set the entry point of execution */ + workload_module->entry = ehdr->e_entry; + if (workload_module_name) + strcpy((char *)workload_module->name, workload_module_name); + else + memset((char *)workload_module->name, 0, + MARS_WORKLOAD_MODULE_NAME_LEN_MAX + 1); + + /* update workload module on EA */ + mars_ea_put(workload_ea, workload_module, MARS_WORKLOAD_MODULE_SIZE); + mars_ea_sync(); + + return MARS_SUCCESS; + +error: + if (text_found) + mars_ea_unmap(workload_module->text_ea, + workload_module->text_size); + if (data_found) + mars_ea_unmap(workload_module->data_ea, + workload_module->data_size); + + return ret; +} + +static void remove_workload_module(struct mars_context *mars, uint16_t id) +{ + struct mars_workload_module *workload_module; + + /* prepare work area for workload module */ + workload_module = mars_ea_work_area_get( + get_workload_ea(mars->workload_queue_ea, id), + MARS_WORKLOAD_MODULE_ALIGN, + MARS_WORKLOAD_MODULE_SIZE); + + /* get workload module from ea */ + mars_ea_get(mars->workload_queue_ea, workload_module, + MARS_WORKLOAD_MODULE_SIZE); + + mars_ea_unmap(workload_module->text_ea, workload_module->text_size); + mars_ea_unmap(workload_module->data_ea, workload_module->data_size); +} + +int mars_workload_queue_add_begin(struct mars_context *mars, + uint16_t *id, + uint64_t *workload_ea, + const void *workload_module_elf, + const char *workload_module_name) +{ + int ret; + int block; + int index = 0; + uint64_t queue_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->workload_queue_ea) + return MARS_ERROR_PARAMS; + if (!id) + return MARS_ERROR_NULL; + if (!workload_module_elf) + return MARS_ERROR_NULL; + if (workload_module_name && + strlen(workload_module_name) > MARS_WORKLOAD_MODULE_NAME_LEN_MAX) + return MARS_ERROR_PARAMS; + + queue_ea = mars->workload_queue_ea; + + /* find free workload queue entry */ + for (block = 0; block < MARS_WORKLOAD_NUM_BLOCKS; block++) { + uint64_t block_ea = get_block_ea(queue_ea, block); + + index = alloc_block(block_ea); + if (index >= 0) + break; + } + + /* no more free workload queue entry */ + if (block >= MARS_WORKLOAD_NUM_BLOCKS) + return MARS_ERROR_LIMIT; + + /* calculate and return workload id */ + *id = block * MARS_WORKLOAD_PER_BLOCK + index; + + /* add the workload module in workload context */ + ret = add_workload_module(get_workload_ea(queue_ea, *id), + workload_module_elf, workload_module_name); + if (ret != MARS_SUCCESS) { + change_state(mars, *id, NULL, + MARS_WORKLOAD_STATE_ADDING, + MARS_WORKLOAD_STATE_NONE, + NULL); + return ret; + } + + /* if requested set workload context pointer to return */ + if (workload_ea) + *workload_ea = get_workload_ea(queue_ea, *id); + + return MARS_SUCCESS; +} + +int mars_workload_queue_add_end(struct mars_context *mars, + uint16_t id, + int cancel) +{ + return change_state(mars, id, NULL, + MARS_WORKLOAD_STATE_ADDING, + cancel ? MARS_WORKLOAD_STATE_NONE : + MARS_WORKLOAD_STATE_FINISHED, + cancel ? remove_workload_module : NULL); +} + +int mars_workload_queue_remove_begin(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea) +{ + return change_state(mars, id, workload_ea, + MARS_WORKLOAD_STATE_FINISHED, + MARS_WORKLOAD_STATE_REMOVING, + NULL); +} + +int mars_workload_queue_remove_end(struct mars_context *mars, + uint16_t id, + int cancel) +{ + return change_state(mars, id, NULL, + MARS_WORKLOAD_STATE_REMOVING, + cancel ? MARS_WORKLOAD_STATE_FINISHED : + MARS_WORKLOAD_STATE_NONE, + cancel ? NULL : remove_workload_module); +} + +static uint64_t set_schedule_bits(uint64_t bits, uint64_t priority) +{ + /* set the info bits inside queue block for this workload */ + MARS_BITS_SET(&bits, WORKLOAD_STATE, MARS_WORKLOAD_STATE_SCHEDULING); + MARS_BITS_SET(&bits, WORKLOAD_PRIORITY, priority); + MARS_BITS_SET(&bits, WORKLOAD_COUNTER, MARS_WORKLOAD_COUNTER_MIN); + MARS_BITS_SET(&bits, WORKLOAD_SIGNAL, MARS_WORKLOAD_SIGNAL_OFF); + MARS_BITS_SET(&bits, WORKLOAD_WAIT_ID, MARS_WORKLOAD_ID_NONE); + + return bits; +} + +int mars_workload_queue_schedule_begin(struct mars_context *mars, + uint16_t id, uint8_t priority, + uint64_t *workload_ea) +{ + return change_bits(mars, id, workload_ea, + check_state_bits, MARS_WORKLOAD_STATE_FINISHED, + set_schedule_bits, priority, + NULL); +} + +static void update_header_bits(struct mars_context *mars, uint16_t id) +{ + int block = id / MARS_WORKLOAD_PER_BLOCK;; + int index; + uint64_t queue_ea; + uint64_t block_ea; + uint64_t header_bits_ea; + uint16_t header_bits; + uint64_t header_access_ea; + uint32_t header_access; + uint8_t block_ready = MARS_WORKLOAD_BLOCK_READY_OFF; + uint8_t block_waiting = MARS_WORKLOAD_BLOCK_WAITING_OFF; + uint8_t block_priority = MARS_WORKLOAD_BLOCK_PRIORITY_MIN; + + queue_ea = mars->workload_queue_ea; + + block_ea = get_block_ea(queue_ea, block); + + /* search through currently locked queue block workload bits */ + for (index = 1; index < MARS_WORKLOAD_PER_BLOCK; index++) { + uint64_t bits_ea = get_block_bits_ea(block_ea, index); + uint64_t bits = mars_ea_get_uint64(bits_ea); + uint8_t state = MARS_BITS_GET(&bits, WORKLOAD_STATE); + + /* workload state is ready so check priority */ + if (state == MARS_WORKLOAD_STATE_READY) { + uint8_t priority = MARS_BITS_GET(&bits, + WORKLOAD_PRIORITY); + + /* set block priority if higher then current */ + if (priority > block_priority) + block_priority = priority; + + /* set block ready bit in header bits for block */ + block_ready = MARS_WORKLOAD_BLOCK_READY_ON; + } else if (state == MARS_WORKLOAD_STATE_WAITING) { + /* set block waiting bit in header bits for block */ + block_waiting = MARS_WORKLOAD_BLOCK_WAITING_ON; + } + } + + /* lock the queue header */ + mars_mutex_lock(queue_ea); + + /* set the info bits inside queue header for this queue block */ + header_bits_ea = queue_ea + + offsetof(struct mars_workload_queue_header, bits) + + sizeof(uint16_t) * block; + header_bits = mars_ea_get_uint16(header_bits_ea); + + MARS_BITS_SET(&header_bits, BLOCK_READY, block_ready); + MARS_BITS_SET(&header_bits, BLOCK_WAITING, block_waiting); + MARS_BITS_SET(&header_bits, BLOCK_PRIORITY, block_priority); + + mars_ea_put_uint16(header_bits_ea, header_bits); + + /* increment the header access value */ + header_access_ea = queue_ea + + offsetof(struct mars_workload_queue_header, access); + header_access = mars_ea_get_uint32(header_access_ea); + + header_access++; + + mars_ea_put_uint32(header_access_ea, header_access); + + /* unlock the queue header */ + mars_mutex_unlock(queue_ea); +} + +int mars_workload_queue_schedule_end(struct mars_context *mars, + uint16_t id, + int cancel) +{ + return change_state(mars, id, NULL, + MARS_WORKLOAD_STATE_SCHEDULING, + cancel ? MARS_WORKLOAD_STATE_FINISHED: + MARS_WORKLOAD_STATE_READY, + cancel ? NULL : update_header_bits); +} + +static int unscheduling_state_bits(uint64_t bits, uint64_t param) +{ + (void)param; + + /* check for valid state */ + switch (MARS_BITS_GET(&bits, WORKLOAD_STATE)) { + case MARS_WORKLOAD_STATE_READY: + case MARS_WORKLOAD_STATE_RUNNING: + case MARS_WORKLOAD_STATE_WAITING: + return 1; + default: + return 0; + } +} + +int mars_workload_queue_unschedule_begin(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea) +{ + return change_bits(mars, id, workload_ea, + unscheduling_state_bits, 0, + set_state_bits, MARS_WORKLOAD_STATE_UNSCHEDULING, + NULL); +} + +int mars_workload_queue_unschedule_end(struct mars_context *mars, + uint16_t id) +{ + int ret; + int block; + int index; + uint64_t queue_ea; + uint64_t block_ea; + uint64_t bits_ea; + + ret = change_state(mars, id, NULL, + MARS_WORKLOAD_STATE_UNSCHEDULING, + MARS_WORKLOAD_STATE_FINISHED, + update_header_bits); + if (ret != MARS_SUCCESS) + return ret; + + queue_ea = mars->workload_queue_ea; + + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + block_ea = get_block_ea(queue_ea, block); + bits_ea = get_block_bits_ea(block_ea, index); + + /* signal any threads possibly waiting for workload to finish */ + mars_ea_cond_signal(bits_ea, 1); + + return MARS_SUCCESS; +} + +static int is_workload_finished(uint32_t upper, void *param) +{ + (void)param; + + /* this function assumes 'WORKLOAD_STATE' is stored in upper 32 bits */ + uint64_t bits = (uint64_t)upper << 32; + + switch (MARS_BITS_GET(&bits, WORKLOAD_STATE)) { + case MARS_WORKLOAD_STATE_FINISHED: + return MARS_SUCCESS; + case MARS_WORKLOAD_STATE_NONE: + return MARS_ERROR_STATE; + default: + return -1; + } +} + +static int workload_queue_wait(struct mars_context *mars, + uint16_t id, + int try, + uint64_t *workload_ea) +{ + int ret; + int block; + int index; + uint64_t queue_ea; + uint64_t block_ea; + uint64_t bits_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!mars->workload_queue_ea) + return MARS_ERROR_PARAMS; + if (id > MARS_WORKLOAD_ID_MAX || !(id % MARS_WORKLOAD_PER_BLOCK)) + return MARS_ERROR_PARAMS; + + queue_ea = mars->workload_queue_ea; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* prepare work area for queue block */ + block_ea = get_block_ea(queue_ea, block); + bits_ea = get_block_bits_ea(block_ea, index); + + if (try) { + ret = is_workload_finished(mars_ea_get_uint32(bits_ea), NULL); + if (ret < 0) + ret = MARS_ERROR_BUSY; + } else { + ret = mars_ea_cond_wait(bits_ea, is_workload_finished, NULL); + } + + if (ret != MARS_SUCCESS) + return ret; + + /* if requested set workload context pointer to return */ + if (workload_ea) + *workload_ea = get_workload_ea(queue_ea, id); + + return MARS_SUCCESS; +} + +int mars_workload_queue_wait(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea) +{ + return workload_queue_wait(mars, id, 0, workload_ea); +} + +int mars_workload_queue_try_wait(struct mars_context *mars, + uint16_t id, + uint64_t *workload_ea) +{ + return workload_queue_wait(mars, id, 1, workload_ea); +} + +static uint64_t set_signal_bits(uint64_t bits, uint64_t signal) +{ + MARS_BITS_SET(&bits, WORKLOAD_SIGNAL, signal); + + return bits; +} + +int mars_workload_queue_signal_send(struct mars_context *mars, + uint16_t id) +{ + return change_bits(mars, id, NULL, + check_state_bits_not, MARS_WORKLOAD_STATE_NONE, + set_signal_bits, MARS_WORKLOAD_SIGNAL_ON, + update_header_bits); +} diff --git a/common/libspumars/ppu/task/lib/elf.h b/common/libspumars/ppu/task/lib/elf.h new file mode 100644 index 00000000..b54dfc68 --- /dev/null +++ b/common/libspumars/ppu/task/lib/elf.h @@ -0,0 +1,2459 @@ +/* This file defines standard ELF types, structures, and macros. + Copyright (C) 1995-2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#ifndef __ELF_H__ +#define __ELF_H__ + +//#include + +/* Standard ELF types. */ + +#include + +/* Type for a 16-bit quantity. */ +typedef uint16_t Elf32_Half; +typedef uint16_t Elf64_Half; + +/* Types for signed and unsigned 32-bit quantities. */ +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf64_Word; +typedef int32_t Elf64_Sword; + +/* Types for signed and unsigned 64-bit quantities. */ +typedef uint64_t Elf32_Xword; +typedef int64_t Elf32_Sxword; +typedef uint64_t Elf64_Xword; +typedef int64_t Elf64_Sxword; + +/* Type of addresses. */ +typedef uint32_t Elf32_Addr; +typedef uint64_t Elf64_Addr; + +/* Type of file offsets. */ +typedef uint32_t Elf32_Off; +typedef uint64_t Elf64_Off; + +/* Type for section indices, which are 16-bit quantities. */ +typedef uint16_t Elf32_Section; +typedef uint16_t Elf64_Section; + +/* Type for version symbol information. */ +typedef Elf32_Half Elf32_Versym; +typedef Elf64_Half Elf64_Versym; + + +/* The ELF file header. This appears at the start of every ELF file. */ + +#define EI_NIDENT (16) + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +} Elf32_Ehdr; + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf64_Half e_type; /* Object file type */ + Elf64_Half e_machine; /* Architecture */ + Elf64_Word e_version; /* Object file version */ + Elf64_Addr e_entry; /* Entry point virtual address */ + Elf64_Off e_phoff; /* Program header table file offset */ + Elf64_Off e_shoff; /* Section header table file offset */ + Elf64_Word e_flags; /* Processor-specific flags */ + Elf64_Half e_ehsize; /* ELF header size in bytes */ + Elf64_Half e_phentsize; /* Program header table entry size */ + Elf64_Half e_phnum; /* Program header table entry count */ + Elf64_Half e_shentsize; /* Section header table entry size */ + Elf64_Half e_shnum; /* Section header table entry count */ + Elf64_Half e_shstrndx; /* Section header string table index */ +} Elf64_Ehdr; + +/* Fields in the e_ident array. The EI_* macros are indices into the + array. The macros under each EI_* macro are the values the byte + may have. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +/* Conglomeration of the identification bytes, for easy testing as a word. */ +#define ELFMAG "\177ELF" +#define SELFMAG 4 + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ +#define ELFCLASSNUM 3 + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ +#define ELFDATANUM 3 + +#define EI_VERSION 6 /* File version byte index */ + /* Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_SYSV 0 /* Alias. */ +#define ELFOSABI_HPUX 1 /* HP-UX */ +#define ELFOSABI_NETBSD 2 /* NetBSD. */ +#define ELFOSABI_LINUX 3 /* Linux. */ +#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ +#define ELFOSABI_AIX 7 /* IBM AIX. */ +#define ELFOSABI_IRIX 8 /* SGI Irix. */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD. */ +#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto. */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD. */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +/* Legal values for e_type (object file type). */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_NUM 5 /* Number of defined types */ +#define ET_LOOS 0xfe00 /* OS-specific range start */ +#define ET_HIOS 0xfeff /* OS-specific range end */ +#define ET_LOPROC 0xff00 /* Processor-specific range start */ +#define ET_HIPROC 0xffff /* Processor-specific range end */ + +/* Legal values for e_machine (architecture). */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 big-endian */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ + +#define EM_PARISC 15 /* HPPA */ +#define EM_VPP500 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* PowerPC 64-bit */ +#define EM_S390 22 /* IBM S390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH-32 */ +#define EM_RCE 39 /* Motorola RCE */ +#define EM_ARM 40 /* ARM */ +#define EM_FAKE_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Hitachi SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore */ +#define EM_ARC 45 /* Argonaut RISC Core */ +#define EM_H8_300 46 /* Hitachi H8/300 */ +#define EM_H8_300H 47 /* Hitachi H8/300H */ +#define EM_H8S 48 /* Hitachi H8S */ +#define EM_H8_500 49 /* Hitachi H8/500 */ +#define EM_IA_64 50 /* Intel Merced */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embeeded RISC */ +#define EM_NDR1 57 /* Denso NDR1 microprocessor */ +#define EM_STARCORE 58 /* Motorola Start*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronic ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ +#define EM_X86_64 62 /* AMD x86-64 architecture */ +#define EM_PDSP 63 /* Sony DSP Processor */ + +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ +#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ +#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ +#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard University machine-independent object files */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Mitsubishi M32R */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_NUM 95 + +/* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the + chances of collision with official or non-GNU unofficial values. */ + +#define EM_ALPHA 0x9026 + +/* Legal values for e_version (version). */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ +#define EV_NUM 2 + +/* Section header. */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +} Elf32_Shdr; + +typedef struct +{ + Elf64_Word sh_name; /* Section name (string tbl index) */ + Elf64_Word sh_type; /* Section type */ + Elf64_Xword sh_flags; /* Section flags */ + Elf64_Addr sh_addr; /* Section virtual addr at execution */ + Elf64_Off sh_offset; /* Section file offset */ + Elf64_Xword sh_size; /* Section size in bytes */ + Elf64_Word sh_link; /* Link to another section */ + Elf64_Word sh_info; /* Additional section information */ + Elf64_Xword sh_addralign; /* Section alignment */ + Elf64_Xword sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + +/* Special section indices. */ + +#define SHN_UNDEF 0 /* Undefined section */ +#define SHN_LORESERVE 0xff00 /* Start of reserved indices */ +#define SHN_LOPROC 0xff00 /* Start of processor-specific */ +#define SHN_BEFORE 0xff00 /* Order section before all others + (Solaris). */ +#define SHN_AFTER 0xff01 /* Order section after all others + (Solaris). */ +#define SHN_HIPROC 0xff1f /* End of processor-specific */ +#define SHN_LOOS 0xff20 /* Start of OS-specific */ +#define SHN_HIOS 0xff3f /* End of OS-specific */ +#define SHN_ABS 0xfff1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xfff2 /* Associated symbol is common */ +#define SHN_XINDEX 0xffff /* Index is in extra table. */ +#define SHN_HIRESERVE 0xffff /* End of reserved indices */ + +/* Legal values for sh_type (section type). */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ +#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table. */ +#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ +#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ +#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ +#define SHT_SUNW_move 0x6ffffffa +#define SHT_SUNW_COMDAT 0x6ffffffb +#define SHT_SUNW_syminfo 0x6ffffffc +#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ +#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ +#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ +#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ +#define SHT_HIOS 0x6fffffff /* End OS-specific type */ +#define SHT_LOPROC 0x70000000 /* Start of processor-specific */ +#define SHT_HIPROC 0x7fffffff /* End of processor-specific */ +#define SHT_LOUSER 0x80000000 /* Start of application-specific */ +#define SHT_HIUSER 0x8fffffff /* End of application-specific */ + +/* Legal values for sh_flags (section flags). */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ +#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ +#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling + required */ +#define SHF_GROUP (1 << 9) /* Section is member of a group. */ +#define SHF_TLS (1 << 10) /* Section hold thread-local data. */ +#define SHF_MASKOS 0x0ff00000 /* OS-specific. */ +#define SHF_MASKPROC 0xf0000000 /* Processor-specific */ +#define SHF_ORDERED (1 << 30) /* Special ordering requirement + (Solaris). */ +#define SHF_EXCLUDE (1 << 31) /* Section is excluded unless + referenced or allocated (Solaris).*/ + +/* Section group handling. */ +#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ + +/* Symbol table entry. */ + +typedef struct +{ + Elf32_Word st_name; /* Symbol name (string tbl index) */ + Elf32_Addr st_value; /* Symbol value */ + Elf32_Word st_size; /* Symbol size */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf32_Section st_shndx; /* Section index */ +} Elf32_Sym; + +typedef struct +{ + Elf64_Word st_name; /* Symbol name (string tbl index) */ + unsigned char st_info; /* Symbol type and binding */ + unsigned char st_other; /* Symbol visibility */ + Elf64_Section st_shndx; /* Section index */ + Elf64_Addr st_value; /* Symbol value */ + Elf64_Xword st_size; /* Symbol size */ +} Elf64_Sym; + +/* The syminfo section if available contains additional information about + every dynamic symbol. */ + +typedef struct +{ + Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf32_Half si_flags; /* Per symbol flags */ +} Elf32_Syminfo; + +typedef struct +{ + Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ + Elf64_Half si_flags; /* Per symbol flags */ +} Elf64_Syminfo; + +/* Possible values for si_boundto. */ +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy + loaded */ +/* Syminfo version values. */ +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + + +/* How to extract and insert information held in the st_info field. */ + +#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) +#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) + +/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ +#define ELF64_ST_BIND(val) ELF32_ST_BIND (val) +#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) +#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) + +/* Legal values for ST_BIND subfield of st_info (symbol binding). */ + +#define STB_LOCAL 0 /* Local symbol */ +#define STB_GLOBAL 1 /* Global symbol */ +#define STB_WEAK 2 /* Weak symbol */ +#define STB_NUM 3 /* Number of defined types. */ +#define STB_LOOS 10 /* Start of OS-specific */ +#define STB_HIOS 12 /* End of OS-specific */ +#define STB_LOPROC 13 /* Start of processor-specific */ +#define STB_HIPROC 15 /* End of processor-specific */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol's name is file name */ +#define STT_COMMON 5 /* Symbol is a common data object */ +#define STT_TLS 6 /* Symbol is thread-local data object*/ +#define STT_NUM 7 /* Number of defined types. */ +#define STT_LOOS 10 /* Start of OS-specific */ +#define STT_HIOS 12 /* End of OS-specific */ +#define STT_LOPROC 13 /* Start of processor-specific */ +#define STT_HIPROC 15 /* End of processor-specific */ + + +/* Symbol table indices are found in the hash buckets and chain table + of a symbol hash table section. This special index value indicates + the end of a chain, meaning no further symbols are found in that bucket. */ + +#define STN_UNDEF 0 /* End of a chain. */ + + +/* How to extract and insert information held in the st_other field. */ + +#define ELF32_ST_VISIBILITY(o) ((o) & 0x03) + +/* For ELF64 the definitions are the same. */ +#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) + +/* Symbol visibility specification encoded in the st_other field. */ +#define STV_DEFAULT 0 /* Default symbol visibility rules */ +#define STV_INTERNAL 1 /* Processor specific hidden class */ +#define STV_HIDDEN 2 /* Sym unavailable in other modules */ +#define STV_PROTECTED 3 /* Not preemptible, not exported */ + + +/* Relocation table entry without addend (in section of type SHT_REL). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ +} Elf32_Rel; + +/* I have seen two different definitions of the Elf64_Rel and + Elf64_Rela structures, so we'll leave them out until Novell (or + whoever) gets their act together. */ +/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ +} Elf64_Rel; + +/* Relocation table entry with addend (in section of type SHT_RELA). */ + +typedef struct +{ + Elf32_Addr r_offset; /* Address */ + Elf32_Word r_info; /* Relocation type and symbol index */ + Elf32_Sword r_addend; /* Addend */ +} Elf32_Rela; + +typedef struct +{ + Elf64_Addr r_offset; /* Address */ + Elf64_Xword r_info; /* Relocation type and symbol index */ + Elf64_Sxword r_addend; /* Addend */ +} Elf64_Rela; + +/* How to extract and insert information held in the r_info field. */ + +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) +#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) + +/* Program segment header. */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +} Elf32_Phdr; + +typedef struct +{ + Elf64_Word p_type; /* Segment type */ + Elf64_Word p_flags; /* Segment flags */ + Elf64_Off p_offset; /* Segment file offset */ + Elf64_Addr p_vaddr; /* Segment virtual address */ + Elf64_Addr p_paddr; /* Segment physical address */ + Elf64_Xword p_filesz; /* Segment size in file */ + Elf64_Xword p_memsz; /* Segment size in memory */ + Elf64_Xword p_align; /* Segment alignment */ +} Elf64_Phdr; + +/* Legal values for p_type (segment type). */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread-local storage segment */ +#define PT_NUM 8 /* Number of defined types */ +#define PT_LOOS 0x60000000 /* Start of OS-specific */ +#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ +#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ +#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ +#define PT_LOSUNW 0x6ffffffa +#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ +#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ +#define PT_HISUNW 0x6fffffff +#define PT_HIOS 0x6fffffff /* End of OS-specific */ +#define PT_LOPROC 0x70000000 /* Start of processor-specific */ +#define PT_HIPROC 0x7fffffff /* End of processor-specific */ + +/* Legal values for p_flags (segment flags). */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +#define PF_MASKOS 0x0ff00000 /* OS-specific */ +#define PF_MASKPROC 0xf0000000 /* Processor-specific */ + +/* Legal values for note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_PRXREG 4 /* Contains copy of prxregset struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task structure */ +#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ +#define NT_AUXV 6 /* Contains copy of auxv array */ +#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ +#define NT_ASRS 8 /* Contains copy of asrset struct */ +#define NT_PSTATUS 10 /* Contains copy of pstatus struct */ +#define NT_PSINFO 13 /* Contains copy of psinfo struct */ +#define NT_PRCRED 14 /* Contains copy of prcred struct */ +#define NT_UTSNAME 15 /* Contains copy of utsname struct */ +#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ +#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ +#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/ + +/* Legal values for the note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ + + +/* Dynamic section entry. */ + +typedef struct +{ + Elf32_Sword d_tag; /* Dynamic entry type */ + union + { + Elf32_Word d_val; /* Integer value */ + Elf32_Addr d_ptr; /* Address value */ + } d_un; +} Elf32_Dyn; + +typedef struct +{ + Elf64_Sxword d_tag; /* Dynamic entry type */ + union + { + Elf64_Xword d_val; /* Integer value */ + Elf64_Addr d_ptr; /* Address value */ + } d_un; +} Elf64_Dyn; + +/* Legal values for d_tag (dynamic entry type). */ + +#define DT_NULL 0 /* Marks end of dynamic section */ +#define DT_NEEDED 1 /* Name of needed library */ +#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ +#define DT_PLTGOT 3 /* Processor defined value */ +#define DT_HASH 4 /* Address of symbol hash table */ +#define DT_STRTAB 5 /* Address of string table */ +#define DT_SYMTAB 6 /* Address of symbol table */ +#define DT_RELA 7 /* Address of Rela relocs */ +#define DT_RELASZ 8 /* Total size of Rela relocs */ +#define DT_RELAENT 9 /* Size of one Rela reloc */ +#define DT_STRSZ 10 /* Size of string table */ +#define DT_SYMENT 11 /* Size of one symbol table entry */ +#define DT_INIT 12 /* Address of init function */ +#define DT_FINI 13 /* Address of termination function */ +#define DT_SONAME 14 /* Name of shared object */ +#define DT_RPATH 15 /* Library search path (deprecated) */ +#define DT_SYMBOLIC 16 /* Start symbol search here */ +#define DT_REL 17 /* Address of Rel relocs */ +#define DT_RELSZ 18 /* Total size of Rel relocs */ +#define DT_RELENT 19 /* Size of one Rel reloc */ +#define DT_PLTREL 20 /* Type of reloc in PLT */ +#define DT_DEBUG 21 /* For debugging; unspecified */ +#define DT_TEXTREL 22 /* Reloc might modify .text */ +#define DT_JMPREL 23 /* Address of PLT relocs */ +#define DT_BIND_NOW 24 /* Process relocations of object */ +#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ +#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ +#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ +#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ +#define DT_RUNPATH 29 /* Library search path */ +#define DT_FLAGS 30 /* Flags for the object being loaded */ +#define DT_ENCODING 32 /* Start of encoded range */ +#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ +#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ +#define DT_NUM 34 /* Number used */ +#define DT_LOOS 0x6000000d /* Start of OS-specific */ +#define DT_HIOS 0x6ffff000 /* End of OS-specific */ +#define DT_LOPROC 0x70000000 /* Start of processor-specific */ +#define DT_HIPROC 0x7fffffff /* End of processor-specific */ +#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ + +/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the + Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's + approach. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ +#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting + the following DT_* entry. */ +#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ +#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ +#define DT_VALRNGHI 0x6ffffdff +#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ +#define DT_VALNUM 12 + +/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the + Dyn.d_un.d_ptr field of the Elf*_Dyn structure. + + If any adjustment is made to the ELF object after it has been + built these entries will need to be adjusted. */ +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ +#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ +#define DT_CONFIG 0x6ffffefa /* Configuration information. */ +#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ +#define DT_AUDIT 0x6ffffefc /* Object auditing. */ +#define DT_PLTPAD 0x6ffffefd /* PLT padding. */ +#define DT_MOVETAB 0x6ffffefe /* Move table. */ +#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ +#define DT_ADDRRNGHI 0x6ffffeff +#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ +#define DT_ADDRNUM 10 + +/* The versioning entry types. The next are defined as part of the + GNU extension. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa + +/* These were chosen by Sun. */ +#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ +#define DT_VERDEF 0x6ffffffc /* Address of version definition + table */ +#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ +#define DT_VERNEED 0x6ffffffe /* Address of table with needed + versions */ +#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGNUM 16 + +/* Sun added these machine-independent extensions in the "processor-specific" + range. Be compatible. */ +#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ +#define DT_FILTER 0x7fffffff /* Shared object to get values from */ +#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) +#define DT_EXTRANUM 3 + +/* Values of `d_un.d_val' in the DT_FLAGS entry. */ +#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ +#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ +#define DF_TEXTREL 0x00000004 /* Object contains text relocations */ +#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ +#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ + +/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 + entry in the dynamic section. */ +#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ +#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ +#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ +#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ +#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ +#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ +#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ +#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ +#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ +#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ +#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ +#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ +#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ +#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ +#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ + +/* Flags for the feature selection in DT_FEATURE_1. */ +#define DTF_1_PARINIT 0x00000001 +#define DTF_1_CONFEXP 0x00000002 + +/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ +#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ +#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not + generally available. */ + +/* Version definition sections. */ + +typedef struct +{ + Elf32_Half vd_version; /* Version revision */ + Elf32_Half vd_flags; /* Version information */ + Elf32_Half vd_ndx; /* Version Index */ + Elf32_Half vd_cnt; /* Number of associated aux entries */ + Elf32_Word vd_hash; /* Version name hash value */ + Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf32_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf32_Verdef; + +typedef struct +{ + Elf64_Half vd_version; /* Version revision */ + Elf64_Half vd_flags; /* Version information */ + Elf64_Half vd_ndx; /* Version Index */ + Elf64_Half vd_cnt; /* Number of associated aux entries */ + Elf64_Word vd_hash; /* Version name hash value */ + Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ + Elf64_Word vd_next; /* Offset in bytes to next verdef + entry */ +} Elf64_Verdef; + + +/* Legal values for vd_version (version revision). */ +#define VER_DEF_NONE 0 /* No version */ +#define VER_DEF_CURRENT 1 /* Current version */ +#define VER_DEF_NUM 2 /* Given version number */ + +/* Legal values for vd_flags (version information flags). */ +#define VER_FLG_BASE 0x1 /* Version definition of file itself */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + +/* Versym symbol index values. */ +#define VER_NDX_LOCAL 0 /* Symbol is local. */ +#define VER_NDX_GLOBAL 1 /* Symbol is global. */ +#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ +#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ + +/* Auxialiary version information. */ + +typedef struct +{ + Elf32_Word vda_name; /* Version or dependency names */ + Elf32_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf32_Verdaux; + +typedef struct +{ + Elf64_Word vda_name; /* Version or dependency names */ + Elf64_Word vda_next; /* Offset in bytes to next verdaux + entry */ +} Elf64_Verdaux; + + +/* Version dependency section. */ + +typedef struct +{ + Elf32_Half vn_version; /* Version of structure */ + Elf32_Half vn_cnt; /* Number of associated aux entries */ + Elf32_Word vn_file; /* Offset of filename for this + dependency */ + Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf32_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf32_Verneed; + +typedef struct +{ + Elf64_Half vn_version; /* Version of structure */ + Elf64_Half vn_cnt; /* Number of associated aux entries */ + Elf64_Word vn_file; /* Offset of filename for this + dependency */ + Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ + Elf64_Word vn_next; /* Offset in bytes to next verneed + entry */ +} Elf64_Verneed; + + +/* Legal values for vn_version (version revision). */ +#define VER_NEED_NONE 0 /* No version */ +#define VER_NEED_CURRENT 1 /* Current version */ +#define VER_NEED_NUM 2 /* Given version number */ + +/* Auxiliary needed version information. */ + +typedef struct +{ + Elf32_Word vna_hash; /* Hash value of dependency name */ + Elf32_Half vna_flags; /* Dependency specific information */ + Elf32_Half vna_other; /* Unused */ + Elf32_Word vna_name; /* Dependency name string offset */ + Elf32_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf32_Vernaux; + +typedef struct +{ + Elf64_Word vna_hash; /* Hash value of dependency name */ + Elf64_Half vna_flags; /* Dependency specific information */ + Elf64_Half vna_other; /* Unused */ + Elf64_Word vna_name; /* Dependency name string offset */ + Elf64_Word vna_next; /* Offset in bytes to next vernaux + entry */ +} Elf64_Vernaux; + + +/* Legal values for vna_flags. */ +#define VER_FLG_WEAK 0x2 /* Weak version identifier */ + + +/* Auxiliary vector. */ + +/* This vector is normally only used by the program interpreter. The + usual definition in an ABI supplement uses the name auxv_t. The + vector is not usually defined in a standard file, but it + can't hurt. We rename it to avoid conflicts. The sizes of these + types are an arrangement between the exec server and the program + interpreter, so we don't fully specify them here. */ + +typedef struct +{ + int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf32_auxv_t; + +typedef struct +{ + long int a_type; /* Entry type */ + union + { + long int a_val; /* Integer value */ + void *a_ptr; /* Pointer value */ + void (*a_fcn) (void); /* Function pointer value */ + } a_un; +} Elf64_auxv_t; + +/* Legal values for a_type (entry type). */ + +#define AT_NULL 0 /* End of vector */ +#define AT_IGNORE 1 /* Entry should be ignored */ +#define AT_EXECFD 2 /* File descriptor of program */ +#define AT_PHDR 3 /* Program headers for program */ +#define AT_PHENT 4 /* Size of program header entry */ +#define AT_PHNUM 5 /* Number of program headers */ +#define AT_PAGESZ 6 /* System page size */ +#define AT_BASE 7 /* Base address of interpreter */ +#define AT_FLAGS 8 /* Flags */ +#define AT_ENTRY 9 /* Entry point of program */ +#define AT_NOTELF 10 /* Program is not ELF */ +#define AT_UID 11 /* Real uid */ +#define AT_EUID 12 /* Effective uid */ +#define AT_GID 13 /* Real gid */ +#define AT_EGID 14 /* Effective gid */ +#define AT_CLKTCK 17 /* Frequency of times() */ + +/* Some more special a_type values describing the hardware. */ +#define AT_PLATFORM 15 /* String identifying platform. */ +#define AT_HWCAP 16 /* Machine dependent hints about + processor capabilities. */ + +/* This entry gives some information about the FPU initialization + performed by the kernel. */ +#define AT_FPUCW 18 /* Used FPU control word. */ + +/* Cache block sizes. */ +#define AT_DCACHEBSIZE 19 /* Data cache block size. */ +#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ +#define AT_UCACHEBSIZE 21 /* Unified cache block size. */ + +/* A special ignored value for PPC, used by the kernel to control the + interpretation of the AUXV. Must be > 16. */ +#define AT_IGNOREPPC 22 /* Entry should be ignored. */ + +#define AT_SECURE 23 /* Boolean, was exec setuid-like? */ + +/* Pointer to the global system page used for system calls and other + nice things. */ +#define AT_SYSINFO 32 +#define AT_SYSINFO_EHDR 33 + + +/* Note section contents. Each entry in the note section begins with + a header of a fixed form. */ + +typedef struct +{ + Elf32_Word n_namesz; /* Length of the note's name. */ + Elf32_Word n_descsz; /* Length of the note's descriptor. */ + Elf32_Word n_type; /* Type of the note. */ +} Elf32_Nhdr; + +typedef struct +{ + Elf64_Word n_namesz; /* Length of the note's name. */ + Elf64_Word n_descsz; /* Length of the note's descriptor. */ + Elf64_Word n_type; /* Type of the note. */ +} Elf64_Nhdr; + +/* Known names of notes. */ + +/* Solaris entries in the note section have this name. */ +#define ELF_NOTE_SOLARIS "SUNW Solaris" + +/* Note entries for GNU systems have this name. */ +#define ELF_NOTE_GNU "GNU" + + +/* Defined types of notes for Solaris. */ + +/* Value of descriptor (one word) is desired pagesize for the binary. */ +#define ELF_NOTE_PAGESIZE_HINT 1 + + +/* Defined note types for GNU systems. */ + +/* ABI information. The descriptor consists of words: + word 0: OS descriptor + word 1: major version of the ABI + word 2: minor version of the ABI + word 3: subminor version of the ABI +*/ +#define ELF_NOTE_ABI 1 + +/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI + note section entry. */ +#define ELF_NOTE_OS_LINUX 0 +#define ELF_NOTE_OS_GNU 1 +#define ELF_NOTE_OS_SOLARIS2 2 +#define ELF_NOTE_OS_FREEBSD 3 + + +/* Move records. */ +typedef struct +{ + Elf32_Xword m_value; /* Symbol value. */ + Elf32_Word m_info; /* Size and index. */ + Elf32_Word m_poffset; /* Symbol offset. */ + Elf32_Half m_repeat; /* Repeat count. */ + Elf32_Half m_stride; /* Stride info. */ +} Elf32_Move; + +typedef struct +{ + Elf64_Xword m_value; /* Symbol value. */ + Elf64_Xword m_info; /* Size and index. */ + Elf64_Xword m_poffset; /* Symbol offset. */ + Elf64_Half m_repeat; /* Repeat count. */ + Elf64_Half m_stride; /* Stride info. */ +} Elf64_Move; + +/* Macro to construct move records. */ +#define ELF32_M_SYM(info) ((info) >> 8) +#define ELF32_M_SIZE(info) ((unsigned char) (info)) +#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) + +#define ELF64_M_SYM(info) ELF32_M_SYM (info) +#define ELF64_M_SIZE(info) ELF32_M_SIZE (info) +#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) + + +/* Motorola 68k specific definitions. */ + +/* Values for Elf32_Ehdr.e_flags. */ +#define EF_CPU32 0x00810000 + +/* m68k relocs. */ + +#define R_68K_NONE 0 /* No reloc */ +#define R_68K_32 1 /* Direct 32 bit */ +#define R_68K_16 2 /* Direct 16 bit */ +#define R_68K_8 3 /* Direct 8 bit */ +#define R_68K_PC32 4 /* PC relative 32 bit */ +#define R_68K_PC16 5 /* PC relative 16 bit */ +#define R_68K_PC8 6 /* PC relative 8 bit */ +#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ +#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ +#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ +#define R_68K_GOT32O 10 /* 32 bit GOT offset */ +#define R_68K_GOT16O 11 /* 16 bit GOT offset */ +#define R_68K_GOT8O 12 /* 8 bit GOT offset */ +#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ +#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ +#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ +#define R_68K_PLT32O 16 /* 32 bit PLT offset */ +#define R_68K_PLT16O 17 /* 16 bit PLT offset */ +#define R_68K_PLT8O 18 /* 8 bit PLT offset */ +#define R_68K_COPY 19 /* Copy symbol at runtime */ +#define R_68K_GLOB_DAT 20 /* Create GOT entry */ +#define R_68K_JMP_SLOT 21 /* Create PLT entry */ +#define R_68K_RELATIVE 22 /* Adjust by program base */ +/* Keep this the last entry. */ +#define R_68K_NUM 23 + +/* Intel 80386 specific definitions. */ + +/* i386 relocs. */ + +#define R_386_NONE 0 /* No reloc */ +#define R_386_32 1 /* Direct 32 bit */ +#define R_386_PC32 2 /* PC relative 32 bit */ +#define R_386_GOT32 3 /* 32 bit GOT entry */ +#define R_386_PLT32 4 /* 32 bit PLT address */ +#define R_386_COPY 5 /* Copy symbol at runtime */ +#define R_386_GLOB_DAT 6 /* Create GOT entry */ +#define R_386_JMP_SLOT 7 /* Create PLT entry */ +#define R_386_RELATIVE 8 /* Adjust by program base */ +#define R_386_GOTOFF 9 /* 32 bit offset to GOT */ +#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ +#define R_386_32PLT 11 +#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ +#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS + block offset */ +#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block + offset */ +#define R_386_TLS_LE 17 /* Offset relative to static TLS + block */ +#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of + general dynamic thread local data */ +#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of + local dynamic thread local data + in LE code */ +#define R_386_16 20 +#define R_386_PC16 21 +#define R_386_8 22 +#define R_386_PC8 23 +#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic + thread local data */ +#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ +#define R_386_TLS_GD_CALL 26 /* Relocation for call to + __tls_get_addr() */ +#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ +#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic + thread local data in LE code */ +#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ +#define R_386_TLS_LDM_CALL 30 /* Relocation for call to + __tls_get_addr() in LDM code */ +#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ +#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ +#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS + block offset */ +#define R_386_TLS_LE_32 34 /* Negated offset relative to static + TLS block */ +#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ +#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ +#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ +/* Keep this the last entry. */ +#define R_386_NUM 38 + +/* SUN SPARC specific definitions. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ + +/* Values for Elf64_Ehdr.e_flags. */ + +#define EF_SPARCV9_MM 3 +#define EF_SPARCV9_TSO 0 +#define EF_SPARCV9_PSO 1 +#define EF_SPARCV9_RMO 2 +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ +#define EF_SPARC_EXT_MASK 0xFFFF00 +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +/* SPARC relocs. */ + +#define R_SPARC_NONE 0 /* No reloc */ +#define R_SPARC_8 1 /* Direct 8 bit */ +#define R_SPARC_16 2 /* Direct 16 bit */ +#define R_SPARC_32 3 /* Direct 32 bit */ +#define R_SPARC_DISP8 4 /* PC relative 8 bit */ +#define R_SPARC_DISP16 5 /* PC relative 16 bit */ +#define R_SPARC_DISP32 6 /* PC relative 32 bit */ +#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ +#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ +#define R_SPARC_HI22 9 /* High 22 bit */ +#define R_SPARC_22 10 /* Direct 22 bit */ +#define R_SPARC_13 11 /* Direct 13 bit */ +#define R_SPARC_LO10 12 /* Truncated 10 bit */ +#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ +#define R_SPARC_GOT13 14 /* 13 bit GOT entry */ +#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ +#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ +#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ +#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ +#define R_SPARC_COPY 19 /* Copy symbol at runtime */ +#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ +#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ +#define R_SPARC_RELATIVE 22 /* Adjust by program base */ +#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ + +/* Additional Sparc64 relocs. */ + +#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ +#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ +#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ +#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ +#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ +#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ +#define R_SPARC_10 30 /* Direct 10 bit */ +#define R_SPARC_11 31 /* Direct 11 bit */ +#define R_SPARC_64 32 /* Direct 64 bit */ +#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ +#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ +#define R_SPARC_HM10 35 /* High middle 10 bits of ... */ +#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ +#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ +#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ +#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ +#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ +#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ +#define R_SPARC_7 43 /* Direct 7 bit */ +#define R_SPARC_5 44 /* Direct 5 bit */ +#define R_SPARC_6 45 /* Direct 6 bit */ +#define R_SPARC_DISP64 46 /* PC relative 64 bit */ +#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ +#define R_SPARC_HIX22 48 /* High 22 bit complemented */ +#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ +#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ +#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ +#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ +#define R_SPARC_REGISTER 53 /* Global register usage */ +#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ +#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ +#define R_SPARC_TLS_GD_HI22 56 +#define R_SPARC_TLS_GD_LO10 57 +#define R_SPARC_TLS_GD_ADD 58 +#define R_SPARC_TLS_GD_CALL 59 +#define R_SPARC_TLS_LDM_HI22 60 +#define R_SPARC_TLS_LDM_LO10 61 +#define R_SPARC_TLS_LDM_ADD 62 +#define R_SPARC_TLS_LDM_CALL 63 +#define R_SPARC_TLS_LDO_HIX22 64 +#define R_SPARC_TLS_LDO_LOX10 65 +#define R_SPARC_TLS_LDO_ADD 66 +#define R_SPARC_TLS_IE_HI22 67 +#define R_SPARC_TLS_IE_LO10 68 +#define R_SPARC_TLS_IE_LD 69 +#define R_SPARC_TLS_IE_LDX 70 +#define R_SPARC_TLS_IE_ADD 71 +#define R_SPARC_TLS_LE_HIX22 72 +#define R_SPARC_TLS_LE_LOX10 73 +#define R_SPARC_TLS_DTPMOD32 74 +#define R_SPARC_TLS_DTPMOD64 75 +#define R_SPARC_TLS_DTPOFF32 76 +#define R_SPARC_TLS_DTPOFF64 77 +#define R_SPARC_TLS_TPOFF32 78 +#define R_SPARC_TLS_TPOFF64 79 +/* Keep this the last entry. */ +#define R_SPARC_NUM 80 + +/* For Sparc64, legal values for d_tag of Elf64_Dyn. */ + +#define DT_SPARC_REGISTER 0x70000001 +#define DT_SPARC_NUM 2 + +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 +#define HWCAP_SPARC_V9 16 /* The cpu is v9, so v8plus is ok. */ +#define HWCAP_SPARC_ULTRA3 32 + +/* MIPS R3000 specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ +#define EF_MIPS_PIC 2 /* Contains PIC code */ +#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ +#define EF_MIPS_XGOT 8 +#define EF_MIPS_64BIT_WHIRL 16 +#define EF_MIPS_ABI2 32 +#define EF_MIPS_ABI_ON32 64 +#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ + +/* Legal values for MIPS architecture level. */ + +#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* The following are non-official names and should not be used. */ + +#define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ +#define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ +#define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ +#define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ +#define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ +#define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ +#define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ + +/* Special section indices. */ + +#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ +#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ +#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ +#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ +#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ +#define SHT_MIPS_MSYM 0x70000001 +#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ +#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ +#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ +#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ +#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ +#define SHT_MIPS_PACKAGE 0x70000007 +#define SHT_MIPS_PACKSYM 0x70000008 +#define SHT_MIPS_RELD 0x70000009 +#define SHT_MIPS_IFACE 0x7000000b +#define SHT_MIPS_CONTENT 0x7000000c +#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ +#define SHT_MIPS_SHDR 0x70000010 +#define SHT_MIPS_FDESC 0x70000011 +#define SHT_MIPS_EXTSYM 0x70000012 +#define SHT_MIPS_DENSE 0x70000013 +#define SHT_MIPS_PDESC 0x70000014 +#define SHT_MIPS_LOCSYM 0x70000015 +#define SHT_MIPS_AUXSYM 0x70000016 +#define SHT_MIPS_OPTSYM 0x70000017 +#define SHT_MIPS_LOCSTR 0x70000018 +#define SHT_MIPS_LINE 0x70000019 +#define SHT_MIPS_RFDESC 0x7000001a +#define SHT_MIPS_DELTASYM 0x7000001b +#define SHT_MIPS_DELTAINST 0x7000001c +#define SHT_MIPS_DELTACLASS 0x7000001d +#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ +#define SHT_MIPS_DELTADECL 0x7000001f +#define SHT_MIPS_SYMBOL_LIB 0x70000020 +#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ +#define SHT_MIPS_TRANSLATE 0x70000022 +#define SHT_MIPS_PIXIE 0x70000023 +#define SHT_MIPS_XLATE 0x70000024 +#define SHT_MIPS_XLATE_DEBUG 0x70000025 +#define SHT_MIPS_WHIRL 0x70000026 +#define SHT_MIPS_EH_REGION 0x70000027 +#define SHT_MIPS_XLATE_OLD 0x70000028 +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ +#define SHF_MIPS_MERGE 0x20000000 +#define SHF_MIPS_ADDR 0x40000000 +#define SHF_MIPS_STRINGS 0x80000000 +#define SHF_MIPS_NOSTRIP 0x08000000 +#define SHF_MIPS_LOCAL 0x04000000 +#define SHF_MIPS_NAMES 0x02000000 +#define SHF_MIPS_NODUPE 0x01000000 + + +/* Symbol tables. */ + +/* MIPS specific values for `st_other'. */ +#define STO_MIPS_DEFAULT 0x0 +#define STO_MIPS_INTERNAL 0x1 +#define STO_MIPS_HIDDEN 0x2 +#define STO_MIPS_PROTECTED 0x3 +#define STO_MIPS_SC_ALIGN_UNUSED 0xff + +/* MIPS specific values for `st_info'. */ +#define STB_MIPS_SPLIT_COMMON 13 + +/* Entries found in sections of type SHT_MIPS_GPTAB. */ + +typedef union +{ + struct + { + Elf32_Word gt_current_g_value; /* -G value used for compilation */ + Elf32_Word gt_unused; /* Not used */ + } gt_header; /* First entry in section */ + struct + { + Elf32_Word gt_g_value; /* If this value were used for -G */ + Elf32_Word gt_bytes; /* This many bytes would be used */ + } gt_entry; /* Subsequent entries in section */ +} Elf32_gptab; + +/* Entry found in sections of type SHT_MIPS_REGINFO. */ + +typedef struct +{ + Elf32_Word ri_gprmask; /* General registers used */ + Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ + Elf32_Sword ri_gp_value; /* $gp register value */ +} Elf32_RegInfo; + +/* Entries found in sections of type SHT_MIPS_OPTIONS. */ + +typedef struct +{ + unsigned char kind; /* Determines interpretation of the + variable part of descriptor. */ + unsigned char size; /* Size of descriptor, including header. */ + Elf32_Section section; /* Section header index of section affected, + 0 for global options. */ + Elf32_Word info; /* Kind-specific information. */ +} Elf_Options; + +/* Values for `kind' field in Elf_Options. */ + +#define ODK_NULL 0 /* Undefined. */ +#define ODK_REGINFO 1 /* Register usage information. */ +#define ODK_EXCEPTIONS 2 /* Exception processing options. */ +#define ODK_PAD 3 /* Section padding options. */ +#define ODK_HWPATCH 4 /* Hardware workarounds performed */ +#define ODK_FILL 5 /* record the fill value used by the linker. */ +#define ODK_TAGS 6 /* reserve space for desktop tools to write. */ +#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ +#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ + +/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ + +#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ +#define OEX_PAGE0 0x10000 /* page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode? */ +#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ +#define OEX_PRECISEFP OEX_FPDBUG +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ + +#define OEX_FPU_INVAL 0x10 +#define OEX_FPU_DIV0 0x08 +#define OEX_FPU_OFLO 0x04 +#define OEX_FPU_UFLO 0x02 +#define OEX_FPU_INEX 0x01 + +/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ + +#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ + +#define OPAD_PREFIX 0x1 +#define OPAD_POSTFIX 0x2 +#define OPAD_SYMBOL 0x4 + +/* Entry found in `.options' section. */ + +typedef struct +{ + Elf32_Word hwp_flags1; /* Extra flags. */ + Elf32_Word hwp_flags2; /* Extra flags. */ +} Elf_Options_Hw; + +/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ + +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA1_R4KEOP_CLEAN 0x00000002 + +/* MIPS relocs. */ + +#define R_MIPS_NONE 0 /* No reloc */ +#define R_MIPS_16 1 /* Direct 16 bit */ +#define R_MIPS_32 2 /* Direct 32 bit */ +#define R_MIPS_REL32 3 /* PC relative 32 bit */ +#define R_MIPS_26 4 /* Direct 26 bit shifted */ +#define R_MIPS_HI16 5 /* High 16 bit */ +#define R_MIPS_LO16 6 /* Low 16 bit */ +#define R_MIPS_GPREL16 7 /* GP relative 16 bit */ +#define R_MIPS_LITERAL 8 /* 16 bit literal entry */ +#define R_MIPS_GOT16 9 /* 16 bit GOT entry */ +#define R_MIPS_PC16 10 /* PC relative 16 bit */ +#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ +#define R_MIPS_GPREL32 12 /* GP relative 32 bit */ + +#define R_MIPS_SHIFT5 16 +#define R_MIPS_SHIFT6 17 +#define R_MIPS_64 18 +#define R_MIPS_GOT_DISP 19 +#define R_MIPS_GOT_PAGE 20 +#define R_MIPS_GOT_OFST 21 +#define R_MIPS_GOT_HI16 22 +#define R_MIPS_GOT_LO16 23 +#define R_MIPS_SUB 24 +#define R_MIPS_INSERT_A 25 +#define R_MIPS_INSERT_B 26 +#define R_MIPS_DELETE 27 +#define R_MIPS_HIGHER 28 +#define R_MIPS_HIGHEST 29 +#define R_MIPS_CALL_HI16 30 +#define R_MIPS_CALL_LO16 31 +#define R_MIPS_SCN_DISP 32 +#define R_MIPS_REL16 33 +#define R_MIPS_ADD_IMMEDIATE 34 +#define R_MIPS_PJUMP 35 +#define R_MIPS_RELGOT 36 +#define R_MIPS_JALR 37 +/* Keep this the last entry. */ +#define R_MIPS_NUM 38 + +/* Legal values for p_type field of Elf32_Phdr. */ + +#define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ +#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Special program header types. */ + +#define PF_MIPS_LOCAL 0x10000000 + +/* Legal values for d_tag field of Elf32_Dyn. */ + +#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ +#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ +#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ +#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ +#define DT_MIPS_FLAGS 0x70000005 /* Flags */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ +#define DT_MIPS_MSYM 0x70000007 +#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ +#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ +#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ +#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ +#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ +#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ +#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ +#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ +#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in + DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in + DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in + DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta + relocations refer to. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in + DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the + class declaration. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in + DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ +#define DT_MIPS_PIXIE_INIT 0x70000023 +#define DT_MIPS_SYMBOL_LIB 0x70000024 +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 +#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ +#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b +#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve + function stored in GOT. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added + by rld on dlopen() calls. */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ +#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ +#define DT_MIPS_NUM 0x32 + +/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ + +#define RHF_NONE 0 /* No flags */ +#define RHF_QUICKSTART (1 << 0) /* Use quickstart */ +#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ +#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ +#define RHF_NO_MOVE (1 << 3) +#define RHF_SGI_ONLY (1 << 4) +#define RHF_GUARANTEE_INIT (1 << 5) +#define RHF_DELTA_C_PLUS_PLUS (1 << 6) +#define RHF_GUARANTEE_START_INIT (1 << 7) +#define RHF_PIXIE (1 << 8) +#define RHF_DEFAULT_DELAY_LOAD (1 << 9) +#define RHF_REQUICKSTART (1 << 10) +#define RHF_REQUICKSTARTED (1 << 11) +#define RHF_CORD (1 << 12) +#define RHF_NO_UNRES_UNDEF (1 << 13) +#define RHF_RLD_ORDER_SAFE (1 << 14) + +/* Entries found in sections of type SHT_MIPS_LIBLIST. */ + +typedef struct +{ + Elf32_Word l_name; /* Name (string table index) */ + Elf32_Word l_time_stamp; /* Timestamp */ + Elf32_Word l_checksum; /* Checksum */ + Elf32_Word l_version; /* Interface version */ + Elf32_Word l_flags; /* Flags */ +} Elf32_Lib; + +typedef struct +{ + Elf64_Word l_name; /* Name (string table index) */ + Elf64_Word l_time_stamp; /* Timestamp */ + Elf64_Word l_checksum; /* Checksum */ + Elf64_Word l_version; /* Interface version */ + Elf64_Word l_flags; /* Flags */ +} Elf64_Lib; + + +/* Legal values for l_flags. */ + +#define LL_NONE 0 +#define LL_EXACT_MATCH (1 << 0) /* Require exact match */ +#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ +#define LL_REQUIRE_MINOR (1 << 2) +#define LL_EXPORTS (1 << 3) +#define LL_DELAY_LOAD (1 << 4) +#define LL_DELTA (1 << 5) + +/* Entries found in sections of type SHT_MIPS_CONFLICT. */ + +typedef Elf32_Addr Elf32_Conflict; + + +/* HPPA specific definitions. */ + +/* Legal values for e_flags field of Elf32_Ehdr. */ + +#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ +#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ +#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ +#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ +#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch + prediction. */ +#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ +#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ + +/* Defined values for `e_flags & EF_PARISC_ARCH' are: */ + +#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ +#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ +#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ + +/* Additional section indeces. */ + +#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared + symbols in ANSI C. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ + +/* Legal values for sh_type field of Elf32_Shdr. */ + +#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ +#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ +#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ + +/* Legal values for sh_flags field of Elf32_Shdr. */ + +#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ +#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ +#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ + +/* Legal values for ST_TYPE subfield of st_info (symbol type). */ + +#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ + +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +/* HPPA relocs. */ + +#define R_PARISC_NONE 0 /* No reloc. */ +#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ +#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ +#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ +#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ +#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ +#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ +#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ +#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ +#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ +#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ +#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ +#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ +#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ +#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ +#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ +#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ +#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ +#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ +#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ +#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ +#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ +#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ +#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ +#define R_PARISC_FPTR64 64 /* 64 bits function address. */ +#define R_PARISC_PLABEL32 65 /* 32 bits function address. */ +#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ +#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ +#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ +#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ +#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ +#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ +#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ +#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ +#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ +#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ +#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ +#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ +#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ +#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ +#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ +#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ +#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ +#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ +#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ +#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ +#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ +#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ +#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ +#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ +#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ +#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ +#define R_PARISC_LORESERVE 128 +#define R_PARISC_COPY 128 /* Copy relocation. */ +#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ +#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ +#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ +#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ +#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ +#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ +#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ +#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ +#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ +#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ +#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ +#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ +#define R_PARISC_HIRESERVE 255 + +/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ + +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) +#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) +#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) +#define PT_HP_STACK (PT_LOOS + 0x14) + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 + +/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ + +#define PF_PARISC_SBP 0x08000000 + +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Alpha specific definitions. */ + +/* Legal values for e_flags field of Elf64_Ehdr. */ + +#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ +#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ + +/* Legal values for sh_type field of Elf64_Shdr. */ + +/* These two are primerily concerned with ECOFF debugging info. */ +#define SHT_ALPHA_DEBUG 0x70000001 +#define SHT_ALPHA_REGINFO 0x70000002 + +/* Legal values for sh_flags field of Elf64_Shdr. */ + +#define SHF_ALPHA_GPREL 0x10000000 + +/* Legal values for st_other field of Elf64_Sym. */ +#define STO_ALPHA_NOPV 0x80 /* No PV required. */ +#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ + +/* Alpha relocs. */ + +#define R_ALPHA_NONE 0 /* No reloc */ +#define R_ALPHA_REFLONG 1 /* Direct 32 bit */ +#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ +#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ +#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ +#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ +#define R_ALPHA_GPDISP 6 /* Add displacement to GP */ +#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ +#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ +#define R_ALPHA_SREL16 9 /* PC relative 16 bit */ +#define R_ALPHA_SREL32 10 /* PC relative 32 bit */ +#define R_ALPHA_SREL64 11 /* PC relative 64 bit */ +#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ +#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ +#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ +#define R_ALPHA_COPY 24 /* Copy symbol at runtime */ +#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ +#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ +#define R_ALPHA_RELATIVE 27 /* Adjust by program base */ +#define R_ALPHA_TLS_GD_HI 28 +#define R_ALPHA_TLSGD 29 +#define R_ALPHA_TLS_LDM 30 +#define R_ALPHA_DTPMOD64 31 +#define R_ALPHA_GOTDTPREL 32 +#define R_ALPHA_DTPREL64 33 +#define R_ALPHA_DTPRELHI 34 +#define R_ALPHA_DTPRELLO 35 +#define R_ALPHA_DTPREL16 36 +#define R_ALPHA_GOTTPREL 37 +#define R_ALPHA_TPREL64 38 +#define R_ALPHA_TPRELHI 39 +#define R_ALPHA_TPRELLO 40 +#define R_ALPHA_TPREL16 41 +/* Keep this the last entry. */ +#define R_ALPHA_NUM 46 + +/* Magic values of the LITUSE relocation addend. */ +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLS_GD 4 +#define LITUSE_ALPHA_TLS_LDM 5 + + +/* PowerPC specific declarations */ + +/* Values for Elf32/64_Ehdr.e_flags. */ +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ + +/* Cygnus local bits below */ +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib + flag */ + +/* PowerPC relocations defined by the ABIs */ +#define R_PPC_NONE 0 +#define R_PPC_ADDR32 1 /* 32bit absolute address */ +#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ +#define R_PPC_ADDR16 3 /* 16bit absolute address */ +#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ +#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ +#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ +#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ +#define R_PPC_ADDR14_BRTAKEN 8 +#define R_PPC_ADDR14_BRNTAKEN 9 +#define R_PPC_REL24 10 /* PC relative 26 bit */ +#define R_PPC_REL14 11 /* PC relative 16 bit */ +#define R_PPC_REL14_BRTAKEN 12 +#define R_PPC_REL14_BRNTAKEN 13 +#define R_PPC_GOT16 14 +#define R_PPC_GOT16_LO 15 +#define R_PPC_GOT16_HI 16 +#define R_PPC_GOT16_HA 17 +#define R_PPC_PLTREL24 18 +#define R_PPC_COPY 19 +#define R_PPC_GLOB_DAT 20 +#define R_PPC_JMP_SLOT 21 +#define R_PPC_RELATIVE 22 +#define R_PPC_LOCAL24PC 23 +#define R_PPC_UADDR32 24 +#define R_PPC_UADDR16 25 +#define R_PPC_REL32 26 +#define R_PPC_PLT32 27 +#define R_PPC_PLTREL32 28 +#define R_PPC_PLT16_LO 29 +#define R_PPC_PLT16_HI 30 +#define R_PPC_PLT16_HA 31 +#define R_PPC_SDAREL16 32 +#define R_PPC_SECTOFF 33 +#define R_PPC_SECTOFF_LO 34 +#define R_PPC_SECTOFF_HI 35 +#define R_PPC_SECTOFF_HA 36 + +/* PowerPC relocations defined for the TLS access ABI. */ +#define R_PPC_TLS 67 /* none (sym+add)@tls */ +#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ +#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ +#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ +#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ +#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ +#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ +#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ +#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ +#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ + +/* Keep this the last entry. */ +#define R_PPC_NUM 95 + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ +#define R_PPC_EMB_NADDR32 101 +#define R_PPC_EMB_NADDR16 102 +#define R_PPC_EMB_NADDR16_LO 103 +#define R_PPC_EMB_NADDR16_HI 104 +#define R_PPC_EMB_NADDR16_HA 105 +#define R_PPC_EMB_SDAI16 106 +#define R_PPC_EMB_SDA2I16 107 +#define R_PPC_EMB_SDA2REL 108 +#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ +#define R_PPC_EMB_MRKREF 110 +#define R_PPC_EMB_RELSEC16 111 +#define R_PPC_EMB_RELST_LO 112 +#define R_PPC_EMB_RELST_HI 113 +#define R_PPC_EMB_RELST_HA 114 +#define R_PPC_EMB_BIT_FLD 115 +#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ + +/* Diab tool relocations. */ +#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ +#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ +#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ +#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ +#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ +#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ +#define R_PPC_TOC16 255 + + +/* PowerPC64 relocations defined by the ABIs */ +#define R_PPC64_NONE R_PPC_NONE +#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ +#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ +#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ +#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ +#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ +#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ +#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ +#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN +#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN +#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ +#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ +#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN +#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN +#define R_PPC64_GOT16 R_PPC_GOT16 +#define R_PPC64_GOT16_LO R_PPC_GOT16_LO +#define R_PPC64_GOT16_HI R_PPC_GOT16_HI +#define R_PPC64_GOT16_HA R_PPC_GOT16_HA + +#define R_PPC64_COPY R_PPC_COPY +#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT +#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT +#define R_PPC64_RELATIVE R_PPC_RELATIVE + +#define R_PPC64_UADDR32 R_PPC_UADDR32 +#define R_PPC64_UADDR16 R_PPC_UADDR16 +#define R_PPC64_REL32 R_PPC_REL32 +#define R_PPC64_PLT32 R_PPC_PLT32 +#define R_PPC64_PLTREL32 R_PPC_PLTREL32 +#define R_PPC64_PLT16_LO R_PPC_PLT16_LO +#define R_PPC64_PLT16_HI R_PPC_PLT16_HI +#define R_PPC64_PLT16_HA R_PPC_PLT16_HA + +#define R_PPC64_SECTOFF R_PPC_SECTOFF +#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO +#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI +#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA +#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ +#define R_PPC64_ADDR64 38 /* doubleword64 S + A */ +#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ +#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ +#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ +#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ +#define R_PPC64_UADDR64 43 /* doubleword64 S + A */ +#define R_PPC64_REL64 44 /* doubleword64 S + A - P */ +#define R_PPC64_PLT64 45 /* doubleword64 L + A */ +#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ +#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ +#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ +#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ +#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ +#define R_PPC64_TOC 51 /* doubleword64 .TOC */ +#define R_PPC64_PLTGOT16 52 /* half16* M + A */ +#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ +#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ +#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ + +#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ +#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ +#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ +#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ +#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ +#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ +#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ +#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ +#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ +#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ +#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ + +/* PowerPC64 relocations defined for the TLS access ABI. */ +#define R_PPC64_TLS 67 /* none (sym+add)@tls */ +#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ +#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ +#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ +#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ +#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ +#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ +#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ +#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ +#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ +#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ +#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ +#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ +#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ +#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ +#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ +#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ +#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ +#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ +#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ +#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ +#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ +#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ +#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ +#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ +#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ +#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ +#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ +#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ +#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ +#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ +#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ +#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ +#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ +#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ +#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ + +/* Keep this the last entry. */ +#define R_PPC64_NUM 107 + +/* PowerPC64 specific values for the Dyn d_tag field. */ +#define DT_PPC64_GLINK (DT_LOPROC + 0) +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) +#define DT_PPC64_NUM 3 + + +/* ARM specific declarations */ + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +/* NB. These conflict with values defined above. */ +#define EF_ARM_SYMSARESORTED 0x04 +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 +#define EF_ARM_MAPSYMSFIRST 0x10 +#define EF_ARM_EABIMASK 0XFF000000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 + +/* Additional symbol types for Thumb */ +#define STT_ARM_TFUNC 0xd + +/* ARM-specific values for sh_flags */ +#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ +#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined + in the input to a link step */ + +/* ARM-specific program header flags */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location + addressed by the static base */ + +/* ARM relocs. */ +#define R_ARM_NONE 0 /* No reloc */ +#define R_ARM_PC24 1 /* PC relative 26 bit branch */ +#define R_ARM_ABS32 2 /* Direct 32 bit */ +#define R_ARM_REL32 3 /* PC relative 32 bit */ +#define R_ARM_PC13 4 +#define R_ARM_ABS16 5 /* Direct 16 bit */ +#define R_ARM_ABS12 6 /* Direct 12 bit */ +#define R_ARM_THM_ABS5 7 +#define R_ARM_ABS8 8 /* Direct 8 bit */ +#define R_ARM_SBREL32 9 +#define R_ARM_THM_PC22 10 +#define R_ARM_THM_PC8 11 +#define R_ARM_AMP_VCALL9 12 +#define R_ARM_SWI24 13 +#define R_ARM_THM_SWI8 14 +#define R_ARM_XPC25 15 +#define R_ARM_THM_XPC22 16 +#define R_ARM_COPY 20 /* Copy symbol at runtime */ +#define R_ARM_GLOB_DAT 21 /* Create GOT entry */ +#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ +#define R_ARM_RELATIVE 23 /* Adjust by program base */ +#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ +#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ +#define R_ARM_GOT32 26 /* 32 bit GOT entry */ +#define R_ARM_PLT32 27 /* 32 bit PLT address */ +#define R_ARM_ALU_PCREL_7_0 32 +#define R_ARM_ALU_PCREL_15_8 33 +#define R_ARM_ALU_PCREL_23_15 34 +#define R_ARM_LDR_SBREL_11_0 35 +#define R_ARM_ALU_SBREL_19_12 36 +#define R_ARM_ALU_SBREL_27_20 37 +#define R_ARM_GNU_VTENTRY 100 +#define R_ARM_GNU_VTINHERIT 101 +#define R_ARM_THM_PC11 102 /* thumb unconditional branch */ +#define R_ARM_THM_PC9 103 /* thumb conditional branch */ +#define R_ARM_RXPC25 249 +#define R_ARM_RSBREL32 250 +#define R_ARM_THM_RPC22 251 +#define R_ARM_RREL32 252 +#define R_ARM_RABS22 253 +#define R_ARM_RPC24 254 +#define R_ARM_RBASE 255 +/* Keep this the last entry. */ +#define R_ARM_NUM 256 + +/* IA-64 specific declarations. */ + +/* Processor specific flags for the Ehdr e_flags field. */ +#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ +#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ +#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ + +/* Processor specific values for the Phdr p_type field. */ +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Processor specific flags for the Phdr p_flags field. */ +#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Shdr sh_type field. */ +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ + +/* Processor specific flags for the Shdr sh_flags field. */ +#define SHF_IA_64_SHORT 0x10000000 /* section near gp */ +#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ + +/* Processor specific values for the Dyn d_tag field. */ +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) +#define DT_IA_64_NUM 1 + +/* IA-64 relocations. */ +#define R_IA64_NONE 0x00 /* none */ +#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ +#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ +#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ +#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ +#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ +#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ +#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ +#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ +#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ +#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ +#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ +#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ +#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ +#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ +#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ +#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ +#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ +#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ +#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ +#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ +#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ +#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ +#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ +#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ +#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ +#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ +#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ +#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ +#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ +#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ +#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ +#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ +#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ +#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ +#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ +#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ +#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ +#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ +#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ +#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ +#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ +#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ +#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ +#define R_IA64_REL32MSB 0x6c /* data 4 + REL */ +#define R_IA64_REL32LSB 0x6d /* data 4 + REL */ +#define R_IA64_REL64MSB 0x6e /* data 8 + REL */ +#define R_IA64_REL64LSB 0x6f /* data 8 + REL */ +#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ +#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ +#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ +#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ +#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ +#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ +#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ +#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ +#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ +#define R_IA64_COPY 0x84 /* copy relocation */ +#define R_IA64_SUB 0x85 /* Addend and symbol difference */ +#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ +#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ +#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ +#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ +#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ +#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ +#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ +#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ +#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ +#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ +#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ +#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ +#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ +#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ +#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ +#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ +#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ + +/* SH specific declarations */ + +/* SH relocs. */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* Additional s390 relocs */ + +#define R_390_NONE 0 /* No reloc. */ +#define R_390_8 1 /* Direct 8 bit. */ +#define R_390_12 2 /* Direct 12 bit. */ +#define R_390_16 3 /* Direct 16 bit. */ +#define R_390_32 4 /* Direct 32 bit. */ +#define R_390_PC32 5 /* PC relative 32 bit. */ +#define R_390_GOT12 6 /* 12 bit GOT offset. */ +#define R_390_GOT32 7 /* 32 bit GOT offset. */ +#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ +#define R_390_COPY 9 /* Copy symbol at runtime. */ +#define R_390_GLOB_DAT 10 /* Create GOT entry. */ +#define R_390_JMP_SLOT 11 /* Create PLT entry. */ +#define R_390_RELATIVE 12 /* Adjust by program base. */ +#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ +#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ +#define R_390_GOT16 15 /* 16 bit GOT offset. */ +#define R_390_PC16 16 /* PC relative 16 bit. */ +#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ +#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ +#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ +#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ +#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ +#define R_390_64 22 /* Direct 64 bit. */ +#define R_390_PC64 23 /* PC relative 64 bit. */ +#define R_390_GOT64 24 /* 64 bit GOT offset. */ +#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ +#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ +#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ +#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ +#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ +#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ +#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ +#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ +#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ +#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ +#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ +#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ +#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ +#define R_390_TLS_GDCALL 38 /* Tag for function call in general + dynamic TLS code. */ +#define R_390_TLS_LDCALL 39 /* Tag for function call in local + dynamic TLS code. */ +#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic + thread local data. */ +#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic + thread local data. */ +#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS + block offset. */ +#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic + thread local data in LE code. */ +#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ +#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to + static TLS block. */ +#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS + block. */ +#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS + block. */ +#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ +#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ +#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS + block. */ + +/* Keep this the last entry. */ +#define R_390_NUM 57 + +/* CRIS relocations. */ +#define R_CRIS_NONE 0 +#define R_CRIS_8 1 +#define R_CRIS_16 2 +#define R_CRIS_32 3 +#define R_CRIS_8_PCREL 4 +#define R_CRIS_16_PCREL 5 +#define R_CRIS_32_PCREL 6 +#define R_CRIS_GNU_VTINHERIT 7 +#define R_CRIS_GNU_VTENTRY 8 +#define R_CRIS_COPY 9 +#define R_CRIS_GLOB_DAT 10 +#define R_CRIS_JUMP_SLOT 11 +#define R_CRIS_RELATIVE 12 +#define R_CRIS_16_GOT 13 +#define R_CRIS_32_GOT 14 +#define R_CRIS_16_GOTPLT 15 +#define R_CRIS_32_GOTPLT 16 +#define R_CRIS_32_GOTREL 17 +#define R_CRIS_32_PLT_GOTREL 18 +#define R_CRIS_32_PLT_PCREL 19 + +#define R_CRIS_NUM 20 + +/* AMD x86-64 relocations. */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative + offset to GOT */ +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ +#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ +#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ +#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ +#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset + to two GOT entries for GD symbol */ +#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset + to two GOT entries for LD symbol */ +#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ +#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset + to GOT entry for IE symbol */ +#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ + +#define R_X86_64_NUM 24 + +#endif /* elf.h */ diff --git a/common/libspumars/ppu/task/lib/task.c b/common/libspumars/ppu/task/lib/task.c new file mode 100644 index 00000000..efc84f73 --- /dev/null +++ b/common/libspumars/ppu/task/lib/task.c @@ -0,0 +1,391 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "mars/task.h" + +#include "elf.h" +#include "task_internal_types.h" + +extern const unsigned char mars_task_module_entry[]; + +static uint64_t task_exit_code_ea(uint64_t task_ea) +{ + return task_ea + offsetof(struct mars_task_context, exit_code); +} + +static int task_map_elf(struct mars_task_context *task, const void *elf_image) +{ + int ret, i; + int text_found = 0; + int data_found = 0; + Elf32_Ehdr *ehdr; + Elf32_Phdr *phdr; + + /* process elf header information */ + ehdr = (Elf32_Ehdr *)elf_image; + phdr = (Elf32_Phdr *)((void *)ehdr + ehdr->e_phoff); + + /* elf is not executable */ + if (ehdr->e_type != ET_EXEC) + return MARS_ERROR_FORMAT; + + /* iterate through program header segments */ + for (i = 0; i < ehdr->e_phnum; i++) { + /* readonly text segment */ + if (phdr->p_type == PT_LOAD && + phdr->p_flags == PF_R + PF_X && + phdr->p_align == 0x80) { + /* make sure base addr is what we expect */ + if (text_found || + phdr->p_vaddr != MARS_TASK_BASE_ADDR || + phdr->p_memsz != phdr->p_filesz) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + /* initialize the task context text info */ + task->text_ea = mars_ea_map((void *)ehdr + + phdr->p_offset, + phdr->p_filesz); + if (!task->text_ea) { + ret = MARS_ERROR_MEMORY; + goto error; + } + + task->text_vaddr = phdr->p_vaddr; + task->text_size = phdr->p_filesz; + + /* make sure we only find 1 text segment */ + text_found = 1; + /* read-write data segment */ + } else if (phdr->p_type == PT_LOAD && + phdr->p_flags == PF_R + PF_W && + phdr->p_align == 0x80) { + if (data_found) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + task->data_ea = mars_ea_map((void *)ehdr + + phdr->p_offset, + phdr->p_filesz); + if (!task->data_ea) { + ret = MARS_ERROR_MEMORY; + goto error; + } + + task->data_vaddr = phdr->p_vaddr; + task->data_size = phdr->p_filesz; + task->bss_size = phdr->p_memsz - phdr->p_filesz; + + /* make sure we only find 1 data segment */ + data_found = 1; + } + + /* increment program header */ + phdr = (void *)phdr + ehdr->e_phentsize; + } + + /* make sure text and data segment is found */ + if (!text_found || !data_found) { + ret = MARS_ERROR_FORMAT; + goto error; + } + + /* set the entry point of execution */ + task->entry = ehdr->e_entry; + + return MARS_SUCCESS; + +error: + if (text_found) + mars_ea_unmap(task->text_ea, task->text_size); + if (data_found) + mars_ea_unmap(task->data_ea, task->data_size); + + return ret; +} + +int mars_task_create(struct mars_context *mars, + struct mars_task_id *id_ret, + const char *name, const void *elf_image, + uint32_t context_save_size) +{ + int ret; + uint16_t workload_id; + uint64_t workload_ea; + struct mars_task_context *task; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!id_ret) + return MARS_ERROR_NULL; + if (!elf_image) + return MARS_ERROR_NULL; + if (name && strlen(name) > MARS_TASK_NAME_LEN_MAX) + return MARS_ERROR_PARAMS; + if (context_save_size > MARS_TASK_CONTEXT_SAVE_SIZE_MAX) + return MARS_ERROR_PARAMS; + + /* invalidate id */ + id_ret->mars_context_ea = 0; + + /* begin process to add the task to the workload queue */ + ret = mars_workload_queue_add_begin(mars, &workload_id, &workload_ea, + mars_task_module_entry, + MARS_TASK_MODULE_NAME); + if (ret != MARS_SUCCESS) + return ret; + + /* prepare work area for task context */ + task = mars_ea_work_area_get(workload_ea, + MARS_TASK_CONTEXT_ALIGN, + MARS_TASK_CONTEXT_SIZE); + + /* map task ELF */ + ret = task_map_elf(task, elf_image); + if (ret != MARS_SUCCESS) { + mars_workload_queue_add_end(mars, workload_id, 1); + return ret; + } + + /* initialize task id */ + task->id.mars_context_ea = mars_ptr_to_ea(mars); + task->id.workload_id = workload_id; + if (name) + strcpy((char *)task->id.name, name); + else + task->id.name[0] = 0; + + /* initialize task exit code */ + task->exit_code = 0; + + /* no context save - run complete */ + if (context_save_size) { + /* allocate context save area */ + task->context_save_area_ea = + mars_ea_memalign(MARS_TASK_CONTEXT_SAVE_ALIGN, + context_save_size + + MARS_TASK_REGISTER_SAVE_AREA_SIZE); + if (!task->context_save_area_ea) { + mars_workload_queue_add_end(mars, workload_id, 1); + return MARS_ERROR_MEMORY; + } + } else + task->context_save_area_ea = 0; + + /* update task context on EA */ + mars_ea_put(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + mars_ea_sync(); + + /* end process to add the task to the workload queue */ + ret = mars_workload_queue_add_end(mars, workload_id, 0); + if (ret != MARS_SUCCESS) { + mars_ea_free(task->context_save_area_ea); + mars_workload_queue_add_end(mars, workload_id, 1); + return ret; + } + + /* return id to caller */ + *id_ret = task->id; + + return MARS_SUCCESS; +} + +int mars_task_destroy(struct mars_task_id *id) +{ + int ret; + struct mars_context *mars; + struct mars_task_context *task; + uint64_t workload_ea; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + if (!id->mars_context_ea) + return MARS_ERROR_PARAMS; + + /* get mars context pointer from task id */ + mars = mars_ea_to_ptr(id->mars_context_ea); + + /* begin process to remove the task from the workload queue */ + ret = mars_workload_queue_remove_begin(mars, id->workload_id, + &workload_ea); + if (ret != MARS_SUCCESS) + return ret; + + /* prepare work area for task context */ + task = mars_ea_work_area_get(workload_ea, + MARS_TASK_CONTEXT_ALIGN, + MARS_TASK_CONTEXT_SIZE); + + /* get task context from EA */ + mars_ea_get(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + + /* free the allocated context save area if it has one */ + if (task->context_save_area_ea) + mars_ea_free(task->context_save_area_ea); + + /* unmap task ELF */ + mars_ea_unmap(task->text_ea, task->text_size); + mars_ea_unmap(task->data_ea, task->data_size); + + /* invalidate id */ + id->mars_context_ea = 0; + + /* end process to remove the task from the workload queue */ + return mars_workload_queue_remove_end(mars, id->workload_id, 0); +} + +int mars_task_schedule(const struct mars_task_id *id, + const struct mars_task_args *args, + uint8_t priority) +{ + int ret; + struct mars_context *mars; + struct mars_task_context *task; + uint64_t workload_ea; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + if (!id->mars_context_ea) + return MARS_ERROR_PARAMS; + + /* get mars context pointer from task id */ + mars = mars_ea_to_ptr(id->mars_context_ea); + + /* begin process to schedule the workload in the workload queue */ + ret = mars_workload_queue_schedule_begin(mars, id->workload_id, + priority, &workload_ea); + if (ret != MARS_SUCCESS) + return ret; + + /* prepare work area for task context */ + task = mars_ea_work_area_get(workload_ea, + MARS_TASK_CONTEXT_ALIGN, + MARS_TASK_CONTEXT_SIZE); + + /* get task context from EA */ + mars_ea_get(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + + /* initialize task specific context variables */ + task->stack = 0; + task->exit_code = 0; + if (args) + memcpy(&task->args, args, sizeof(struct mars_task_args)); + + /* update task context on EA */ + mars_ea_put(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + mars_ea_sync(); + + /* end process to schedule the workload in the workload queue */ + return mars_workload_queue_schedule_end(mars, id->workload_id, 0); +} + +int mars_task_unschedule(const struct mars_task_id *id, int32_t exit_code) +{ + int ret; + struct mars_context *mars; + struct mars_task_context *task; + uint64_t workload_ea; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + if (!id->mars_context_ea) + return MARS_ERROR_PARAMS; + + /* get mars context pointer from task id */ + mars = mars_ea_to_ptr(id->mars_context_ea); + + /* begin process to schedule the workload in the workload queue */ + ret = mars_workload_queue_unschedule_begin(mars, id->workload_id, + &workload_ea); + if (ret != MARS_SUCCESS) + return ret; + + /* prepare work area for task context */ + task = mars_ea_work_area_get(workload_ea, + MARS_TASK_CONTEXT_ALIGN, + MARS_TASK_CONTEXT_SIZE); + + /* get task context from EA */ + mars_ea_get(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + + /* store exit code in task context */ + task->exit_code = exit_code; + + /* update task context on EA */ + mars_ea_put(workload_ea, task, MARS_TASK_CONTEXT_SIZE); + mars_ea_sync(); + + /* end process to unschedule the workload in the workload queue */ + return mars_workload_queue_unschedule_end(mars, id->workload_id); +} + +int mars_task_wait(const struct mars_task_id *id, int32_t *exit_code) +{ + int ret; + struct mars_context *mars; + uint64_t workload_ea; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + if (!id->mars_context_ea) + return MARS_ERROR_PARAMS; + + /* get mars context pointer from task id */ + mars = mars_ea_to_ptr(id->mars_context_ea); + + /* blocking wait for workload completion */ + ret = mars_workload_queue_wait(mars, id->workload_id, &workload_ea); + if (ret != MARS_SUCCESS) + return ret; + + /* exit_code requested so return it to caller */ + if (exit_code) + *exit_code = mars_ea_get_uint32(task_exit_code_ea(workload_ea)); + + return MARS_SUCCESS; +} + +int mars_task_try_wait(const struct mars_task_id *id, int32_t *exit_code) +{ + int ret; + struct mars_context *mars; + uint64_t workload_ea; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + if (!id->mars_context_ea) + return MARS_ERROR_PARAMS; + + /* get mars context pointer from task id */ + mars = mars_ea_to_ptr(id->mars_context_ea); + + /* non-blocking wait for workload completion */ + ret = mars_workload_queue_try_wait(mars, id->workload_id, &workload_ea); + if (ret != MARS_SUCCESS) + return ret; + + /* exit_code requested so return it to caller */ + if (exit_code) + *exit_code = mars_ea_get_uint32(task_exit_code_ea(workload_ea)); + + return MARS_SUCCESS; +} + +uint32_t mars_task_get_ticks(void) +{ + return mars_get_ticks(); +} diff --git a/common/libspumars/ppu/task/lib/task_barrier.c b/common/libspumars/ppu/task/lib/task_barrier.c new file mode 100644 index 00000000..97e703ba --- /dev/null +++ b/common/libspumars/ppu/task/lib/task_barrier.c @@ -0,0 +1,111 @@ +#include +#include +#include + +#include "mars/task_barrier.h" + +#include "task_barrier_internal_types.h" + +int mars_task_barrier_create(struct mars_context *mars, + uint64_t *barrier_ea_ret, + uint32_t total) +{ + struct mars_task_barrier *barrier; + uint64_t barrier_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!barrier_ea_ret) + return MARS_ERROR_NULL; + if (!total || total > MARS_TASK_BARRIER_WAIT_MAX) + return MARS_ERROR_PARAMS; + + /* allocate barrier instance */ + barrier_ea = mars_ea_memalign(MARS_TASK_BARRIER_ALIGN, + MARS_TASK_BARRIER_SIZE); + if (!barrier_ea) + return MARS_ERROR_MEMORY; + + /* prepare work area for initialization */ + barrier = mars_ea_work_area_get(barrier_ea, + MARS_TASK_BARRIER_ALIGN, + MARS_TASK_BARRIER_SIZE); + + /* initialize barrier instance on work area */ + barrier->mars_context_ea = mars_ptr_to_ea(mars); + barrier->total = total; + barrier->notified_count = 0; + barrier->waited_count = 0; + barrier->notify_wait_count = 0; + barrier->wait_count = 0; + + /* update barrier on EA */ + mars_ea_put(barrier_ea, barrier, MARS_TASK_BARRIER_SIZE); + mars_ea_sync(); + + mars_mutex_reset(barrier_ea); + + /* return barrier instance pointer */ + *barrier_ea_ret = barrier_ea; + + return MARS_SUCCESS; +} + +int mars_task_barrier_initialize(uint64_t barrier_ea, + uint32_t total) +{ + struct mars_task_barrier *barrier; + + /* check function params */ + if (!barrier_ea) + return MARS_ERROR_NULL; + if (!total || total > MARS_TASK_BARRIER_WAIT_MAX) + return MARS_ERROR_PARAMS; + + /* prepare work area */ + barrier = mars_ea_work_area_get(barrier_ea, + MARS_TASK_BARRIER_ALIGN, + MARS_TASK_BARRIER_SIZE); + + mars_ea_get(barrier_ea, barrier, MARS_TASK_BARRIER_SIZE); + + /* initialize barrier instance on work area */ + barrier->total = total; + barrier->notified_count = 0; + barrier->waited_count = 0; + barrier->notify_wait_count = 0; + barrier->wait_count = 0; + + /* update barrier on EA */ + mars_ea_put(barrier_ea, barrier, MARS_TASK_BARRIER_SIZE); + mars_ea_sync(); + + mars_mutex_reset(barrier_ea); + + return MARS_SUCCESS; +} + +int mars_task_barrier_destroy(uint64_t barrier_ea) +{ + struct mars_task_barrier *barrier; + + /* check function params */ + if (!barrier_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + barrier = mars_ea_work_area_get(barrier_ea, + MARS_TASK_BARRIER_ALIGN, + MARS_TASK_BARRIER_SIZE); + + mars_ea_get(barrier_ea, barrier, MARS_TASK_BARRIER_SIZE); + + /* make sure no tasks in wait list */ + if (barrier->wait_count) + return MARS_ERROR_STATE; + + mars_ea_free(barrier_ea); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/task/lib/task_event_flag.c b/common/libspumars/ppu/task/lib/task_event_flag.c new file mode 100644 index 00000000..584b62c1 --- /dev/null +++ b/common/libspumars/ppu/task/lib/task_event_flag.c @@ -0,0 +1,314 @@ +#include + +#include +#include +#include +#include +#include + +#include "mars/task_event_flag.h" + +#include "task_event_flag_internal_types.h" + + +static inline uint64_t event_flag_bits_ea(uint64_t event_flag_ea) +{ + return event_flag_ea + + offsetof(struct mars_task_event_flag, bits); +} + +int mars_task_event_flag_create(struct mars_context *mars, + uint64_t *event_flag_ea_ret, + uint8_t direction, + uint8_t clear_mode) +{ + struct mars_task_event_flag *event_flag; + uint64_t event_flag_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!event_flag_ea_ret) + return MARS_ERROR_NULL; + if (direction != MARS_TASK_EVENT_FLAG_HOST_TO_MPU && + direction != MARS_TASK_EVENT_FLAG_MPU_TO_HOST && + direction != MARS_TASK_EVENT_FLAG_MPU_TO_MPU) + return MARS_ERROR_PARAMS; + if (clear_mode != MARS_TASK_EVENT_FLAG_CLEAR_AUTO && + clear_mode != MARS_TASK_EVENT_FLAG_CLEAR_MANUAL) + return MARS_ERROR_PARAMS; + + /* allocate event flag instance */ + event_flag_ea = mars_ea_memalign(MARS_TASK_EVENT_FLAG_ALIGN, + MARS_TASK_EVENT_FLAG_SIZE); + if (!event_flag_ea) + return MARS_ERROR_MEMORY; + + /* prepare work area for initialization */ + event_flag = mars_ea_work_area_get(event_flag_ea, + MARS_TASK_EVENT_FLAG_ALIGN, + MARS_TASK_EVENT_FLAG_SIZE); + + /* intialize event flag instance on work area */ + event_flag->mars_context_ea = mars_ptr_to_ea(mars); + event_flag->bits = 0; + event_flag->direction = direction; + event_flag->clear_mode = clear_mode; + event_flag->wait_count = 0; + + /* update event flag on EA */ + mars_ea_put(event_flag_ea, event_flag, MARS_TASK_EVENT_FLAG_SIZE); + mars_ea_sync(); + + mars_mutex_reset(event_flag_ea); + + /* return event flag instance pointer */ + *event_flag_ea_ret = event_flag_ea; + + return MARS_SUCCESS; +} + +int mars_task_event_flag_destroy(uint64_t event_flag_ea) +{ + struct mars_task_event_flag *event_flag; + + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + event_flag = mars_ea_work_area_get(event_flag_ea, + MARS_TASK_EVENT_FLAG_ALIGN, + MARS_TASK_EVENT_FLAG_SIZE); + + mars_ea_get(event_flag_ea, event_flag, MARS_TASK_EVENT_FLAG_SIZE); + + /* make sure no tasks in wait list */ + if (event_flag->wait_count) + return MARS_ERROR_STATE; + + mars_ea_free(event_flag_ea); + + return MARS_SUCCESS; +} + +int mars_task_event_flag_clear(uint64_t event_flag_ea, uint32_t bits) +{ + uint32_t new_bits; + uint64_t bits_ea; + + if (!event_flag_ea) + return MARS_ERROR_NULL; + + bits_ea = event_flag_bits_ea(event_flag_ea); + + mars_mutex_lock(event_flag_ea); + + /* clear the necessary bits */ + new_bits = mars_ea_get_uint32(bits_ea) & ~bits; + mars_ea_put_uint32(bits_ea, new_bits); + + mars_mutex_unlock(event_flag_ea); + + return MARS_SUCCESS; +} + +int mars_task_event_flag_set(uint64_t event_flag_ea, uint32_t bits) +{ + int ret; + int i; + struct mars_context *mars; + struct mars_task_event_flag *event_flag; + + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + event_flag = mars_ea_work_area_get(event_flag_ea, + MARS_TASK_EVENT_FLAG_ALIGN, + MARS_TASK_EVENT_FLAG_SIZE); + + /* get event flag from EA */ + mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)event_flag); + + /* check event flag status */ + ret = MARS_ERROR_NULL; + if (!event_flag->mars_context_ea) + goto end; + ret = MARS_ERROR_STATE; + if (event_flag->direction != MARS_TASK_EVENT_FLAG_HOST_TO_MPU) + goto end; + + /* get mars context pointer */ + mars = mars_ea_to_ptr(event_flag->mars_context_ea); + + /* set the necessary bits */ + event_flag->bits |= bits; + + /* save current set bits */ + bits = event_flag->bits; + + /* search through wait list for tasks to be signalled */ + for (i = 0; i < event_flag->wait_count; i++) { + /* check condition based on wait mode */ + switch (event_flag->wait_mask_mode[i]) { + case MARS_TASK_EVENT_FLAG_MASK_OR: + if ((bits & event_flag->wait_mask[i]) == 0) + continue; + break; + case MARS_TASK_EVENT_FLAG_MASK_AND: + if ((bits & event_flag->wait_mask[i]) != + event_flag->wait_mask[i]) + continue; + break; + } + + /* signal the task to go to ready state */ + ret = mars_workload_queue_signal_send(mars, + event_flag->wait_id[i]); + if (ret != MARS_SUCCESS) + goto end; + + /* flush id from wait list */ + event_flag->wait_count--; + memmove(&event_flag->wait_id[i], + &event_flag->wait_id[i + 1], + sizeof(uint16_t) * (event_flag->wait_count - i)); + memmove(&event_flag->wait_mask[i], + &event_flag->wait_mask[i + 1], + sizeof(uint32_t) * (event_flag->wait_count - i)); + memmove(&event_flag->wait_mask_mode[i], + &event_flag->wait_mask_mode[i + 1], + sizeof(uint8_t) * (event_flag->wait_count - i)); + i--; + } + + ret = MARS_SUCCESS; + +end: + mars_mutex_unlock_put(event_flag_ea, (struct mars_mutex *)event_flag); + + return ret; +} + +static int test_any_bits(uint32_t bits, void *param) +{ + const uint32_t *mask = (const uint32_t *)param; + + return (bits & *mask) ? MARS_SUCCESS : -1; +} + +static int test_all_bits(uint32_t bits, void *param) +{ + const uint32_t *mask = (const uint32_t *)param; + + return ((bits & *mask) == *mask) ? MARS_SUCCESS : -1; +} + +static int wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, uint32_t *bits, int try) +{ + int ret; + struct mars_task_event_flag *event_flag; + uint64_t bits_ea; + + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + event_flag = mars_ea_work_area_get(event_flag_ea, + MARS_TASK_EVENT_FLAG_ALIGN, + MARS_TASK_EVENT_FLAG_SIZE); + + /* get event flag from EA */ + mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)event_flag); + + /* check function params */ + ret = MARS_ERROR_STATE; + if (event_flag->direction != MARS_TASK_EVENT_FLAG_MPU_TO_HOST) + goto end; + ret = MARS_ERROR_PARAMS; + if (mask_mode != MARS_TASK_EVENT_FLAG_MASK_OR && + mask_mode != MARS_TASK_EVENT_FLAG_MASK_AND) + goto end; + + /* check condition based on wait mode */ + bits_ea = event_flag_bits_ea(event_flag_ea); + switch (mask_mode) { + case MARS_TASK_EVENT_FLAG_MASK_OR: + while ((event_flag->bits & mask) == 0) { + /* get current bits status if return bits requested */ + if (bits) + *bits = event_flag->bits; + + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)event_flag); + + /* only try so return busy */ + if (try) + return MARS_ERROR_BUSY; + + /* wait until condition is met */ + ret = mars_ea_cond_wait(bits_ea, test_any_bits, &mask); + if (ret) + return ret; + + mars_mutex_lock_get(event_flag_ea, + (struct mars_mutex *)event_flag); + } + break; + case MARS_TASK_EVENT_FLAG_MASK_AND: + while ((event_flag->bits & mask) != mask) { + /* get current bits status if return bits requested */ + if (bits) + *bits = event_flag->bits; + + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)event_flag); + + /* only try so return busy */ + if (try) + return MARS_ERROR_BUSY; + + /* wait until condition is met */ + ret = mars_ea_cond_wait(bits_ea, test_all_bits, &mask); + if (ret) + return ret; + + mars_mutex_lock_get(event_flag_ea, + (struct mars_mutex *)event_flag); + } + break; + } + + /* return bits if requested */ + if (bits) + *bits = event_flag->bits; + + /* clear event if clear mode is auto */ + if (event_flag->clear_mode == MARS_TASK_EVENT_FLAG_CLEAR_AUTO) + event_flag->bits &= ~mask; + + ret = MARS_SUCCESS; + +end: + mars_mutex_unlock_put(event_flag_ea, (struct mars_mutex *)event_flag); + + return ret; +} + +int mars_task_event_flag_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits) +{ + return wait(event_flag_ea, mask, mask_mode, bits, 0); +} + +int mars_task_event_flag_try_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits) +{ + return wait(event_flag_ea, mask, mask_mode, bits, 1); +} diff --git a/common/libspumars/ppu/task/lib/task_queue.c b/common/libspumars/ppu/task/lib/task_queue.c new file mode 100644 index 00000000..ecbbd867 --- /dev/null +++ b/common/libspumars/ppu/task/lib/task_queue.c @@ -0,0 +1,372 @@ +#include +#include +#include +#include +#include + +#include "mars/task_queue.h" + +#include "task_queue_internal_types.h" + +static inline uint64_t queue_count_ea(uint64_t queue_ea) +{ + return queue_ea + offsetof(struct mars_task_queue, count); +} + +int mars_task_queue_create(struct mars_context *mars, + uint64_t *queue_ea_ret, + uint32_t size, + uint32_t depth, + uint8_t direction) +{ + struct mars_task_queue *queue; + uint64_t queue_ea; + uint64_t buffer_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!queue_ea_ret) + return MARS_ERROR_NULL; + if (size & MARS_TASK_QUEUE_ENTRY_SIZE_MASK) + return MARS_ERROR_PARAMS; + if (size > MARS_TASK_QUEUE_ENTRY_SIZE_MAX) + return MARS_ERROR_PARAMS; + if (direction != MARS_TASK_QUEUE_HOST_TO_MPU && + direction != MARS_TASK_QUEUE_MPU_TO_HOST && + direction != MARS_TASK_QUEUE_MPU_TO_MPU) + return MARS_ERROR_PARAMS; + + /* allocate queue instance */ + queue_ea = mars_ea_memalign(MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + if (!queue_ea) + return MARS_ERROR_MEMORY; + + /* prepare work area for initialization */ + queue = mars_ea_work_area_get(queue_ea, + MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + + /* allocate queue buffer instance */ + buffer_ea = mars_ea_memalign(MARS_TASK_QUEUE_BUFFER_ALIGN, + size * depth); + if (!buffer_ea) { + mars_ea_free(queue_ea); + return MARS_ERROR_MEMORY; + } + + /* initialize queue instance */ + queue->mars_context_ea = mars_ptr_to_ea(mars); + queue->buffer_ea = buffer_ea; + queue->push_ea = buffer_ea; + queue->pop_ea = buffer_ea; + queue->size = size; + queue->depth = depth; + queue->direction = direction; + queue->count = 0; + queue->push_wait_count = 0; + queue->pop_wait_count = 0; + queue->push_wait_head = 0; + queue->pop_wait_head = 0; + + /* update queue on EA */ + mars_ea_put(queue_ea, queue, MARS_TASK_QUEUE_SIZE); + mars_ea_sync(); + + mars_mutex_reset(queue_ea); + + /* return queue instance pointer */ + *queue_ea_ret = queue_ea; + + return MARS_SUCCESS; +} + +int mars_task_queue_destroy(uint64_t queue_ea) +{ + struct mars_task_queue *queue; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + queue = mars_ea_work_area_get(queue_ea, + MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + + mars_ea_get(queue_ea, queue, MARS_TASK_QUEUE_SIZE); + + /* make sure no tasks in wait list */ + if (queue->push_wait_count || queue->pop_wait_count) + return MARS_ERROR_STATE; + + /* free shared memory */ + mars_ea_free(queue->buffer_ea); + mars_ea_free(queue_ea); + + return MARS_SUCCESS; +} + +int mars_task_queue_count(uint64_t queue_ea, uint32_t *count) +{ + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (!count) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* get queue from EA */ + mars_mutex_lock(queue_ea); + + /* return current items in queue */ + *count = mars_ea_get_uint32(queue_count_ea(queue_ea)); + + mars_mutex_unlock(queue_ea); + + return MARS_SUCCESS; +} + +int mars_task_queue_clear(uint64_t queue_ea) +{ + int i; + struct mars_context *mars; + struct mars_task_queue *queue; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* prepare work area */ + queue = mars_ea_work_area_get(queue_ea, + MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + + /* get mars context pointer */ + mars = mars_ea_to_ptr(queue->mars_context_ea); + + /* signal all waiting tasks that queue is ready for push */ + for (i = 0; i < queue->push_wait_count; i++) + mars_workload_queue_signal_send(mars, queue->push_wait_id[0]); + + /* flush all ids from push wait list */ + queue->push_wait_count = 0; + + /* clear the queue count and push/pop ea */ + queue->count = 0; + queue->push_ea = queue->buffer_ea; + queue->pop_ea = queue->buffer_ea; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + return MARS_SUCCESS; +} + +static void push_update(struct mars_task_queue *queue) +{ + struct mars_context *mars = mars_ea_to_ptr(queue->mars_context_ea); + + /* signal waiting task that queue is ready for pop */ + if (queue->pop_wait_count) { + /* signal waiting task */ + mars_workload_queue_signal_send(mars, + queue->pop_wait_id[queue->pop_wait_head]); + + /* flush id from pop wait list */ + queue->pop_wait_count--; + queue->pop_wait_head++; + queue->pop_wait_head %= MARS_TASK_QUEUE_WAIT_MAX; + } + + /* increment queue count */ + queue->count++; + + /* increment queue push ea */ + queue->push_ea += queue->size; + + /* wrap to front of queue if necessary */ + if (queue->push_ea == queue->buffer_ea + (queue->size * queue->depth)) + queue->push_ea = queue->buffer_ea; +} + +static int test_not_full(uint32_t count, void *param) +{ + const struct mars_task_queue *queue = + (const struct mars_task_queue *)param; + + return (count != queue->depth) ? MARS_SUCCESS : -1; +} + +static int push(uint64_t queue_ea, const void *data, int try) +{ + int ret; + struct mars_task_queue *queue; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* prepare work area */ + queue = mars_ea_work_area_get(queue_ea, + MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + + /* check queue status */ + ret = MARS_ERROR_STATE; + if (queue->direction != MARS_TASK_QUEUE_HOST_TO_MPU) + goto end; + + /* queue is full so wait */ + while (queue->count == queue->depth) { + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + /* only try so return busy */ + if (try) + return MARS_ERROR_BUSY; + + ret = mars_ea_cond_wait(queue_count_ea(queue_ea), + test_not_full, queue); + if (ret) + return ret; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + } + + /* copy data into queue */ + mars_ea_put(queue->push_ea, data, queue->size); + + /* update queue data */ + push_update(queue); + + ret = MARS_SUCCESS; +end: + mars_mutex_unlock_put(queue_ea, (struct mars_mutex*)queue); + + return ret; +} + +int mars_task_queue_push(uint64_t queue_ea, const void *data) +{ + return push(queue_ea, data, 0); +} + +int mars_task_queue_try_push(uint64_t queue_ea, const void *data) +{ + return push(queue_ea, data, 1); +} + +static void pop_update(struct mars_task_queue *queue) +{ + struct mars_context *mars = mars_ea_to_ptr(queue->mars_context_ea); + + /* signal waiting task that queue is ready for push */ + if (queue->push_wait_count) { + /* signal waiting task */ + mars_workload_queue_signal_send(mars, + queue->push_wait_id[queue->push_wait_head]); + + /* flush id from push wait list */ + queue->push_wait_count--; + queue->push_wait_head++; + queue->push_wait_head %= MARS_TASK_QUEUE_WAIT_MAX; + } + + /* decrement queue count */ + queue->count--; + + /* increment queue pop ea */ + queue->pop_ea += queue->size; + + /* wrap to front of queue if necessary */ + if (queue->pop_ea == queue->buffer_ea + (queue->size * queue->depth)) + queue->pop_ea = queue->buffer_ea; +} + +static int test_not_empty(uint32_t count, void *param) +{ + (void)param; + + return count ? MARS_SUCCESS : -1; +} + +static int pop(uint64_t queue_ea, void *data, int peek, int try) +{ + int ret; + struct mars_task_queue *queue; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* prepare work area */ + queue = mars_ea_work_area_get(queue_ea, + MARS_TASK_QUEUE_ALIGN, + MARS_TASK_QUEUE_SIZE); + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + + ret = MARS_ERROR_STATE; + if (queue->direction != MARS_TASK_QUEUE_MPU_TO_HOST) + goto end; + + /* queue is empty so wait */ + while (!queue->count) { + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + /* only try so return busy */ + if (try) + return MARS_ERROR_BUSY; + + ret = mars_ea_cond_wait(queue_count_ea(queue_ea), + test_not_empty, queue); + if (ret) + return ret; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + } + + /* copy data from queue */ + mars_ea_get(queue->pop_ea, data, queue->size); + + /* update queue data only if this is not a peek operation */ + if (!peek) + pop_update(queue); + + ret = MARS_SUCCESS; +end: + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + return ret; +} + +int mars_task_queue_pop(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 0, 0); +} + +int mars_task_queue_try_pop(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 0, 1); +} + +int mars_task_queue_peek(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 1, 0); +} + +int mars_task_queue_try_peek(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 1, 1); +} diff --git a/common/libspumars/ppu/task/lib/task_semaphore.c b/common/libspumars/ppu/task/lib/task_semaphore.c new file mode 100644 index 00000000..c5200937 --- /dev/null +++ b/common/libspumars/ppu/task/lib/task_semaphore.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "mars/task_semaphore.h" + +#include "task_semaphore_internal_types.h" + +int mars_task_semaphore_create(struct mars_context *mars, + uint64_t *semaphore_ea_ret, + int32_t count) +{ + struct mars_task_semaphore *semaphore; + uint64_t semaphore_ea; + + /* check function params */ + if (!mars) + return MARS_ERROR_NULL; + if (!semaphore_ea_ret) + return MARS_ERROR_NULL; + + /* allocate semaphore instance */ + semaphore_ea = mars_ea_memalign(MARS_TASK_SEMAPHORE_ALIGN, + MARS_TASK_SEMAPHORE_SIZE); + if (!semaphore_ea) + return MARS_ERROR_MEMORY; + + /* prepare work area for initialization */ + semaphore = mars_ea_work_area_get(semaphore_ea, + MARS_TASK_SEMAPHORE_ALIGN, + MARS_TASK_SEMAPHORE_SIZE); + + /* initialize semaphore instance */ + semaphore->mars_context_ea = mars_ptr_to_ea(mars); + semaphore->count = count; + semaphore->wait_count = 0; + semaphore->wait_head = 0; + + /* update semaphore on EA */ + mars_ea_put(semaphore_ea, semaphore, MARS_TASK_SEMAPHORE_SIZE); + mars_ea_sync(); + + mars_mutex_reset(semaphore_ea); + + /* return semaphore instance */ + *semaphore_ea_ret = semaphore_ea; + + return MARS_SUCCESS; +} + +int mars_task_semaphore_destroy(uint64_t semaphore_ea) +{ + struct mars_task_semaphore *semaphore; + + /* check function params */ + if (!semaphore_ea) + return MARS_ERROR_NULL; + + /* prepare work area */ + semaphore = mars_ea_work_area_get(semaphore_ea, + MARS_TASK_SEMAPHORE_ALIGN, + MARS_TASK_SEMAPHORE_SIZE); + + mars_ea_get(semaphore_ea, semaphore, MARS_TASK_SEMAPHORE_SIZE); + + /* make sure no tasks in wait list */ + if (semaphore->wait_count) + return MARS_ERROR_STATE; + + mars_ea_free(semaphore_ea); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/ppu/task/lib/task_signal.c b/common/libspumars/ppu/task/lib/task_signal.c new file mode 100644 index 00000000..69bf2d08 --- /dev/null +++ b/common/libspumars/ppu/task/lib/task_signal.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +#include "mars/task_signal.h" + +int mars_task_signal_send(struct mars_task_id *id) +{ + int ret; + struct mars_context *mars; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + /* get mars context pointer */ + mars = mars_ea_to_ptr(id->mars_context_ea); + if (!mars) + return MARS_ERROR_PARAMS; + + /* send signal to workload */ + ret = mars_workload_queue_signal_send(mars, id->workload_id); + if (ret != MARS_SUCCESS) + return ret; + + return MARS_SUCCESS; +} diff --git a/common/libspumars/spu/Makefile b/common/libspumars/spu/Makefile new file mode 100644 index 00000000..b55884ca --- /dev/null +++ b/common/libspumars/spu/Makefile @@ -0,0 +1,136 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/spu_rules + +BUILD := build + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPF := $(BASEDIR)/deps +export LIBF := $(BASEDIR)/lib + +export LD := $(CC) + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBF)/$(PLATFORM) +export DEPSDIR := $(DEPF)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +LIBRARY := $(LIBDIR)/libspumars +KERNELMODULE := $(LIBF)/mars_kernel +TASKMODULE := $(LIBF)/mars_task_module + +#--------------------------------------------------------------------------------- +INCLUDES := -I$(BASEDIR) \ + -I$(BASEDIR)/../include/common \ + -I$(BASEDIR)/../include/spu \ + -I$(BASEDIR)/../base/common \ + -I$(BASEDIR)/../task/common \ + -I$(BASEDIR)/../../../spu/include + +LIBS := -lsputhread +LIBPATHS := -L$(BASEDIR)/../../../spu/libsputhread/lib/spu + +CFLAGS := -Wall -ffunction-sections -fdata-sections $(MACHDEP) -DLIBSPUMARS_INTERNAL $(INCLUDES) +ASFLAGS := $(MACHDEP) -D__ASSEMBLY__ $(INCLUDES) + +#--------------------------------------------------------------------------------- +VPATH := $(BASEDIR) \ + $(BASEDIR)/base/lib \ + $(BASEDIR)/base/kernel \ + $(BASEDIR)/task/lib \ + $(BASEDIR)/task/module + +#--------------------------------------------------------------------------------- +OBJS_LIB := module.o \ + task.o task_barrier.o task_event_flag.o \ + task_queue.o task_semaphore.o task_signal.o + +OBJS_KERNEL := kernel_crt.o switch.o kernel.o dma.o mutex.o + +OBJS_MODULE := task_switch.o task_module.o + +all: spu + +#--------------------------------------------------------------------------------- +spu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBF)/spu ] || mkdir -p $(LIBF)/spu + @[ -d $(DEPF)/spu ] || mkdir -p $(DEPF)/spu + @[ -d spu ] || mkdir -p spu + @$(MAKE) PLATFORM=spu lib -C spu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install-header: +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/spu/include ] || mkdir -p $(PSL1GHT)/spu/include + @cp -frv $(CURDIR)/../include/common/mars $(PSL1GHT)/spu/include + @cp -frv $(CURDIR)/../include/spu/mars $(PSL1GHT)/spu/include + +#--------------------------------------------------------------------------------- +install: all install-header +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/spu/lib ] || mkdir -p $(PSL1GHT)/spu/lib + @cp -frv $(CURDIR)/lib/spu/*.a $(PSL1GHT)/spu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: CFLAGS += -Os --param max-inline-insns-single=20 +$(LIBRARY).a: $(OBJS_LIB) + +$(KERNELMODULE).elf: CFLAGS += -Os -mfixed-range=80-127 -funroll-loops -fschedule-insns +$(KERNELMODULE).elf: $(OBJS_KERNEL) + @echo linking ... $(notdir $@) + $(VERB) $(LD) $^ -nostdlib \ + -Wl,--defsym=__stack=0x29f0 \ + -Wl,-Map -Wl,$(CURDIR)/$(notdir $@).map -Wl,--cref \ + -Wl,--gc-sections \ + -Wl,--sort-common \ + -Wl,--sort-section -Wl,alignment \ + -Wl,-N \ + $(LIBPATHS) $(LIBS) -o $@ + +$(TASKMODULE).elf: CFLAGS += -Os -mfixed-range=80-127 -funroll-loops -fschedule-insns +$(TASKMODULE).elf: $(OBJS_MODULE) + @echo linking ... $(notdir $@) + $(VERB) $(LD) $^ -nodefaultlibs \ + -Wl,--defsym=__stack=0x3fe0 -Wl,-Ttext-segment=0x2a00 \ + -Wl,--entry,mars_module_entry -Wl,-u,mars_module_entry \ + -Wl,-Map -Wl,$(CURDIR)/$(notdir $@).map -Wl,--cref \ + -Wl,--gc-sections \ + -Wl,--sort-common \ + -Wl,--sort-section -Wl,alignment \ + $(LIBPATHS) $(LIBS) -L$(LIBDIR) -lspumars -o $@ + +#--------------------------------------------------------------------------------- + +.PHONY: lib spu install + +#--------------------------------------------------------------------------------- +lib: $(LIBRARY).a $(KERNELMODULE).elf $(TASKMODULE).elf +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf spu + @rm -rf $(DEPF) + @rm -rf $(LIBF) + +-include $(DEPSDIR)/*.d diff --git a/common/libspumars/spu/base/kernel/dma.c b/common/libspumars/spu/base/kernel/dma.c new file mode 100644 index 00000000..72e72b6e --- /dev/null +++ b/common/libspumars/spu/base/kernel/dma.c @@ -0,0 +1,59 @@ +#include +#include + +#include + +#include "kernel_internal_types.h" + +#define MARS_DMA_TAG_MAX 31 +#define MARS_DMA_SIZE_MAX 16384 +#define MARS_DMA_ALIGN_MASK 0xf + +static int dma_large(void *ls, uint64_t ea, uint32_t size, uint32_t tag, unsigned int dma_cmd) +{ + unsigned int cmd = MFC_CMD_WORD(0, 0, dma_cmd); + + if (tag > MARS_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + if (((uintptr_t)ls & MARS_DMA_ALIGN_MASK) || + ((uintptr_t)ea & MARS_DMA_ALIGN_MASK)) + return MARS_ERROR_ALIGN; + + while (size) { + unsigned int block_size; + + block_size = (size < MARS_DMA_SIZE_MAX) ? + size : MARS_DMA_SIZE_MAX; + + spu_mfcdma64((volatile void *)ls, mfc_ea2h(ea), mfc_ea2l(ea), + block_size, tag, cmd); + + ls += block_size; + ea += block_size; + size -= block_size; + } + + return MARS_SUCCESS; +} + +int dma_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag) +{ + return dma_large(ls, ea, size, tag, MFC_GET_CMD); +} + +int dma_put(const void *ls, uint64_t ea, uint32_t size, uint32_t tag) +{ + return dma_large((void *)ls, ea, size, tag, MFC_PUT_CMD); +} + +int dma_wait(uint32_t tag) +{ + if (tag > MARS_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + mfc_write_tag_mask(1 << tag); + mfc_write_tag_update_all(); + mfc_read_tag_status(); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/spu/base/kernel/kernel.c b/common/libspumars/spu/base/kernel/kernel.c new file mode 100644 index 00000000..f4149a12 --- /dev/null +++ b/common/libspumars/spu/base/kernel/kernel.c @@ -0,0 +1,1065 @@ +#include +#include +#include + +#include +#include + +#include + +#include + +#include "callback_internal_types.h" +#include "kernel_internal_types.h" +#include "workload_internal_types.h" + +#define MARS_KERNEL_STATUS_EXIT 0x1 +#define MARS_KERNEL_STATUS_IDLE 0x2 +#define MARS_KERNEL_STATUS_BUSY 0x4 +#define MARS_KERNEL_STATUS_RETRY 0x8 + +#define MARS_KERNEL_UPDATE_HEADER_BITS_ACCESS 0x0 +#define MARS_KERNEL_UPDATE_HEADER_BITS_STATE 0x1 +#define MARS_KERNEL_UPDATE_HEADER_BITS_COUNTER 0x2 +#define MARS_KERNEL_UPDATE_HEADER_BITS_COUNTER_RESET 0x4 + +/* kernel */ +union mars_kernel_buffer kernel_buffer; +static struct mars_kernel_params kernel_params; +static uint64_t kernel_params_ea; + +/* workload queue */ +static struct mars_workload_queue_header queue_header; +static struct mars_workload_queue_block queue_block; + +/* workload */ +static struct mars_workload_context workload_buf; +static struct mars_workload_context workload; +static uint16_t workload_id; +static uint64_t workload_ea; +static uint8_t workload_state; +static uint8_t workload_is_cached; + +/* workload module */ +static struct mars_workload_module cached_workload_module; +static struct mars_workload_module *workload_module; +static uint8_t workload_module_is_cached; + +/* workload module entry */ +typedef void (*module_entry)(const struct mars_kernel_syscalls *kernel_syscalls); + +/* defined in switch.S */ +extern void workload_run(void); +extern void workload_exit(uint8_t state); + +/* called by switch.S */ +void __workload_run(void); +void __workload_exit(uint8_t state); + +static void kernel_memcpy(void *dst, const void *src, int size) +{ + __vector const int *vptr_src = (__vector const int *)src; + __vector int *vptr_dst = (__vector int *)dst; + __vector int *vptr_end = (__vector int *)(dst + size); + + while (__builtin_expect(vptr_dst < vptr_end, 1)) + *vptr_dst++ = *vptr_src++; +} + +static int kernel_memcmp(const void *s1, const void *s2, int size) +{ + unsigned int offset1, offset2; + __vector int n_v; + __vector unsigned char shuffle1, shuffle2; + __vector const unsigned char *vptr_1 = (__vector const unsigned char*)s1; + __vector const unsigned char *vptr_2 = (__vector const unsigned char*)s2; + __vector unsigned int neq_v, tmp1_v, shift_n_v, mask_v, gt_v, lt_v; + __vector unsigned char data1A, data1B, data1, data2A, data2B, data2; + + n_v = spu_promote(size, 0); + data1 = data2 = spu_splats((unsigned char)0); + + offset1 = (unsigned int)(vptr_1)&15; + offset2 = (unsigned int)(vptr_2)&15; + + shuffle1 = (__vector unsigned char)spu_add((__vector unsigned int)spu_splats((unsigned char)offset1), + ((__vector unsigned int) {0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F})); + shuffle2 = (__vector unsigned char)spu_add((__vector unsigned int)spu_splats((unsigned char)offset2), + ((__vector unsigned int) {0x00010203, 0x04050607, 0x08090A0B, 0x0C0D0E0F})); + + data1A = *vptr_1++; + data2A = *vptr_2++; + do { + data1B = *vptr_1++; + data2B = *vptr_2++; + + data1 = spu_shuffle(data1A, data1B, shuffle1); + data2 = spu_shuffle(data2A, data2B, shuffle2); + + data1A = data1B; + data2A = data2B; + + neq_v = spu_gather(spu_xor(spu_cmpeq(data1, data2), -1)); + n_v = spu_add(n_v, -16); + tmp1_v = spu_cmpeq(neq_v, 0); + tmp1_v = spu_and(tmp1_v, spu_cmpgt(n_v, 0)); + } while(spu_extract(tmp1_v, 0)); + + mask_v = spu_splats((unsigned int)0xFFFF); + shift_n_v = spu_andc((__vector unsigned int)spu_sub(0, n_v), spu_cmpgt(n_v, -1)); + mask_v = spu_and(spu_sl(mask_v, spu_extract(shift_n_v, 0)), mask_v); + + gt_v = spu_gather(spu_cmpgt(data1, data2)); + lt_v = spu_gather(spu_cmpgt(data2, data1)); + gt_v = spu_sub(-1, spu_sl(spu_cmpgt(gt_v, lt_v), 1)); + + mask_v = spu_cmpeq(spu_and(neq_v, mask_v), 0); + return (spu_extract(spu_andc(gt_v, mask_v), 0)); +} + +static uint32_t get_ticks() +{ + return kernel_params.kernel_ticks.offset - spu_read_decrementer(); +} + +static uint64_t get_mars_context_ea(void) +{ + return kernel_params.mars_context_ea; +} + +static uint16_t get_kernel_id(void) +{ + return kernel_params.kernel_id; +} + +static uint16_t get_workload_id(void) +{ + return workload_id; +} + +static struct mars_workload_context *get_workload(void) +{ + return &workload; +} + + +static uint64_t get_workload_ea(uint16_t id) +{ + int context_index = id - (id / MARS_WORKLOAD_PER_BLOCK) - 1; + + return queue_header.context_ea + + context_index * MARS_WORKLOAD_CONTEXT_SIZE; + +} + +static struct mars_workload_context *get_workload_by_id(uint16_t id) +{ + static struct mars_workload_context ret_workload; + + /* id is caller workload's id so return current workload */ + if (id == workload_id) + return &workload; + + /* get the workload context from workload queue */ + dma_get(&ret_workload, get_workload_ea(id), MARS_WORKLOAD_CONTEXT_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + return &ret_workload; +} + +static uint64_t get_block_ea(int block) +{ + return queue_header.queue_ea + + offsetof(struct mars_workload_queue, block) + + MARS_WORKLOAD_QUEUE_BLOCK_SIZE * block; +} + +static uint64_t get_block_bits(uint16_t id) +{ + int block; + int index; + uint64_t block_ea; + uint64_t block_bits; + + /* check function params */ + if (id > MARS_WORKLOAD_ID_MAX || !(id % MARS_WORKLOAD_PER_BLOCK)) + return 0; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* calculate block ea */ + block_ea = get_block_ea(block); + + /* lock the queue block */ + mutex_lock_get(block_ea, (struct mars_mutex *)&queue_block); + + block_bits = queue_block.bits[index]; + + /* unlock the queue block */ + mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block); + + return block_bits; +} + +static void update_header_bits(int mode, int block) +{ + int index; + uint16_t *block_bits = &queue_header.bits[block]; + uint8_t block_ready = MARS_WORKLOAD_BLOCK_READY_OFF; + uint8_t block_waiting = MARS_WORKLOAD_BLOCK_WAITING_OFF; + uint8_t block_priority = MARS_WORKLOAD_BLOCK_PRIORITY_MIN; + uint8_t block_counter = MARS_WORKLOAD_BLOCK_COUNTER_MIN; + + if (mode & MARS_KERNEL_UPDATE_HEADER_BITS_STATE) { + /* search through currently locked queue block workload bits */ + for (index = 1; index < MARS_WORKLOAD_PER_BLOCK; index++) { + uint64_t *bits = &queue_block.bits[index]; + uint8_t state = MARS_BITS_GET(bits, WORKLOAD_STATE); + + /* workload state is ready so check priority */ + if (state & MARS_WORKLOAD_STATE_READY) { + uint8_t priority = + MARS_BITS_GET(bits, WORKLOAD_PRIORITY); + + /* set block priority if higher then current */ + if (priority > block_priority) + block_priority = priority; + + /* set block ready bit in header bits */ + block_ready = MARS_WORKLOAD_BLOCK_READY_ON; + } else if (state & MARS_WORKLOAD_STATE_WAITING) { + /* set block waiting bit in header bits */ + block_waiting = MARS_WORKLOAD_BLOCK_WAITING_ON; + } + } + } + + /* lock the queue header */ + mutex_lock_get(kernel_params.workload_queue_ea, + (struct mars_mutex *)&queue_header); + + /* update header bits state */ + if (mode & MARS_KERNEL_UPDATE_HEADER_BITS_STATE) { + /* set the info bits inside queue header for this queue block */ + MARS_BITS_SET(block_bits, BLOCK_READY, block_ready); + MARS_BITS_SET(block_bits, BLOCK_WAITING, block_waiting); + MARS_BITS_SET(block_bits, BLOCK_PRIORITY, block_priority); + /* update header bits counter */ + } else if (mode) { + /* reset is not specified so increment current block counter */ + if (mode & MARS_KERNEL_UPDATE_HEADER_BITS_COUNTER) { + block_counter = + MARS_BITS_GET(block_bits, BLOCK_COUNTER); + if (block_counter < MARS_WORKLOAD_BLOCK_COUNTER_MAX) + block_counter++; + } + + /* set the block counter bits */ + MARS_BITS_SET(block_bits, BLOCK_COUNTER, block_counter); + } + + /* increment the header access value */ + queue_header.access++; + + /* unlock the queue header */ + mutex_unlock_put(kernel_params.workload_queue_ea, + (struct mars_mutex *)&queue_header); +} + +static int change_bits(uint16_t id, + int (*check_bits)(uint64_t bits, uint64_t param), + uint64_t check_bits_param, + uint64_t (*set_bits)(uint64_t bits, uint64_t param), + uint64_t set_bits_param, + void (*callback)(uint16_t id)) +{ + int block; + int index; + uint64_t block_ea; + uint64_t bits; + + /* check function params */ + if (id > MARS_WORKLOAD_ID_MAX || !(id % MARS_WORKLOAD_PER_BLOCK)) + return MARS_ERROR_PARAMS; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* calculate block ea */ + block_ea = get_block_ea(block); + + /* lock the queue block */ + mutex_lock_get(block_ea, (struct mars_mutex *)&queue_block); + + /* check for valid state */ + if (check_bits && + !(*check_bits)(queue_block.bits[index], check_bits_param)) { + mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block); + return MARS_ERROR_STATE; + } + + /* reset workload queue bits and set state to new state */ + bits = (*set_bits)(queue_block.bits[index], set_bits_param); + + /* store new bits into queue block */ + queue_block.bits[index] = bits; + + /* if callback requested call it */ + if (callback) + (*callback)(id); + + /* unlock the queue block */ + mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block); + + return MARS_SUCCESS; +} + +static int check_state_bits(uint64_t bits, uint64_t state) +{ + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) == state); +} + +static int check_state_bits_not(uint64_t bits, uint64_t state) +{ + return !check_state_bits(bits, state); +} + +static uint64_t set_state_bits(uint64_t bits, uint64_t state) +{ + MARS_BITS_SET(&bits, WORKLOAD_STATE, state); + + return bits; +} + +static int change_state(uint16_t id, + unsigned int old_state, + unsigned int new_state, + void (*callback)(uint16_t id)) +{ + return change_bits(id, + check_state_bits, old_state, + set_state_bits, new_state, + callback); +} + +static int workload_query(uint16_t id, int query) +{ + uint64_t bits = get_block_bits(id); + + switch (query) { + case MARS_WORKLOAD_QUERY_IS_MODULE_CACHED: + return workload_module_is_cached; + case MARS_WORKLOAD_QUERY_IS_CONTEXT_CACHED: + return (id == workload_id && workload_is_cached); + case MARS_WORKLOAD_QUERY_IS_INITIALIZED: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE)); + case MARS_WORKLOAD_QUERY_IS_READY: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) & + MARS_WORKLOAD_STATE_READY); + case MARS_WORKLOAD_QUERY_IS_WAITING: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) & + MARS_WORKLOAD_STATE_WAITING); + case MARS_WORKLOAD_QUERY_IS_RUNNING: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) & + MARS_WORKLOAD_STATE_RUNNING); + case MARS_WORKLOAD_QUERY_IS_FINISHED: + return (MARS_BITS_GET(&bits, WORKLOAD_STATE) & + MARS_WORKLOAD_STATE_FINISHED); + case MARS_WORKLOAD_QUERY_IS_SIGNAL_SET: + return (MARS_BITS_GET(&bits, WORKLOAD_SIGNAL) & + MARS_WORKLOAD_SIGNAL_ON); + } + + return 0; +} + +static uint64_t set_wait_id_bits(uint64_t bits, uint64_t id) +{ + MARS_BITS_SET(&bits, WORKLOAD_WAIT_ID, id); + + return bits; +} + +static int workload_wait_set(uint16_t id) +{ + return change_bits(workload_id, + check_state_bits_not, MARS_WORKLOAD_STATE_NONE, + set_wait_id_bits, id, + NULL); +} + +static int workload_wait_reset(void) +{ + return change_bits(workload_id, + NULL, 0, + set_wait_id_bits, MARS_WORKLOAD_ID_NONE, + NULL); +} + +static uint64_t set_signal_bits(uint64_t bits, uint64_t signal) +{ + MARS_BITS_SET(&bits, WORKLOAD_SIGNAL, signal); + + /* update queue header bits access in case kernel is idle */ + update_header_bits(MARS_KERNEL_UPDATE_HEADER_BITS_ACCESS, 0); + + return bits; +} + +static int workload_signal_set(uint16_t id) +{ + return change_bits(id, + check_state_bits_not, MARS_WORKLOAD_STATE_NONE, + set_signal_bits, MARS_WORKLOAD_SIGNAL_ON, + NULL); +} + +static int workload_signal_reset(void) +{ + return change_bits(workload_id, + NULL, 0, + set_signal_bits, MARS_WORKLOAD_SIGNAL_OFF, + NULL); +} + +static void begin_callback(uint16_t id) +{ + /* get the workload context from workload queue */ + dma_get(&workload_buf, get_workload_ea(id), + MARS_WORKLOAD_CONTEXT_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + /* update queue header bits */ + update_header_bits(MARS_KERNEL_UPDATE_HEADER_BITS_STATE, + id / MARS_WORKLOAD_PER_BLOCK); +} + +static void end_callback(uint16_t id) +{ + /* put the workload context into workload queue */ + dma_put((void *)&workload_buf, get_workload_ea(id), + MARS_WORKLOAD_CONTEXT_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + /* update queue header bits */ + update_header_bits(MARS_KERNEL_UPDATE_HEADER_BITS_STATE, + id / MARS_WORKLOAD_PER_BLOCK); +} + +static uint64_t set_schedule_bits(uint64_t bits, uint64_t priority) +{ + /* set the info bits inside queue block for this workload */ + MARS_BITS_SET(&bits, WORKLOAD_STATE, MARS_WORKLOAD_STATE_SCHEDULING); + MARS_BITS_SET(&bits, WORKLOAD_PRIORITY, priority); + MARS_BITS_SET(&bits, WORKLOAD_COUNTER, MARS_WORKLOAD_COUNTER_MAX); + MARS_BITS_SET(&bits, WORKLOAD_SIGNAL, MARS_WORKLOAD_SIGNAL_OFF); + MARS_BITS_SET(&bits, WORKLOAD_WAIT_ID, MARS_WORKLOAD_ID_NONE); + + return bits; +} + +static int workload_schedule_begin(uint16_t id, uint8_t priority, + struct mars_workload_context **workload) +{ + int ret; + + /* change bits necessary to begin scheduling */ + ret = change_bits(id, + check_state_bits, MARS_WORKLOAD_STATE_FINISHED, + set_schedule_bits, priority, + begin_callback); + if (ret != MARS_SUCCESS) + return ret; + + /* if requested set workload context pointer to return */ + if (workload) + *workload = &workload_buf; + + return MARS_SUCCESS; +} + +static int workload_schedule_end(uint16_t id, int cancel) +{ + return change_state(id, + MARS_WORKLOAD_STATE_SCHEDULING, + cancel ? MARS_WORKLOAD_STATE_FINISHED : + MARS_WORKLOAD_STATE_READY, + end_callback); +} + +static int unscheduling_state_bits(uint64_t bits, uint64_t param) +{ + (void)param; + + uint8_t state = MARS_BITS_GET(&bits, WORKLOAD_STATE); + + return (state & (MARS_WORKLOAD_STATE_READY | + MARS_WORKLOAD_STATE_RUNNING | + MARS_WORKLOAD_STATE_WAITING)); +} + +static int workload_unschedule_begin(uint16_t id, + struct mars_workload_context **workload) +{ + int ret; + + /* change bits necessary to begin unscheduling */ + ret = change_bits(id, + unscheduling_state_bits, 0, + set_state_bits, MARS_WORKLOAD_STATE_UNSCHEDULING, + begin_callback); + if (ret != MARS_SUCCESS) + return ret; + + /* if requested set workload context pointer to return */ + if (workload) + *workload = &workload_buf; + + return MARS_SUCCESS; +} + +static void notify_host_bits(uint64_t block_ea, int index); + +static int workload_unschedule_end(uint16_t id) +{ + int ret; + int block; + int index; + uint64_t block_ea; + + ret = change_state(id, + MARS_WORKLOAD_STATE_UNSCHEDULING, + MARS_WORKLOAD_STATE_FINISHED, + end_callback); + if (ret != MARS_SUCCESS) + return ret; + + /* calculate block/index from id */ + block = id / MARS_WORKLOAD_PER_BLOCK; + index = id % MARS_WORKLOAD_PER_BLOCK; + + /* calculate block ea */ + block_ea = get_block_ea(block); + + /* notify host */ + notify_host_bits(block_ea, index); + + return MARS_SUCCESS; +} + +static void host_signal_send(uint64_t watch_point_ea) +{ + spu_thread_send_event(MARS_KERNEL_SPU_EVENT_PORT, (uint32_t)(watch_point_ea >> 32), (watch_point_ea & 0xffffffff)); +} + +static int host_callback_queue_push(void) +{ + uint64_t queue_ea = kernel_params.callback_queue_ea; + struct mars_callback_queue *queue = &kernel_buffer.callback_queue; + + /* lock the queue */ + mutex_lock_get(queue_ea, (struct mars_mutex *)queue); + + /* check if queue is full */ + if (queue->count == MARS_CALLBACK_QUEUE_MAX) { + mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + return MARS_ERROR_LIMIT; + } + + /* set the push flag to signal host of new item */ + queue->flag = MARS_CALLBACK_QUEUE_FLAG_PUSH; + + /* put workload id at tail of queue */ + queue->workload_id[queue->tail] = workload_id; + + /* increment count */ + queue->count++; + + /* increment tail */ + queue->tail++; + + /* wrap tail to front of queue if necessary */ + if (queue->tail == MARS_CALLBACK_QUEUE_MAX) + queue->tail = 0; + + /* unlock the queue */ + mutex_unlock_put(queue_ea, (struct mars_mutex *)queue); + + return MARS_SUCCESS; +} + +static int host_callback_set(uint64_t callback_ea, + const struct mars_callback_args *in) +{ + int ret; + struct mars_workload_callback *callback = + (struct mars_workload_callback *) + ((void *)&workload + MARS_WORKLOAD_MODULE_SIZE); + + /* set the callback function pointer into workload callback area */ + callback->callback_ea = callback_ea; + + /* input args specified so copy into workload data area */ + if (in) + kernel_memcpy(&callback->callback_args, in, + MARS_CALLBACK_ARGS_SIZE); + + /* push workload id to callback queue */ + ret = host_callback_queue_push(); + if (ret != MARS_SUCCESS) + return ret; + + /* notify host to process callback */ + host_signal_send(kernel_params.callback_queue_ea + + offsetof(struct mars_callback_queue, flag)); + + return MARS_SUCCESS; +} + +static int host_callback_reset(struct mars_callback_args *out) +{ + struct mars_workload_callback *callback = + (struct mars_workload_callback *) + ((void *)&workload + MARS_WORKLOAD_MODULE_SIZE); + + /* output requested so dma from workload data area */ + if (out) + kernel_memcpy(out, &callback->callback_args, + MARS_CALLBACK_ARGS_SIZE); + + return callback->callback_ret; +} + +static struct mars_kernel_syscalls kernel_syscalls = +{ + get_ticks, + get_mars_context_ea, + get_kernel_id, + get_workload_id, + get_workload, + get_workload_by_id, + workload_exit, + workload_query, + workload_wait_set, + workload_wait_reset, + workload_signal_set, + workload_signal_reset, + workload_schedule_begin, + workload_schedule_end, + workload_unschedule_begin, + workload_unschedule_end, + host_signal_send, + host_callback_set, + host_callback_reset, + mutex_lock_get, + mutex_unlock_put, + dma_get, + dma_put, + dma_wait +}; + +void __workload_run() +{ + /* call module entry function */ + ((module_entry)workload_module->entry)(&kernel_syscalls); +} + +void __workload_exit(uint8_t state) +{ + workload_state = state; +} + +static int search_block(int block, int ready) +{ + int i; + int index = -1; + uint8_t max_priority = 0; + uint16_t max_counter = 0; + uint64_t block_ea = get_block_ea(block); + + /* lock the queue block */ + mutex_lock_get(block_ea, (struct mars_mutex *)&queue_block); + + /* search through all workloads in block */ + for (i = 1; i < MARS_WORKLOAD_PER_BLOCK; i++) { + uint64_t *bits = &queue_block.bits[i]; + uint8_t state = MARS_BITS_GET(bits, WORKLOAD_STATE); + uint8_t priority = MARS_BITS_GET(bits, WORKLOAD_PRIORITY); + uint8_t signal = MARS_BITS_GET(bits, WORKLOAD_SIGNAL); + uint16_t wait_id = MARS_BITS_GET(bits, WORKLOAD_WAIT_ID); + uint16_t counter = MARS_BITS_GET(bits, WORKLOAD_COUNTER); + + /* found workload in ready state */ + if (ready && (state & MARS_WORKLOAD_STATE_READY)) { + /* compare priority and counter with previous ones */ + if (index < 0 || priority > max_priority || + (priority == max_priority && counter > max_counter)) { + index = i; + max_counter = counter; + max_priority = priority; + } + + /* increment wait counter without overflowing */ + if (counter < MARS_WORKLOAD_COUNTER_MAX) + MARS_BITS_SET(bits, WORKLOAD_COUNTER, + counter + 1); + /* found workload in waiting state */ + } else if (!ready && (state & MARS_WORKLOAD_STATE_WAITING)) { + /* waiting for workload to finish so check status */ + if (wait_id != MARS_WORKLOAD_ID_NONE) { + struct mars_workload_queue_block *wait_block; + uint8_t wait_state; + + int bl = wait_id / MARS_WORKLOAD_PER_BLOCK; + int id = wait_id % MARS_WORKLOAD_PER_BLOCK; + + /* check if workload id is in the same block */ + if (block != bl) { + /* set pointer to check buffer block */ + wait_block = + &kernel_buffer.workload_queue_block; + + /* fetch the necessary block */ + dma_get(wait_block, get_block_ea(bl), + MARS_WORKLOAD_QUEUE_BLOCK_SIZE, + MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + } else { + /* set pointer to check current block */ + wait_block = &queue_block; + } + + /* get state of workload its waiting for */ + wait_state = + MARS_BITS_GET(&wait_block->bits[id], + WORKLOAD_STATE); + + /* check if workload is finished and reset */ + if (wait_state & MARS_WORKLOAD_STATE_FINISHED) { + MARS_BITS_SET(bits, WORKLOAD_WAIT_ID, + MARS_WORKLOAD_ID_NONE); + MARS_BITS_SET(bits, WORKLOAD_STATE, + MARS_WORKLOAD_STATE_READY); + + index = i; + } + /* waiting for signal so check signal bit and reset */ + } else if (signal & MARS_WORKLOAD_SIGNAL_ON) { + MARS_BITS_SET(bits, WORKLOAD_SIGNAL, + MARS_WORKLOAD_SIGNAL_OFF); + MARS_BITS_SET(bits, WORKLOAD_STATE, + MARS_WORKLOAD_STATE_READY); + + index = i; + } + } + } + + /* index is set so reserve the runnable workload */ + if (index >= 0) { + if (ready) { + /* update the current state of the workload */ + MARS_BITS_SET(&queue_block.bits[index], + WORKLOAD_STATE, + MARS_WORKLOAD_STATE_RUNNING); + + /* reset the counter for reserved workload */ + MARS_BITS_SET(&queue_block.bits[index], + WORKLOAD_COUNTER, + MARS_WORKLOAD_COUNTER_MIN); + + /* check if kernel ran this workload most recently */ + workload_is_cached = + (workload_id == + MARS_WORKLOAD_PER_BLOCK * block + index) && + (kernel_params.kernel_id == + MARS_BITS_GET(&queue_block.bits[index], + WORKLOAD_KERNEL_ID)); + + /* set the kernel id of this kernel into block bits */ + MARS_BITS_SET(&queue_block.bits[index], + WORKLOAD_KERNEL_ID, + kernel_params.kernel_id); + + /* reset block counter */ + update_header_bits( + MARS_KERNEL_UPDATE_HEADER_BITS_COUNTER_RESET, + block); + } + + /* update queue header bits */ + update_header_bits(MARS_KERNEL_UPDATE_HEADER_BITS_STATE, block); + } + + /* unlock the queue block */ + mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block); + + /* returns -1 if no runnable workload found */ + return index; +} + +static void notify_host_bits(uint64_t block_ea, int index) +{ + uint64_t bits_ea = + block_ea + + offsetof(struct mars_workload_queue_block, bits) + + sizeof(uint64_t) * index; + + host_signal_send(bits_ea); +} + +static int workload_reserve(void) +{ + int i; + int block = -1; + int index; + int retry = 0; + uint8_t max_block_priority = 0; + uint16_t max_block_counter = 0; + + /* get the workload queue header */ + dma_get(&queue_header, kernel_params.workload_queue_ea, + MARS_WORKLOAD_QUEUE_HEADER_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + /* return exit status if exit flag is set from host */ + if (queue_header.flag & MARS_WORKLOAD_QUEUE_FLAG_EXIT) + return MARS_KERNEL_STATUS_EXIT; + + /* search workload queue header for highest priority ready block that + * has waited the longest in ready state */ + for (i = 0; i < MARS_WORKLOAD_NUM_BLOCKS; i++) { + uint16_t *bits = &queue_header.bits[i]; + uint8_t block_ready = MARS_BITS_GET(bits, BLOCK_READY); + uint8_t block_waiting = MARS_BITS_GET(bits, BLOCK_WAITING); + uint8_t block_priority = MARS_BITS_GET(bits, BLOCK_PRIORITY); + uint16_t block_counter = MARS_BITS_GET(bits, BLOCK_COUNTER); + + /* block is ready so check scheduling conditions */ + if (block_ready) { + if (block < 0 || block_priority > max_block_priority || + (block_priority == max_block_priority && + block_counter > max_block_counter)) { + block = i; + max_block_priority = block_priority; + max_block_counter = block_counter; + } + + /* increment block counter */ + update_header_bits( + MARS_KERNEL_UPDATE_HEADER_BITS_COUNTER, i); + } + + /* block is waiting so check block */ + if (block_waiting) + retry |= (search_block(i, 0) >= 0); + } + + /* no runnable workload found */ + if (block < 0) + return retry ? + MARS_KERNEL_STATUS_RETRY : MARS_KERNEL_STATUS_IDLE; + + /* search block for workload index to run */ + index = search_block(block, 1); + if (index < 0) + return MARS_KERNEL_STATUS_RETRY; + + /* set global workload info based on workload_id */ + workload_id = MARS_WORKLOAD_PER_BLOCK * block + index; + workload_ea = get_workload_ea(workload_id); + workload_module = (struct mars_workload_module *)&workload; + + /* get the workload context code from workload queue */ + dma_get(&workload, workload_ea, + MARS_WORKLOAD_CONTEXT_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + return MARS_KERNEL_STATUS_BUSY; +} + +static void workload_release(void) +{ + int unscheduled; + int block = workload_id / MARS_WORKLOAD_PER_BLOCK; + int index = workload_id % MARS_WORKLOAD_PER_BLOCK; + uint64_t block_ea = get_block_ea(block); + uint8_t state; + + /* lock the queue block */ + mutex_lock_get(block_ea, (struct mars_mutex *)&queue_block); + + /* get current state */ + state = MARS_BITS_GET(&queue_block.bits[index], WORKLOAD_STATE); + + /* if state is unscheduling or finished, it (was/will be) aborted */ + unscheduled = state & (MARS_WORKLOAD_STATE_UNSCHEDULING | + MARS_WORKLOAD_STATE_FINISHED); + + if (!unscheduled) { + /* put the workload context into workload queue */ + dma_put(&workload, workload_ea, + MARS_WORKLOAD_CONTEXT_SIZE, MARS_KERNEL_DMA_TAG); + dma_wait(MARS_KERNEL_DMA_TAG); + + /* update current workload state in workload queue block */ + MARS_BITS_SET(&queue_block.bits[index], WORKLOAD_STATE, + workload_state); + + /* update queue header bits */ + update_header_bits(MARS_KERNEL_UPDATE_HEADER_BITS_STATE, block); + } + + /* unlock the queue block */ + mutex_unlock_put(block_ea, (struct mars_mutex *)&queue_block); + + /* workload state is finished so notify host */ + if (!unscheduled && (workload_state & MARS_WORKLOAD_STATE_FINISHED)) + notify_host_bits(block_ea, index); +} + +static void workload_module_load(void) +{ + __vector unsigned char *bss_ptr, *bss_end; + + workload_module_is_cached = + !(kernel_memcmp(&cached_workload_module, workload_module, + MARS_WORKLOAD_MODULE_SIZE)); + + /* only reload the readonly text segment if different from cached */ + if (!workload_module_is_cached) { + /* store the current cached workload module ea */ + kernel_memcpy(&cached_workload_module, workload_module, + MARS_WORKLOAD_MODULE_SIZE); + + /* load the text into mpu storage from host storage */ + dma_get((void *)workload_module->text_vaddr, + workload_module->text_ea, + workload_module->text_size, + MARS_KERNEL_DMA_TAG); + } + + /* load the read-write data segment */ + dma_get((void *)workload_module->data_vaddr, + workload_module->data_ea, + workload_module->data_size, + MARS_KERNEL_DMA_TAG); + + /* 0 the bss segment */ + bss_ptr = (__vector unsigned char *)(workload_module->data_vaddr + + workload_module->data_size); + bss_end = (__vector unsigned char *)((void *)bss_ptr + + workload_module->bss_size); + + while (__builtin_expect(bss_ptr < bss_end, 1)) + *bss_ptr++ = spu_splats((unsigned char)0); + + dma_wait(MARS_KERNEL_DMA_TAG); + + /* sync before executing loaded code */ + spu_sync(); +} + +static void idle_wait(void) +{ + struct mars_workload_queue_header *cur_queue_header = + &kernel_buffer.workload_queue_header; + + /* set event mask for the lost event */ + spu_write_event_mask(MFC_LLR_LOST_EVENT); + + /* get current atomic state of queue header */ + mfc_getllar(cur_queue_header, kernel_params.workload_queue_ea, 0, 0); + mfc_read_atomic_status(); + + /* check if queue header has been modified since we last fetched it */ + if (!kernel_memcmp(&queue_header, cur_queue_header, + MARS_WORKLOAD_QUEUE_HEADER_SIZE)) { + /* wait until queue header is modified */ + spu_read_event_status(); + spu_write_event_ack(MFC_LLR_LOST_EVENT); + } + + /* clear any remnant lost event */ + spu_write_event_ack(MFC_LLR_LOST_EVENT); +} + +static void get_params(void) +{ + /* set event mask for the lost event */ + spu_write_event_mask(MFC_LLR_LOST_EVENT); + + /* set sync begin flag so host knows to begin sync process */ + do { + mfc_getllar(&kernel_params, kernel_params_ea, 0, 0); + mfc_read_atomic_status(); + + /* set the flag */ + kernel_params.kernel_ticks.flag = + MARS_KERNEL_TICKS_FLAG_SYNC_BEGIN; + spu_dsync(); + + mfc_putllc(&kernel_params, kernel_params_ea, 0, 0); + } while (mfc_read_atomic_status() & MFC_PUTLLC_STATUS); + + /* get the tick offset from host and check if sync end flag is set */ + do { + spu_write_event_ack(MFC_LLR_LOST_EVENT); + + mfc_getllar(&kernel_params, kernel_params_ea, 0, 0); + mfc_read_atomic_status(); + + /* host set the sync end flag so finish */ + if (kernel_params.kernel_ticks.flag & + MARS_KERNEL_TICKS_FLAG_SYNC_END) + break; + + spu_read_event_status(); + } while (1); + + /* now, kernel parameters, including offset of tick counters, + * are stored in 'kernel_params'. + */ + + /* start decrementer */ + spu_write_decrementer(0); + + /* clear any remnant lost event */ + spu_write_event_ack(MFC_LLR_LOST_EVENT); +} + +int main(uint64_t params_ea) +{ + kernel_params_ea = params_ea; + + get_params(); + + do { + int status = workload_reserve(); + + if (status & MARS_KERNEL_STATUS_BUSY) { + workload_module_load(); + workload_run(); + workload_release(); + } else if (status & MARS_KERNEL_STATUS_IDLE) { + idle_wait(); + } else if (status & MARS_KERNEL_STATUS_EXIT) { + break; + } + } while (1); + + host_signal_send(MARS_HOST_SIGNAL_EXIT); + + return MARS_SUCCESS; +} + + +void exit(int rc) +{ + spu_thread_exit(rc); + for(;;) + ; +} diff --git a/common/libspumars/spu/base/kernel/kernel_crt.S b/common/libspumars/spu/base/kernel/kernel_crt.S new file mode 100644 index 00000000..ca7f3053 --- /dev/null +++ b/common/libspumars/spu/base/kernel/kernel_crt.S @@ -0,0 +1,46 @@ +.section .interrupt, "ax", @progbits + heq $LR, $LR, $LR + +.section .init + +.globl _init +.type _init, @function +_init: + stqd $LR, 16($SP) + stqd $SP, -32($SP) + ai $SP, $SP, -32 + + ai $SP, $SP, 32 + lqd $LR, 16($SP) + bi $LR + +.section .fini + +.globl _fini +.type _fini, @function +_fini: + stqd $LR, 16($SP) + stqd $SP, -32($SP) + ai $SP, $SP, -32 + + ai $SP, $SP, 32 + lqd $LR, 16($SP) + bi $LR + +.section .text + +.globl _start +.type _start, @function +_start: + il $LR, 0 + ila $SP, __stack + + stqd $LR, 0($SP) /* init back chain to NULL */ + stqd $SP, -32($SP) /* init stack frame */ + ai $SP, $SP, -32 /* push stack frame */ + + brsl $LR, _init + brsl $LR, main + br exit +.size _start, .-_start + \ No newline at end of file diff --git a/common/libspumars/spu/base/kernel/mutex.c b/common/libspumars/spu/base/kernel/mutex.c new file mode 100644 index 00000000..d118a20b --- /dev/null +++ b/common/libspumars/spu/base/kernel/mutex.c @@ -0,0 +1,105 @@ +#include +#include + +#include +#include + +#include "kernel_internal_types.h" + +#define MARS_MUTEX_STATE_NONE 0 +#define MARS_MUTEX_STATE_DONE 2 + +static struct mars_mutex mutex_buffer; + +int mutex_lock_get(uint64_t mutex_ea, struct mars_mutex *mutex) +{ + int state = MARS_MUTEX_STATE_NONE; + uint8_t id = 0; + + /* check function params */ + if (!mutex_ea) + return MARS_ERROR_NULL; + if (!mutex) + return MARS_ERROR_NULL; + if (mutex_ea & MARS_MUTEX_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if ((uintptr_t)mutex & MARS_MUTEX_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* set event mask for the lost event */ + spu_write_event_mask(MFC_LLR_LOST_EVENT); + + /* update waiting state */ + while (state != MARS_MUTEX_STATE_DONE) { + mfc_getllar(mutex, mutex_ea, 0, 0); + mfc_read_atomic_status(); + + if (state && + (mutex->status.lock == MARS_MUTEX_LOCKED || + mutex->status.current_id != id)) { + /* wait until mutex is released */ + spu_read_event_status(); + spu_write_event_ack(MFC_LLR_LOST_EVENT); + } + else { + if (state) { + /* get lock */ + mutex->status.lock = MARS_MUTEX_LOCKED; + mutex->status.current_id++; + } + else { + /* get my id */ + id = mutex->status.next_id++; + } + + spu_dsync(); + mfc_putllc(mutex, mutex_ea, 0, 0); + if (!(mfc_read_atomic_status() & MFC_PUTLLC_STATUS)) + state++; + } + } + + /* clear any remnant lost event */ + spu_write_event_ack(MFC_LLR_LOST_EVENT); + + return MARS_SUCCESS; +} + +int mutex_unlock_put(uint64_t mutex_ea, struct mars_mutex *mutex) +{ + int status; + + /* check function params */ + if (!mutex_ea) + return MARS_ERROR_NULL; + if (!mutex) + return MARS_ERROR_NULL; + if (mutex_ea & MARS_MUTEX_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if ((uintptr_t)mutex & MARS_MUTEX_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (mutex->status.lock != MARS_MUTEX_LOCKED) + return MARS_ERROR_STATE; + + mfc_sync(0); + + /* set event mask for the lost event */ + spu_write_event_mask(MFC_LLR_LOST_EVENT); + + do { + mfc_getllar(&mutex_buffer, mutex_ea, 0, 0); + mfc_read_atomic_status(); + + mutex->status = mutex_buffer.status; + mutex->status.lock = MARS_MUTEX_UNLOCKED; + + spu_dsync(); + mfc_putllc(mutex, mutex_ea, 0, 0); + status = mfc_read_atomic_status() & MFC_PUTLLC_STATUS; + } while (status); + + /* clear any remnant lost event */ + spu_write_event_ack(MFC_LLR_LOST_EVENT); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/spu/base/kernel/switch.S b/common/libspumars/spu/base/kernel/switch.S new file mode 100644 index 00000000..34becef5 --- /dev/null +++ b/common/libspumars/spu/base/kernel/switch.S @@ -0,0 +1,39 @@ +.section .bss + +.align 4 +.globl __kernel_stack +__kernel_stack: + .space 16 + + +.text + +.globl workload_run +.type workload_run, @function +workload_run: + stqd $LR, 16($SP) + stqd $SP, -32($SP) + ai $SP, $SP, -32 + + stqa $SP, __kernel_stack + brsl $LR, __workload_run + + ai $SP, $SP, 32 + lqd $LR, 16($SP) + bi $LR +.size workload_run, .-workload_run + +.globl workload_exit +.type workload_exit, @function +workload_exit: + stqd $LR, 16($SP) + stqd $SP, -32($SP) + ai $SP, $SP, -32 + + brsl $LR, __workload_exit + lqa $SP, __kernel_stack + + ai $SP, $SP, 32 + lqd $LR, 16($SP) + bi $LR +.size workload_exit, .-workload_exit diff --git a/common/libspumars/spu/base/lib/module.S b/common/libspumars/spu/base/lib/module.S new file mode 100644 index 00000000..cb941268 --- /dev/null +++ b/common/libspumars/spu/base/lib/module.S @@ -0,0 +1,307 @@ +/* NOTE: Order of defines must be the same as the member order of + struct mars_kernel_syscalls declaration in kernel_internal_types.h */ +#define get_ticks 0 +#define get_mars_context_ea 4 +#define get_kernel_id 8 +#define get_workload_id 12 +#define get_workload 16 +#define get_workload_by_id 20 +#define workload_exit 24 +#define workload_query 28 +#define workload_wait_set 32 +#define workload_wait_reset 36 +#define workload_signal_set 40 +#define workload_signal_reset 44 +#define workload_schedule_begin 48 +#define workload_schedule_end 52 +#define workload_unschedule_begin 56 +#define workload_unschedule_end 60 +#define host_signal_send 64 +#define host_callback_set 68 +#define host_callback_reset 72 +#define mutex_lock_get 76 +#define mutex_unlock_put 80 +#define dma_get 84 +#define dma_put 88 +#define dma_wait 92 + +/* NOTE: Value of defines must equal defines in workload_internal_types.h */ +#define WORKLOAD_EXIT_STATE_READY 0x10 /* MARS_WORKLOAD_STATE_READY */ +#define WORKLOAD_EXIT_STATE_WAITING 0x20 /* MARS_WORKLOAD_STATE_WAITING */ +#define WORKLOAD_EXIT_STATE_FINISHED 0x80 /* MARS_WORKLOAD_STATE_FINISHED */ + +.section .bss + +/* const struct mars_kernel_syscalls *kernel_syscalls */ +.align 4 +.globl kernel_syscalls +kernel_syscalls: +.space 16 + + +.section .text + +/* void mars_module_entry(const struct mars_kernel_syscalls *syscalls) */ +.global mars_module_entry +.type mars_module_entry, @function +mars_module_entry: + ila $SP, __stack /* switch to module stack */ + il $LR, 0 /* set link register to NULL */ + stqd $LR, 0($SP) /* init back chain to NULL */ + stqd $SP, -32($SP) /* init stack frame */ + ai $SP, $SP, -32 /* push stack frame */ + + stqr $3, kernel_syscalls /* save kernel syscalls ptr */ + brsl $LR, _init /* call _init() */ + brsl $LR, mars_module_main /* call mars_module_main() */ + br mars_module_workload_finish /* return to kernel */ +.size mars_module_entry, .-mars_module_entry + + +/* uint32_t mars_module_get_ticks(void) */ +.global mars_module_get_ticks +.type mars_module_get_ticks, @function +mars_module_get_ticks: + il $2, get_ticks + br call_kernel_syscall +.size mars_module_get_ticks, .-mars_module_get_ticks + + +/* uint64_t mars_module_get_mars_context_ea(void) */ +.global mars_module_get_mars_context_ea +.type mars_module_get_mars_context_ea, @function +mars_module_get_mars_context_ea: + il $2, get_mars_context_ea + br call_kernel_syscall +.size mars_module_get_mars_context_ea, .-mars_module_get_mars_context_ea + + +/* uint16_t mars_module_get_kernel_id(void) */ +.global mars_module_get_kernel_id +.type mars_module_get_kernel_id, @function +mars_module_get_kernel_id: + il $2, get_kernel_id + br call_kernel_syscall +.size mars_module_get_kernel_id, .-mars_module_get_kernel_id + +/* uint16_t mars_module_get_workload_id(void) */ +.global mars_module_get_workload_id +.type mars_module_get_workload_id, @function +mars_module_get_workload_id: + il $2, get_workload_id + br call_kernel_syscall +.size mars_module_get_workload_id, .-mars_module_get_workload_id + + +/* struct mars_workload_context *mars_module_get_workload(void) */ +.global mars_module_get_workload +.type mars_module_get_workload, @function +mars_module_get_workload: + il $2, get_workload + br call_kernel_syscall +.size mars_module_get_workload, .-mars_module_get_workload + + +/* struct mars_workload_context *mars_module_get_workload_by_id(uint16_t id) */ +.global mars_module_get_workload_by_id +.type mars_module_get_workload_by_id, @function +mars_module_get_workload_by_id: + il $2, get_workload_by_id + br call_kernel_syscall +.size mars_module_get_workload_by_id, .-mars_module_get_workload_by_id + + +/* int mars_module_workload_query(uint16_t id, int query) */ +.global mars_module_workload_query +.type mars_module_workload_query, @function +mars_module_workload_query: + il $2, workload_query + br call_kernel_syscall +.size mars_module_workload_query, .-mars_module_workload_query + + +/* int mars_module_workload_wait_set(uint16_t id) */ +.global mars_module_workload_wait_set +.type mars_module_workload_wait_set, @function +mars_module_workload_wait_set: + il $2, workload_wait_set + br call_kernel_syscall +.size mars_module_workload_wait_set, .-mars_module_workload_wait_set + +/* int mars_module_workload_wait_reset(void) */ +.global mars_module_workload_wait_reset +.type mars_module_workload_wait_reset, @function +mars_module_workload_wait_reset: + il $2, workload_wait_reset + br call_kernel_syscall +.size mars_module_workload_wait_reset, .-mars_module_workload_wait_reset + + +/* int mars_module_workload_signal_set(uint16_t id) */ +.global mars_module_workload_signal_set +.type mars_module_workload_signal_set, @function +mars_module_workload_signal_set: + il $2, workload_signal_set + br call_kernel_syscall +.size mars_module_workload_signal_set, .-mars_module_workload_signal_set + + +/* int mars_module_workload_signal_reset(void) */ +.global mars_module_workload_signal_reset +.type mars_module_workload_signal_reset, @function +mars_module_workload_signal_reset: + il $2, workload_signal_reset + br call_kernel_syscall +.size mars_module_workload_signal_reset, .-mars_module_workload_signal_reset + + +/* int mars_module_workload_schedule_begin(uint16_t id, uint8_t priority, + struct mars_workload_context **workload) */ +.global mars_module_workload_schedule_begin +.type mars_module_workload_schedule_begin, @function +mars_module_workload_schedule_begin: + il $2, workload_schedule_begin + br call_kernel_syscall +.size mars_module_workload_schedule_begin, .-mars_module_workload_schedule_begin + + +/* int mars_module_workload_schedule_end(uint16_t id, int cancel) */ +.global mars_module_workload_schedule_end +.type mars_module_workload_schedule_end, @function +mars_module_workload_schedule_end: + il $2, workload_schedule_end + br call_kernel_syscall +.size mars_module_workload_schedule_end, .-mars_module_workload_schedule_end + + +/* int mars_module_workload_unschedule_begin(uint16_t id, + struct mars_workload_context **workload) */ +.global mars_module_workload_unschedule_begin +.type mars_module_workload_unschedule_begin, @function +mars_module_workload_unschedule_begin: + il $2, workload_unschedule_begin + br call_kernel_syscall +.size mars_module_workload_unschedule_begin, .-mars_module_workload_unschedule_begin + + +/* int mars_module_workload_unschedule_end(uint16_t id) */ +.global mars_module_workload_unschedule_end +.type mars_module_workload_unschedule_end, @function +mars_module_workload_unschedule_end: + il $2, workload_unschedule_end + br call_kernel_syscall +.size mars_module_workload_unschedule_end, .-mars_module_workload_unschedule_end + + +/* void mars_module_workload_wait(void) */ +.global mars_module_workload_wait +.type mars_module_workload_wait, @function +mars_module_workload_wait: + il $3, WORKLOAD_EXIT_STATE_WAITING + il $2, workload_exit + br call_kernel_syscall +.size mars_module_workload_wait, .-mars_module_workload_wait + + +/* void mars_module_workload_yield(void) */ +.global mars_module_workload_yield +.type mars_module_workload_yield, @function +mars_module_workload_yield: + il $3, WORKLOAD_EXIT_STATE_READY + il $2, workload_exit + br call_kernel_syscall +.size mars_module_workload_yield, .-mars_module_workload_yield + + +/* void mars_module_workload_finish(void) */ +.global mars_module_workload_finish +.type mars_module_workload_finish, @function +mars_module_workload_finish: + il $3, WORKLOAD_EXIT_STATE_FINISHED + il $2, workload_exit + br call_kernel_syscall +.size mars_module_workload_finish, .-mars_module_workload_finish + +/* int mars_module_host_signal_send(uint64_t watch_point_ea) */ +.global mars_module_host_signal_send +.type mars_module_host_signal_send, @function +mars_module_host_signal_send: + il $2, host_signal_send + br call_kernel_syscall +.size mars_module_host_signal_send, .-mars_module_host_signal_send + + +/* int mars_module_host_callback_set(uint64_t callback_ea, + const struct mars_callback_args *in) */ +.global mars_module_host_callback_set +.type mars_module_host_callback_set, @function +mars_module_host_callback_set: + il $2, host_callback_set + br call_kernel_syscall +.size mars_module_host_callback_set, .-mars_module_host_callback_set + + +/* int mars_module_host_callback_reset(struct mars_callback_args *out) */ +.global mars_module_host_callback_reset +.type mars_module_host_callback_reset, @function +mars_module_host_callback_reset: + il $2, host_callback_reset + br call_kernel_syscall +.size mars_module_host_callback_reset, .-mars_module_host_callback_reset + + +/* int mars_module_mutex_lock_get(uint64_t mutex_ea, + struct mars_mutex *mutex) */ +.global mars_module_mutex_lock_get +.type mars_module_mutex_lock_get, @function +mars_module_mutex_lock_get: + il $2, mutex_lock_get + br call_kernel_syscall +.size mars_module_mutex_lock_get, .-mars_module_mutex_lock_get + + +/* int mars_module_mutex_unlock_put(uint64_t mutex_ea, + struct mars_mutex *mutex) */ +.global mars_module_mutex_unlock_put +.type mars_module_mutex_unlock_put, @function +mars_module_mutex_unlock_put: + il $2, mutex_unlock_put + br call_kernel_syscall +.size mars_module_mutex_unlock_put, .-mars_module_mutex_unlock_put + + +/* int mars_module_dma_get(void *ls, uint64_t ea, uint32_t size, + uint32_t tag) */ +.global mars_module_dma_get +.type mars_module_dma_get, @function +mars_module_dma_get: + il $2, dma_get + br call_kernel_syscall +.size mars_module_dma_get, .-mars_module_dma_get + + +/* int mars_module_dma_put(const void *ls, uint64_t ea, uint32_t size, + uint32_t tag) */ +.global mars_module_dma_put +.type mars_module_dma_put, @function +mars_module_dma_put: + il $2, dma_put + br call_kernel_syscall +.size mars_module_dma_put, .-mars_module_dma_get + + +/* int mars_module_dma_wait(uint32_t tag) */ +.global mars_module_dma_wait +.type mars_module_dma_wait, @function +mars_module_dma_wait: + il $2, dma_wait + br call_kernel_syscall +.size mars_module_dma_wait, .-mars_module_dma_wait + + +call_kernel_syscall: + lqr $76, kernel_syscalls + lqx $77, $76, $2 + a $78, $76, $2 + rotqby $79, $77, $78 + bi $79 diff --git a/common/libspumars/spu/task/lib/task.c b/common/libspumars/spu/task/lib/task.c new file mode 100644 index 00000000..1f4a7f47 --- /dev/null +++ b/common/libspumars/spu/task/lib/task.c @@ -0,0 +1,177 @@ +#include + +#include +#include +//#include + +#include "../module/task_module.h" + +const struct mars_task_module_syscalls *mars_task_module_syscalls; + +int main(const struct mars_task_args *args, + const struct mars_task_module_syscalls *module_syscalls) +{ + struct mars_task_context *task; + + /* save the module syscalls pointer */ + mars_task_module_syscalls = module_syscalls; + + /* get task context */ + task = mars_task_module_get_task(); + + /* call task main function and store return value in task context */ + task->exit_code = mars_task_main(args); + + /* exit */ + mars_task_module_exit(); + + return MARS_SUCCESS; +} + +void mars_task_exit(int32_t exit_code) +{ + struct mars_task_context *task; + + /* get task context */ + task = mars_task_module_get_task(); + + /* store exit code in task context */ + task->exit_code = exit_code; + + /* exit */ + mars_task_module_exit(); +} + +int mars_task_yield(void) +{ + struct mars_task_context *task; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea) + return MARS_ERROR_FORMAT; + + mars_task_module_yield(mars_task_module_get_heap()); + + return MARS_SUCCESS; +} + +int mars_task_schedule(const struct mars_task_id *id, + const struct mars_task_args *args, + uint8_t priority) +{ + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + return mars_task_module_schedule(id->workload_id, args, priority); +} + +int mars_task_unschedule(const struct mars_task_id *id, int32_t exit_code) +{ + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + return mars_task_module_unschedule(id->workload_id, exit_code); +} + +int mars_task_wait(const struct mars_task_id *id, int32_t *exit_code) +{ + struct mars_task_context *task; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea) + return MARS_ERROR_FORMAT; + + mars_task_module_wait(id->workload_id, mars_task_module_get_heap()); + + /* exit code requested so get it from the task context and return it */ + if (exit_code) { + task = (struct mars_task_context *) + mars_task_module_get_task_by_id(id); + if (!task) + return MARS_ERROR_INTERNAL; + + *exit_code = task->exit_code; + } + + return MARS_SUCCESS; +} + +int mars_task_try_wait(const struct mars_task_id *id, int32_t *exit_code) +{ + struct mars_task_context *task; + + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + mars_task_module_try_wait(id->workload_id); + + /* exit code requested so get it from the task context and return it */ + if (exit_code) { + task = (struct mars_task_context *) + mars_task_module_get_task_by_id(id); + if (!task) + return MARS_ERROR_INTERNAL; + + *exit_code = task->exit_code; + } + + return MARS_SUCCESS; +} + +int mars_task_call_host(uint64_t callback_ea, + const struct mars_callback_args *in, + struct mars_callback_args *out) +{ + struct mars_task_context *task; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea) + return MARS_ERROR_FORMAT; + + return mars_task_module_call_host(callback_ea, in, out, + mars_task_module_get_heap()); +} + +uint32_t mars_task_get_ticks(void) +{ + return mars_task_module_get_ticks(); +} + +uint16_t mars_task_get_kernel_id(void) +{ + return mars_task_module_get_kernel_id(); +} + +const struct mars_task_id *mars_task_get_id(void) +{ + struct mars_task_context *task; + + task = mars_task_module_get_task(); + + return &task->id; +} + +const char *mars_task_get_name(void) +{ + struct mars_task_context *task; + + task = mars_task_module_get_task(); + + return task->id.name[0] ? (const char *)task->id.name : NULL; +} diff --git a/common/libspumars/spu/task/lib/task_barrier.c b/common/libspumars/spu/task/lib/task_barrier.c new file mode 100644 index 00000000..87d7df98 --- /dev/null +++ b/common/libspumars/spu/task/lib/task_barrier.c @@ -0,0 +1,164 @@ +#include + +#include +#include + +#include "task_barrier_internal_types.h" +#include "task_internal_types.h" +#include "../module/task_module.h" + +static struct mars_task_barrier barrier; + +static int notify(uint64_t barrier_ea, int try) +{ + int i; + struct mars_task_context *task; + + /* check function params */ + if (!barrier_ea) + return MARS_ERROR_NULL; + if (barrier_ea & MARS_TASK_BARRIER_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea && !try) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier); + + /* previous barrier wait not complete so wait */ + if (barrier.notified_count == barrier.total) { + /* only try so return busy */ + if (try) { + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + return MARS_ERROR_BUSY; + } + + /* check if barrier notify wait limit reached */ + if (barrier.notify_wait_count == barrier.total) { + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + return MARS_ERROR_LIMIT; + } + + /* add id to wait list */ + barrier.notify_wait_id[barrier.notify_wait_count] = + task->id.workload_id; + barrier.notify_wait_count++; + + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier); + } + + /* increment notified count */ + barrier.notified_count++; + + /* notified count reached total so release barrier */ + if (barrier.notified_count == barrier.total) { + /* signal all task ids in wait list */ + for (i = 0; i < barrier.wait_count; i++) + mars_task_module_signal_send(barrier.wait_id[i]); + barrier.wait_count = 0; + } + + mars_mutex_unlock_put(barrier_ea, (struct mars_mutex *)&barrier); + + return MARS_SUCCESS; +} + +int mars_task_barrier_notify(uint64_t barrier_ea) +{ + return notify(barrier_ea, 0); +} + +int mars_task_barrier_try_notify(uint64_t barrier_ea) +{ + return notify(barrier_ea, 1); +} + +static int wait(uint64_t barrier_ea, int try) +{ + int i; + struct mars_task_context *task; + + /* check function params */ + if (!barrier_ea) + return MARS_ERROR_NULL; + if (barrier_ea & MARS_TASK_BARRIER_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea && !try) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier); + + /* not all tasks notified barrier so need to wait */ + if (barrier.notified_count != barrier.total) { + /* only try so return busy */ + if (try) { + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + return MARS_ERROR_BUSY; + } + + /* check if barrier wait limit reached */ + if (barrier.wait_count == barrier.total) { + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + return MARS_ERROR_LIMIT; + } + + /* add id to wait list */ + barrier.wait_id[barrier.wait_count] = task->id.workload_id; + barrier.wait_count++; + + mars_mutex_unlock_put(barrier_ea, + (struct mars_mutex *)&barrier); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + mars_mutex_lock_get(barrier_ea, (struct mars_mutex *)&barrier); + } + + /* increment waited count */ + barrier.waited_count++; + + /* all tasks have called wait so reset barrier */ + if (barrier.waited_count == barrier.total) { + barrier.notified_count = 0; + barrier.waited_count = 0; + + /* signal all task ids in notify wait list */ + for (i = 0; i < barrier.notify_wait_count; i++) + mars_task_module_signal_send(barrier.notify_wait_id[i]); + barrier.notify_wait_count = 0; + } + + mars_mutex_unlock_put(barrier_ea, (struct mars_mutex *)&barrier); + + return MARS_SUCCESS; +} + +int mars_task_barrier_wait(uint64_t barrier_ea) +{ + return wait(barrier_ea, 0); +} + +int mars_task_barrier_try_wait(uint64_t barrier_ea) +{ + return wait(barrier_ea, 1); +} diff --git a/common/libspumars/spu/task/lib/task_event_flag.c b/common/libspumars/spu/task/lib/task_event_flag.c new file mode 100644 index 00000000..755b1562 --- /dev/null +++ b/common/libspumars/spu/task/lib/task_event_flag.c @@ -0,0 +1,207 @@ +#include +#include + +#include +#include +#include + +#include "task_event_flag_internal_types.h" +#include "task_internal_types.h" +#include "../module/task_module.h" + +static struct mars_task_event_flag event_flag; + +int mars_task_event_flag_clear(uint64_t event_flag_ea, uint32_t bits) +{ + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + if (event_flag_ea & MARS_TASK_EVENT_FLAG_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)&event_flag); + + /* clear the necessary bits */ + event_flag.bits &= ~bits; + + mars_mutex_unlock_put(event_flag_ea, (struct mars_mutex *)&event_flag); + + return MARS_SUCCESS; +} + +int mars_task_event_flag_set(uint64_t event_flag_ea, uint32_t bits) +{ + int i; + + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + if (event_flag_ea & MARS_TASK_EVENT_FLAG_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)&event_flag); + + /* check for valid direction */ + if (event_flag.direction != MARS_TASK_EVENT_FLAG_MPU_TO_HOST && + event_flag.direction != MARS_TASK_EVENT_FLAG_MPU_TO_MPU) { + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)&event_flag); + return MARS_ERROR_STATE; + } + + /* set the necessary bits */ + event_flag.bits |= bits; + + /* save current set bits */ + bits = event_flag.bits; + + /* search through wait list for tasks to be signalled */ + for (i = 0; i < event_flag.wait_count; i++) { + /* check condition based on wait mode */ + switch (event_flag.wait_mask_mode[i]) { + case MARS_TASK_EVENT_FLAG_MASK_OR: + if ((bits & event_flag.wait_mask[i]) == 0) + continue; + break; + case MARS_TASK_EVENT_FLAG_MASK_AND: + if ((bits & event_flag.wait_mask[i]) + != event_flag.wait_mask[i]) + continue; + break; + } + + /* signal the waiting tasks */ + mars_task_module_signal_send(event_flag.wait_id[i]); + + /* flush id from wait list */ + event_flag.wait_count--; + memmove(&event_flag.wait_id[i], + &event_flag.wait_id[i + 1], + sizeof(uint16_t) * (event_flag.wait_count - i)); + memmove(&event_flag.wait_mask[i], + &event_flag.wait_mask[i + 1], + sizeof(uint32_t) * (event_flag.wait_count - i)); + memmove(&event_flag.wait_mask_mode[i], + &event_flag.wait_mask_mode[i + 1], + sizeof(uint8_t) * (event_flag.wait_count - i)); + i--; + } + + mars_mutex_unlock_put(event_flag_ea, (struct mars_mutex *)&event_flag); + + /* signal the waiting host */ + if (event_flag.direction != MARS_TASK_EVENT_FLAG_HOST_TO_MPU && + event_flag.direction != MARS_TASK_EVENT_FLAG_MPU_TO_MPU) + mars_task_module_signal_host(event_flag_ea + + offsetof(struct mars_task_event_flag, bits)); + + return MARS_SUCCESS; +} + +static int wait(uint64_t event_flag_ea,uint32_t mask, uint8_t mask_mode, + uint32_t *bits, int try) +{ + int wait = 0; + struct mars_task_context *task; + + /* check function params */ + if (!event_flag_ea) + return MARS_ERROR_NULL; + if (event_flag_ea & MARS_TASK_EVENT_FLAG_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (mask_mode != MARS_TASK_EVENT_FLAG_MASK_OR && + mask_mode != MARS_TASK_EVENT_FLAG_MASK_AND) + return MARS_ERROR_PARAMS; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea && !try) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(event_flag_ea, (struct mars_mutex *)&event_flag); + + /* check for valid direction */ + if (event_flag.direction != MARS_TASK_EVENT_FLAG_HOST_TO_MPU && + event_flag.direction != MARS_TASK_EVENT_FLAG_MPU_TO_MPU) { + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)&event_flag); + return MARS_ERROR_STATE; + } + + /* check condition based on wait mode */ + switch (mask_mode) { + case MARS_TASK_EVENT_FLAG_MASK_OR: + if ((event_flag.bits & mask) == 0) + wait = 1; + break; + case MARS_TASK_EVENT_FLAG_MASK_AND: + if ((event_flag.bits & mask) != mask) + wait = 1; + break; + } + + if (wait) { + /* only try so return busy */ + if (try) { + /* get current bits status if return bits requested */ + if (bits) + *bits = event_flag.bits; + + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)&event_flag); + + return MARS_ERROR_BUSY; + } + + /* check if event flag wait limit reached */ + if (event_flag.wait_count == MARS_TASK_EVENT_FLAG_WAIT_MAX) { + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)&event_flag); + return MARS_ERROR_LIMIT; + } + + /* add id to wait list */ + event_flag.wait_id[event_flag.wait_count] = + task->id.workload_id; + event_flag.wait_mask[event_flag.wait_count] = mask; + event_flag.wait_mask_mode[event_flag.wait_count] = mask_mode; + event_flag.wait_count++; + + mars_mutex_unlock_put(event_flag_ea, + (struct mars_mutex *)&event_flag); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + mars_mutex_lock_get(event_flag_ea, + (struct mars_mutex *)&event_flag); + } + + /* return bits if requested */ + if (bits) + *bits = event_flag.bits; + + /* clear event if clear mode is auto */ + if (event_flag.clear_mode == MARS_TASK_EVENT_FLAG_CLEAR_AUTO) + event_flag.bits &= ~mask; + + mars_mutex_unlock_put(event_flag_ea, (struct mars_mutex *)&event_flag); + + return MARS_SUCCESS; +} + +int mars_task_event_flag_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits) +{ + return wait(event_flag_ea, mask, mask_mode, bits, 0); +} + +int mars_task_event_flag_try_wait(uint64_t event_flag_ea, + uint32_t mask, uint8_t mask_mode, + uint32_t *bits) +{ + return wait(event_flag_ea, mask, mask_mode, bits, 1); +} diff --git a/common/libspumars/spu/task/lib/task_queue.c b/common/libspumars/spu/task/lib/task_queue.c new file mode 100644 index 00000000..398ec3f2 --- /dev/null +++ b/common/libspumars/spu/task/lib/task_queue.c @@ -0,0 +1,455 @@ +#include + +#include +#include +#include + +#include "task_internal_types.h" +#include "task_queue_internal_types.h" +#include "../module/task_module.h" + +static struct mars_task_queue queue; + +int mars_task_queue_count(uint64_t queue_ea, uint32_t *count) +{ + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (!count) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + + /* return current items in queue */ + *count = queue.count; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + return MARS_SUCCESS; +} + +int mars_task_queue_clear(uint64_t queue_ea) +{ + int i; + int signal_host; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + + /* whether signal the waiting host */ + signal_host = + (queue.count == queue.depth && + queue.direction != MARS_TASK_QUEUE_MPU_TO_HOST && + queue.direction != MARS_TASK_QUEUE_MPU_TO_MPU); + + /* signal all waiting tasks that queue is ready for push */ + for (i = 0; i < queue.push_wait_count; i++) + mars_task_module_signal_send(queue.push_wait_id[i]); + + /* flush all ids from push wait list */ + queue.push_wait_count = 0; + + /* clear the queue count and push/pop ea */ + queue.count = 0; + queue.push_ea = queue.buffer_ea; + queue.pop_ea = queue.buffer_ea; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* signal the waiting host */ + if (signal_host) + mars_task_module_signal_host( + queue_ea + offsetof(struct mars_task_queue, count)); + + return MARS_SUCCESS; +} + +static int push_update(void) +{ + int signal_host; + + /* whether signal the waiting host */ + signal_host = + (queue.count == 0 && + queue.direction != MARS_TASK_QUEUE_HOST_TO_MPU && + queue.direction != MARS_TASK_QUEUE_MPU_TO_MPU); + + /* signal waiting task that queue is ready for pop */ + if (queue.pop_wait_count) { + /* signal waiting task */ + mars_task_module_signal_send( + queue.pop_wait_id[queue.pop_wait_head]); + + /* flush id from pop wait list */ + queue.pop_wait_count--; + queue.pop_wait_head++; + queue.pop_wait_head %= MARS_TASK_QUEUE_WAIT_MAX; + } + + /* increment queue count */ + queue.count++; + + /* increment queue push ea */ + queue.push_ea += queue.size; + + /* wrap to front of queue if necessary */ + if (queue.push_ea == queue.buffer_ea + (queue.size * queue.depth)) + queue.push_ea = queue.buffer_ea; + + return signal_host; +} + +static int push(uint64_t queue_ea, const void *data, + int try, int begin, uint32_t tag) +{ + struct mars_task_context *task; + int signal_host; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if ((uintptr_t)data & MARS_TASK_QUEUE_ENTRY_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (tag > MARS_TASK_MODULE_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea && !try) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + + /* check for valid direction */ + if (queue.direction != MARS_TASK_QUEUE_MPU_TO_HOST && + queue.direction != MARS_TASK_QUEUE_MPU_TO_MPU) { + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + return MARS_ERROR_STATE; + } + + /* queue is full so wait */ + while (queue.count == queue.depth) { + uint8_t push_wait_tail; + + /* only try so return busy */ + if (try) { + mars_mutex_unlock_put(queue_ea, + (struct mars_mutex *)&queue); + return MARS_ERROR_BUSY; + } + + /* check if push wait list full */ + if (queue.push_wait_count == MARS_TASK_QUEUE_WAIT_MAX) { + mars_mutex_unlock_put(queue_ea, + (struct mars_mutex *)&queue); + return MARS_ERROR_LIMIT; + } + + /* add id to push wait list */ + push_wait_tail = (queue.push_wait_head + queue.push_wait_count) + % MARS_TASK_QUEUE_WAIT_MAX; + queue.push_wait_id[push_wait_tail] = task->id.workload_id; + queue.push_wait_count++; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + } + + /* begin data transfer into queue */ + mars_dma_put(data, queue.push_ea, queue.size, tag); + + /* only begin data transfer so return */ + if (begin) + return MARS_SUCCESS; + + /* wait for dma completion */ + mars_dma_wait(tag); + + /* update queue data */ + signal_host = push_update(); + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* signal the waiting host */ + if (signal_host) + mars_task_module_signal_host( + queue_ea + offsetof(struct mars_task_queue, count)); + + return MARS_SUCCESS; +} + +int mars_task_queue_push(uint64_t queue_ea, const void *data) +{ + return push(queue_ea, data, 0, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_push_begin(uint64_t queue_ea, const void *data, + uint32_t tag) +{ + return push(queue_ea, data, 0, 1, tag); +} + +int mars_task_queue_push_end(uint64_t queue_ea, uint32_t tag) +{ + int signal_host; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (tag > MARS_TASK_MODULE_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + /* wait for dma completion */ + mars_dma_wait(tag); + + /* update queue data */ + signal_host = push_update(); + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* signal the waiting host */ + if (signal_host) + mars_task_module_signal_host( + queue_ea + offsetof(struct mars_task_queue, count)); + + return MARS_SUCCESS; +} + +int mars_task_queue_try_push(uint64_t queue_ea, const void *data) +{ + return push(queue_ea, data, 1, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_try_push_begin(uint64_t queue_ea, const void *data, + uint32_t tag) +{ + return push(queue_ea, data, 1, 1, tag); +} + +static int pop_update(void) +{ + int signal_host; + + /* whether signal the waiting host */ + signal_host = + (queue.count == queue.depth && + queue.direction != MARS_TASK_QUEUE_MPU_TO_HOST && + queue.direction != MARS_TASK_QUEUE_MPU_TO_MPU); + + /* signal waiting task that queue is ready for push */ + if (queue.push_wait_count) { + /* signal waiting task */ + mars_task_module_signal_send( + queue.push_wait_id[queue.push_wait_head]); + + /* flush id from push wait list */ + queue.push_wait_count--; + queue.push_wait_head++; + queue.push_wait_head %= MARS_TASK_QUEUE_WAIT_MAX; + } + + /* decrement queue count */ + queue.count--; + + /* increment queue pop ea */ + queue.pop_ea += queue.size; + + /* wrap to front of queue if necessary */ + if (queue.pop_ea == queue.buffer_ea + (queue.size * queue.depth)) + queue.pop_ea = queue.buffer_ea; + + return signal_host; +} + +static int pop(uint64_t queue_ea, void *data, + int peek, int try, int begin, uint32_t tag) +{ + struct mars_task_context *task; + int signal_host; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if ((uintptr_t)data & MARS_TASK_QUEUE_ENTRY_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (tag > MARS_TASK_MODULE_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea && !try) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + + /* check for valid direction */ + if (queue.direction != MARS_TASK_QUEUE_HOST_TO_MPU && + queue.direction != MARS_TASK_QUEUE_MPU_TO_MPU) { + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + return MARS_ERROR_STATE; + } + + /* queue is empty so wait */ + while (!queue.count) { + uint8_t pop_wait_tail; + + /* only try so return busy */ + if (try) { + mars_mutex_unlock_put(queue_ea, + (struct mars_mutex *)&queue); + return MARS_ERROR_BUSY; + } + + /* check if pop wait list full */ + if (queue.pop_wait_count == MARS_TASK_QUEUE_WAIT_MAX) { + mars_mutex_unlock_put(queue_ea, + (struct mars_mutex *)&queue); + return MARS_ERROR_LIMIT; + } + + /* add id to pop wait list */ + pop_wait_tail = (queue.pop_wait_head + queue.pop_wait_count) + % MARS_TASK_QUEUE_WAIT_MAX; + queue.pop_wait_id[pop_wait_tail] = task->id.workload_id; + queue.pop_wait_count++; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + mars_mutex_lock_get(queue_ea, (struct mars_mutex *)&queue); + } + + /* begin data transfer from queue */ + mars_dma_get(data, queue.pop_ea, queue.size, tag); + + /* only begin data transfer so return */ + if (begin) + return MARS_SUCCESS; + + /* wait for dma completion */ + mars_dma_wait(tag); + + /* update queue data only if this is not a peek operation */ + if (!peek) + signal_host = pop_update(); + else + signal_host = 0; + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* signal the waiting host */ + if (signal_host) + mars_task_module_signal_host( + queue_ea + offsetof(struct mars_task_queue, count)); + + return MARS_SUCCESS; +} + +int mars_task_queue_pop(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 0, 0, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_pop_begin(uint64_t queue_ea, void *data, uint32_t tag) +{ + return pop(queue_ea, data, 0, 0, 1, tag); +} + +int mars_task_queue_pop_end(uint64_t queue_ea, uint32_t tag) +{ + int signal_host; + + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (tag > MARS_TASK_MODULE_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + /* wait for dma completion */ + mars_dma_wait(tag); + + /* update queue data */ + signal_host = pop_update(); + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + /* signal the waiting host */ + if (signal_host) + mars_task_module_signal_host( + queue_ea + offsetof(struct mars_task_queue, count)); + + return MARS_SUCCESS; +} + +int mars_task_queue_try_pop(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 0, 1, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_try_pop_begin(uint64_t queue_ea, void *data, uint32_t tag) +{ + return pop(queue_ea, data, 0, 1, 1, tag); +} + +int mars_task_queue_peek(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 1, 0, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_peek_begin(uint64_t queue_ea, void *data, uint32_t tag) +{ + return pop(queue_ea, data, 1, 0, 1, tag); +} + +int mars_task_queue_peek_end(uint64_t queue_ea, uint32_t tag) +{ + /* check function params */ + if (!queue_ea) + return MARS_ERROR_NULL; + if (queue_ea & MARS_TASK_QUEUE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + if (tag > MARS_TASK_MODULE_DMA_TAG_MAX) + return MARS_ERROR_PARAMS; + + /* wait for dma completion */ + mars_dma_wait(tag); + + mars_mutex_unlock_put(queue_ea, (struct mars_mutex *)&queue); + + return MARS_SUCCESS; +} + +int mars_task_queue_try_peek(uint64_t queue_ea, void *data) +{ + return pop(queue_ea, data, 1, 1, 0, MARS_TASK_MODULE_DMA_TAG); +} + +int mars_task_queue_try_peek_begin(uint64_t queue_ea, void *data, uint32_t tag) +{ + return pop(queue_ea, data, 1, 1, 1, tag); +} diff --git a/common/libspumars/spu/task/lib/task_semaphore.c b/common/libspumars/spu/task/lib/task_semaphore.c new file mode 100644 index 00000000..35eed766 --- /dev/null +++ b/common/libspumars/spu/task/lib/task_semaphore.c @@ -0,0 +1,93 @@ +#include +#include +#include + +#include "task_internal_types.h" +#include "task_semaphore_internal_types.h" +#include "../module/task_module.h" + +static struct mars_task_semaphore semaphore; + +int mars_task_semaphore_acquire(uint64_t semaphore_ea) +{ + struct mars_task_context *task; + + /* check function params */ + if (!semaphore_ea) + return MARS_ERROR_NULL; + if (semaphore_ea & MARS_TASK_SEMAPHORE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea) + return MARS_ERROR_FORMAT; + + mars_mutex_lock_get(semaphore_ea, (struct mars_mutex *)&semaphore); + + /* check if semaphore wait limit reached */ + if (semaphore.wait_count == MARS_TASK_SEMAPHORE_WAIT_MAX) { + mars_mutex_unlock_put(semaphore_ea, + (struct mars_mutex *)&semaphore); + return MARS_ERROR_LIMIT; + } + + if (semaphore.count <= 0) { + uint8_t wait_tail = (semaphore.wait_head + semaphore.wait_count) + % MARS_TASK_SEMAPHORE_WAIT_MAX; + + /* add id to wait list */ + semaphore.wait_id[wait_tail] = task->id.workload_id; + semaphore.wait_count++; + + mars_mutex_unlock_put(semaphore_ea, + (struct mars_mutex *)&semaphore); + + /* wait for signal */ + mars_task_module_signal_wait(mars_task_module_get_heap()); + + return MARS_SUCCESS; + } + + /* decrement semaphore count */ + semaphore.count--; + + mars_mutex_unlock_put(semaphore_ea, (struct mars_mutex *)&semaphore); + + return MARS_SUCCESS; +} + +int mars_task_semaphore_release(uint64_t semaphore_ea) +{ + /* check function params */ + if (!semaphore_ea) + return MARS_ERROR_NULL; + if (semaphore_ea & MARS_TASK_SEMAPHORE_ALIGN_MASK) + return MARS_ERROR_ALIGN; + + mars_mutex_lock_get(semaphore_ea, (struct mars_mutex *)&semaphore); + + /* increment semaphore count */ + semaphore.count++; + + /* signal those that are waiting */ + if (semaphore.count > 0 && semaphore.wait_count) { + /* decrement semaphore count */ + semaphore.count--; + + /* signal waiting task */ + mars_task_module_signal_send( + semaphore.wait_id[semaphore.wait_head]); + + /* flush id from wait list */ + semaphore.wait_count--; + semaphore.wait_head++; + semaphore.wait_head %= MARS_TASK_SEMAPHORE_WAIT_MAX; + } + + mars_mutex_unlock_put(semaphore_ea, (struct mars_mutex *)&semaphore); + + return MARS_SUCCESS; +} diff --git a/common/libspumars/spu/task/lib/task_signal.c b/common/libspumars/spu/task/lib/task_signal.c new file mode 100644 index 00000000..3bdcf014 --- /dev/null +++ b/common/libspumars/spu/task/lib/task_signal.c @@ -0,0 +1,33 @@ +#include +#include +#include + +#include "../module/task_module.h" + +int mars_task_signal_send(struct mars_task_id *id) +{ + /* check function params */ + if (!id) + return MARS_ERROR_NULL; + + return mars_task_module_signal_send(id->workload_id); +} + +int mars_task_signal_wait(void) +{ + struct mars_task_context *task; + + /* get task context */ + task = mars_task_module_get_task(); + + /* make sure task context has a context save area */ + if (!task->context_save_area_ea) + return MARS_ERROR_FORMAT; + + return mars_task_module_signal_wait(mars_task_module_get_heap()); +} + +int mars_task_signal_try_wait(void) +{ + return mars_task_module_signal_try_wait(); +} diff --git a/common/libspumars/spu/task/module/task_module.c b/common/libspumars/spu/task/module/task_module.c new file mode 100644 index 00000000..9d77fe5d --- /dev/null +++ b/common/libspumars/spu/task/module/task_module.c @@ -0,0 +1,358 @@ +#include + +#include +#include + +#include "task_module.h" + +#define MARS_TASK_MODULE_DMA_SIZE_MAX 16384 +#define MARS_TASK_MODULE_DMA_SIZE_MASK 0x7f + +/* global task variables */ +static struct mars_task_context *task; + +/* called by task_switch.S */ +void __module_main(void); +void __dma_registers(void *ptr, int put); +void __task_save(void *task_heap); +void __task_restore(int task_cached); + +/* defined in task_switch.S */ +extern void *__task_stack; +extern void task_exit(void); +extern void task_save(void *task_heap, int wait); +extern void task_restore(int task_cached); + +/* task entry */ +typedef void (*mars_task_entry)(struct mars_task_args *args, + struct mars_task_module_syscalls *task_module_syscalls); + +static uint32_t get_ticks(void) +{ + return mars_module_get_ticks(); +} + +static uint16_t get_kernel_id(void) +{ + return mars_module_get_kernel_id(); +} + +static struct mars_task_context *get_task(void) +{ + return (struct mars_task_context *)mars_module_get_workload(); +} + +static struct mars_task_context * + get_task_by_id(const struct mars_task_id *task_id) +{ + return (struct mars_task_context *) + mars_module_get_workload_by_id(task_id->workload_id); +} + +static void dma_wait(void) +{ + mars_module_dma_wait(MARS_TASK_MODULE_DMA_TAG); +} + +static void dma(void *ls, uint64_t ea, int size, int put) +{ + if (put) + mars_module_dma_put(ls, ea, size, MARS_TASK_MODULE_DMA_TAG); + else + mars_module_dma_get(ls, ea, size, MARS_TASK_MODULE_DMA_TAG); +} + +/* + * Structure of Context Save Area + * High Address + * +------------------------------------+ + * | Local Storage (stack) | + * +------------------------------------+ + * | Local Storage (text + data + heap) | + * +------------------------------------+ + * | Non-volatile Registers | + * +------------------------------------+ + * Low Address +*/ +static void dma_context(uint32_t low_size, uint32_t high_size, int put) +{ + /* save or restore data segment and heap (low address) */ + dma((void *)task->data_vaddr, task->context_save_area_ea + + MARS_TASK_REGISTER_SAVE_AREA_SIZE, + low_size, put); + + /* save or restore stack (high address) */ + dma((void *)MARS_TASK_BASE_ADDR + MARS_TASK_CONTEXT_SAVE_SIZE_MAX - + high_size, task->context_save_area_ea + + MARS_TASK_REGISTER_SAVE_AREA_SIZE + low_size, + high_size, put); + + dma_wait(); +} + +void __dma_registers(void *ptr, int put) +{ + /* dma registers state to/from the context save area */ + dma(ptr, task->context_save_area_ea, MARS_TASK_REGISTER_SAVE_AREA_SIZE, + put); + + dma_wait(); +} + +void __task_save(void *task_heap) +{ + /* save workload stack pointer */ + task->stack = (uint32_t)__task_stack; + + /* save data segment and heap size (low address) */ + task->context_save_area_low_size = + ((uintptr_t)task_heap - task->data_vaddr + + MARS_TASK_MODULE_DMA_SIZE_MASK) & + ~MARS_TASK_MODULE_DMA_SIZE_MASK; + + /* save used stack size (high address) */ + task->context_save_area_high_size = + (MARS_TASK_BASE_ADDR + MARS_TASK_CONTEXT_SAVE_SIZE_MAX - + (uintptr_t)__task_stack + + MARS_TASK_MODULE_DMA_SIZE_MASK) & + ~MARS_TASK_MODULE_DMA_SIZE_MASK; + + /* save context MPU storage state */ + dma_context(task->context_save_area_low_size, + task->context_save_area_high_size, 1); +} + +void __task_restore(int task_cached) +{ + /* if task not cashed restore context MPU storage state */ + if (!task_cached) + dma_context(task->context_save_area_low_size, + task->context_save_area_high_size, 0); + + /* restore workload stack pointer */ + __task_stack = (void *)task->stack; +} + +static void task_yield(void *task_heap) +{ + task_save(task_heap, 0); +} + +static void task_arg_copy(struct mars_task_args* __restrict__ dst, const struct mars_task_args* __restrict__ src) +{ + __vector const int *v_src = (__vector const int*)src; + __vector int *v_dst = (__vector int*)dst; + __vector int *v_end = (__vector int*)((char*)src + sizeof(*src)); + while(__builtin_expect(v_src < v_end, 1)) + *v_dst++ = *v_src++; +} + +static int task_schedule(uint16_t workload_id, + const struct mars_task_args *args, + uint8_t priority) +{ + int ret; + struct mars_task_context *schedule_task; + struct mars_workload_context *schedule_workload; + + ret = mars_module_workload_schedule_begin(workload_id, priority, + &schedule_workload); + if (ret != MARS_SUCCESS) + return ret; + + /* cast workload context to task context */ + schedule_task = (struct mars_task_context *)schedule_workload; + + /* initialize task specific context variables */ + schedule_task->stack = 0; + schedule_task->exit_code = 0; + if (args) + task_arg_copy(&schedule_task->args, args); + + /* end process to schedule the workload in the workload queue */ + return mars_module_workload_schedule_end(workload_id, 0); +} + +static int task_unschedule(uint16_t workload_id, int32_t exit_code) +{ + int ret; + struct mars_task_context *unschedule_task; + struct mars_workload_context *unschedule_workload; + + ret = mars_module_workload_unschedule_begin(workload_id, + &unschedule_workload); + if (ret != MARS_SUCCESS) + return ret; + + /* cast workload context to task context */ + unschedule_task = (struct mars_task_context *)unschedule_workload; + + unschedule_task->exit_code = exit_code; + + /* end process to unschedule the workload in the workload queue */ + return mars_module_workload_unschedule_end(workload_id); +} + +static int task_wait(uint16_t workload_id, void *task_heap) +{ + int ret; + + ret = mars_module_workload_wait_set(workload_id); + if (ret != MARS_SUCCESS) + return ret; + + task_save(task_heap, 1); + + return mars_module_workload_wait_reset(); +} + +static int task_try_wait(uint16_t workload_id) +{ + /* make sure workload is initialized */ + if (!mars_module_workload_query(workload_id, + MARS_WORKLOAD_QUERY_IS_INITIALIZED)) + return MARS_ERROR_STATE; + + /* if workload not finished return busy */ + if (!mars_module_workload_query(workload_id, + MARS_WORKLOAD_QUERY_IS_FINISHED)) + return MARS_ERROR_BUSY; + + return mars_module_workload_wait_reset(); +} + +static void task_signal_host(uint64_t watch_point_ea) +{ + mars_module_host_signal_send(watch_point_ea); +} + +static int task_signal_send(uint16_t workload_id) +{ + return mars_module_workload_signal_set(workload_id); +} + +static int task_signal_wait(void *task_heap) +{ + task_save(task_heap, 1); + + return mars_module_workload_signal_reset(); +} + +static int task_signal_try_wait(void) +{ + /* if signal not yet received return busy */ + if (!mars_module_workload_query(mars_module_get_workload_id(), + MARS_WORKLOAD_QUERY_IS_SIGNAL_SET)) + return MARS_ERROR_BUSY; + + return mars_module_workload_signal_reset(); +} + +static int task_call_host(uint64_t callback_ea, + const struct mars_callback_args *in, + struct mars_callback_args *out, void *task_heap) +{ + int ret; + + ret = mars_module_host_callback_set(callback_ea, in); + if (ret != MARS_SUCCESS) + return ret; + + task_save(task_heap, 1); + + mars_module_workload_signal_reset(); + + return mars_module_host_callback_reset(out); +} + +static struct mars_task_module_syscalls task_module_syscalls = +{ + get_ticks, + get_kernel_id, + get_task, + get_task_by_id, + + task_exit, + task_yield, + task_schedule, + task_unschedule, + task_wait, + task_try_wait, + task_signal_host, + task_signal_send, + task_signal_wait, + task_signal_try_wait, + task_call_host, + + mars_module_mutex_lock_get, + mars_module_mutex_unlock_put, + + mars_module_dma_get, + mars_module_dma_put, + mars_module_dma_wait +}; + +static void task_run(void) +{ + __vector unsigned char *bss_ptr, *bss_end; + + /* load the read-write data segment */ + dma((void *)task->data_vaddr, task->data_ea, task->data_size, 0); + + /* 0 the bss section */ + bss_ptr = (__vector unsigned char *)(task->data_vaddr + + task->data_size); + bss_end = (__vector unsigned char *)((void *)bss_ptr + + task->bss_size); + + while (__builtin_expect(bss_ptr < bss_end, 1)) + *bss_ptr++ = spu_splats((unsigned char)0); + + dma_wait(); + + /* sync before executing loaded code */ + spu_sync(); + + /* call entry function */ + ((mars_task_entry)task->entry)(&task->args, &task_module_syscalls); +} + +void __module_main(void) +{ + int task_cached = 0; + int text_cached = 0; + uint64_t *cached_text_ea = (uint64_t *)(MARS_TASK_BASE_ADDR - 16); + + /* get task context */ + task = get_task(); + + /* check if this workload module was in the cache */ + if (mars_module_workload_query(mars_module_get_workload_id(), + MARS_WORKLOAD_QUERY_IS_MODULE_CACHED)) { + /* check if task context is cached in mpu storage */ + task_cached = mars_module_workload_query( + mars_module_get_workload_id(), + MARS_WORKLOAD_QUERY_IS_CONTEXT_CACHED); + + /* check if text is cached in mpu storage */ + text_cached = task_cached || (*cached_text_ea == task->text_ea); + } + + /* only reload the readonly text segment if different from cached */ + if (!text_cached) { + /* set info of current cached text */ + *cached_text_ea = task->text_ea; + + /* dma text segment from host storage to mpu storage */ + dma((void *)MARS_TASK_BASE_ADDR, + task->text_ea, task->text_size, 0); + } + + /* if stack pointer is uninitialized run fresh, otherwise resume */ + if (!task->stack) + task_run(); + else + task_restore(task_cached); + + /* we should never reach here */ +} diff --git a/common/libspumars/spu/task/module/task_module.h b/common/libspumars/spu/task/module/task_module.h new file mode 100644 index 00000000..a312b29a --- /dev/null +++ b/common/libspumars/spu/task/module/task_module.h @@ -0,0 +1,179 @@ +#ifndef __MARS_TASK_MODULE_H__ +#define __MARS_TASK_MODULE_H__ + +#include +#include + +#include "mars/callback_types.h" +#include "mars/mutex_types.h" +#include "mars/task_types.h" + +#include "task_internal_types.h" + +#define MARS_TASK_MODULE_DMA_TAG 31 +#define MARS_TASK_MODULE_DMA_TAG_MAX 31 + +/* mars task module syscalls */ +struct mars_task_module_syscalls { + uint32_t (*get_ticks)(void); + uint16_t (*get_kernel_id)(void); + struct mars_task_context * (*get_task)(void); + struct mars_task_context * (*get_task_by_id) + (const struct mars_task_id *task_id); + + void (*exit)(void); + void (*yield)(void *heap); + int (*schedule)(uint16_t workload_id, + const struct mars_task_args *args, + uint8_t priority); + int (*unschedule)(uint16_t workload_id, int32_t exit_code); + int (*wait)(uint16_t workload_id, void *heap); + int (*try_wait)(uint16_t workload_id); + void (*signal_host)(uint64_t watch_point_ea); + int (*signal_send)(uint16_t workload_id); + int (*signal_wait)(void *heap); + int (*signal_try_wait)(void); + int (*call_host)(uint64_t callback_ea, + const struct mars_callback_args *in, + struct mars_callback_args *out, void *heap); + + int (*mutex_lock_get)(uint64_t mutex_ea, + struct mars_mutex *mutex); + int (*mutex_unlock_put)(uint64_t mutex_ea, + struct mars_mutex *mutex); + + int (*dma_get)(void *ls, uint64_t ea, uint32_t size, uint32_t tag); + int (*dma_put)(const void *ls, uint64_t ea, uint32_t size, + uint32_t tag); + int (*dma_wait)(uint32_t tag); +}; + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct mars_task_module_syscalls *mars_task_module_syscalls; + +static inline void *mars_task_module_get_heap(void) +{ + return sbrk(0); +} + +static inline uint32_t mars_task_module_get_ticks(void) +{ + return (*mars_task_module_syscalls->get_ticks)(); +} + +static inline uint16_t mars_task_module_get_kernel_id(void) +{ + return (*mars_task_module_syscalls->get_kernel_id)(); +} + +static inline struct mars_task_context *mars_task_module_get_task(void) +{ + return (*mars_task_module_syscalls->get_task)(); +} + +static inline struct mars_task_context *mars_task_module_get_task_by_id + (const struct mars_task_id *task_id) +{ + return (*mars_task_module_syscalls->get_task_by_id)(task_id); +} + +static inline void mars_task_module_exit(void) +{ + (*mars_task_module_syscalls->exit)(); +} + +static inline void mars_task_module_yield(void *task_heap) +{ + (*mars_task_module_syscalls->yield)(task_heap); +} + +static inline int mars_task_module_schedule(uint16_t workload_id, + const struct mars_task_args *args, + uint8_t priority) +{ + return (*mars_task_module_syscalls->schedule)(workload_id, args, + priority); +} + +static inline int mars_task_module_unschedule(uint16_t workload_id, + int32_t exit_code) +{ + return (*mars_task_module_syscalls->unschedule)(workload_id, exit_code); +} + +static inline int mars_task_module_wait(uint16_t workload_id, void *task_heap) +{ + return (*mars_task_module_syscalls->wait)(workload_id, task_heap); +} + +static inline int mars_task_module_try_wait(uint16_t workload_id) +{ + return (*mars_task_module_syscalls->try_wait)(workload_id); +} + +static inline void mars_task_module_signal_host(uint64_t watch_point_ea) +{ + (*mars_task_module_syscalls->signal_host)(watch_point_ea); +} + +static inline int mars_task_module_signal_send(uint16_t workload_id) +{ + return (*mars_task_module_syscalls->signal_send)(workload_id); +} + +static inline int mars_task_module_signal_wait(void *task_heap) +{ + return (*mars_task_module_syscalls->signal_wait)(task_heap); +} + +static inline int mars_task_module_signal_try_wait(void) +{ + return (*mars_task_module_syscalls->signal_try_wait)(); +} + +static inline int mars_task_module_call_host(uint64_t callback_ea, + const struct mars_callback_args *in, + struct mars_callback_args *out, + void *task_heap) +{ + return (*mars_task_module_syscalls->call_host)(callback_ea, in, out, + task_heap); +} + +static inline int mars_mutex_lock_get(uint64_t mutex_ea, + struct mars_mutex *mutex) +{ + return (*mars_task_module_syscalls->mutex_lock_get)(mutex_ea, mutex); +} + +static inline int mars_mutex_unlock_put(uint64_t mutex_ea, + struct mars_mutex *mutex) +{ + return (*mars_task_module_syscalls->mutex_unlock_put)(mutex_ea, mutex); +} + +static inline int mars_dma_get(void *ls, uint64_t ea, uint32_t size, + uint32_t tag) +{ + return (*mars_task_module_syscalls->dma_get)(ls, ea, size, tag); +} + +static inline int mars_dma_put(const void *ls, uint64_t ea, uint32_t size, + uint32_t tag) +{ + return (*mars_task_module_syscalls->dma_put)(ls, ea, size, tag); +} + +static inline int mars_dma_wait(uint32_t tag) +{ + return (*mars_task_module_syscalls->dma_wait)(tag); +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/common/libspumars/spu/task/module/task_switch.S b/common/libspumars/spu/task/module/task_switch.S new file mode 100644 index 00000000..195431c0 --- /dev/null +++ b/common/libspumars/spu/task/module/task_switch.S @@ -0,0 +1,195 @@ +#define NUM_REGS 48 /* number of registers to be saved/restored */ + +.section .bss + +/* void *__module_stack */ +.align 4 +.globl __module_stack +__module_stack: +.space 16 + +/* void *__task_stack */ +.align 4 +.globl __task_stack +__task_stack: +.space 16 + +/* void *__work_stack*/ +.align 4 +.global __work_stack +__work_stack: +.space (NUM_REGS + 3) * 16 + + +.text + +/* void mars_module_main(void) */ +.global mars_module_main +.type mars_module_main, @function +mars_module_main: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain */ + ai $SP, $SP, -32 /* push stack frame */ + + stqa $SP, __module_stack /* save module stack */ + brsl $LR, __module_main /* call module main body */ + + ai $SP, $SP, 32 /* pop stack frame */ + lqd $LR, 16($SP) /* restore link register */ + bi $LR /* return */ + +.size mars_module_main, .-mars_module_main + + +/* void task_exit(void) */ +.global task_exit +.type task_exit, @function +task_exit: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain */ + ai $SP, $SP, -32 /* push stack frame */ + + lqa $SP, __module_stack /* restore module stack */ + br mars_module_workload_finish /* module finish (no return) */ + +.size task_exit, .-task_exit + + +/* void task_save(void *task_heap, int wait) */ +.global task_save +.type task_save, @function +task_save: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain */ + ai $SP, $SP, -32 /* push stack frame */ + + stqa $4, __work_stack /* save func param */ + + stqa $SP, __task_stack /* save task stack */ + + lqa $SP, __module_stack /* restore module stack */ + + brsl $LR, __task_save /* call task save body */ + + brsl $LR, __registers_save /* save registers */ + + lqa $2, __work_stack /* restore func param */ + + brz $2, mars_module_workload_yield /* module yield (no return) */ + br mars_module_workload_wait /* module wait (no return) */ + +.size task_save, .-task_save + + +/* void task_restore(int task_cached) */ +.global task_restore +.type task_restore, @function +task_restore: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain */ + ai $SP, $SP, -32 /* push stack frame */ + + stqa $3, __work_stack /* save func param */ + + brsl $LR, __registers_restore /* restore registers */ + + lqa $3, __work_stack /* restore func param */ + + brsl $LR, __task_restore /* call task restore body */ + + lqa $SP, __task_stack /* restore task stack */ + sync /* sync before execution */ + + ai $SP, $SP, 32 /* pop task_save stack frame */ + lqd $LR, 16($SP) /* restore link register */ + bi $LR /* return from task_save call */ + +.size task_restore, .-task_restore + + +/* + * Registers are saved/restored to task module work stack + * + * High Address +* +------------------------+ <--- TOP OF STACK (__work_stack + 48 + 768) + * | Non-volatile Registers | | + * | $127 | | + * | $126 | | + * | $125 | (size) + * | ... | NUM_REGS * 16 (48 * 16 = 768) + * | $82 | | + * | $81 | | + * | $80 | | + * +------------------------+ <--- REGS_PTR (__work_stack + 48) + * | Work Code Block | + * +------------------------+ <--- CODE_PTR + 16 (__work_stack + 32) + * | Loop Code Block | + * +------------------------+ <--- CODE_PTR (__work_stack + 16) + * | Save Func Param | + * +------------------------+ <--- __work_stack + * Low Address + */ + +#define CODE_PTR $74 /* where code will be loaded into stack */ +#define REGS_PTR $75 /* where regs will be placed into stack */ +#define REGS_INC $76 /* register increment value for instruction */ +#define TEMP $77 /* temporary register */ +#define INST $78 /* register to store volatile instruction */ +#define INST_MASK $79 /* mask instruction to store or load */ + +__registers_save: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain pointer */ + ai $SP, $SP, -32 /* push stack frame */ + + il INST_MASK, 0 /* no mask - default is stqd */ + br body /* jump to the body */ + +__registers_restore: + stqd $LR, 16($SP) /* save link register */ + stqd $SP, -32($SP) /* save back chain pointer */ + ai $SP, $SP, -32 /* push stack frame */ + + ila $3, __work_stack + 48 /* ptr = __work_stack */ + il $4, 0 /* restore so put = 0 */ + brsl $LR, __dma_registers /* call __dma_registers(0) */ + + il INST_MASK, 16 /* set necessary bits */ + shlqbyi INST_MASK, INST_MASK, 15 /* shift to correct position */ + +body: + ila CODE_PTR, __work_stack + 16 /* set code load addr pointer */ + ila REGS_PTR, __work_stack + 48 /* set regs load addr pointer */ + lqr TEMP, loop /* load loop code to register */ + stqd TEMP, 0(CODE_PTR) /* store loop code to stack */ + lqr INST, inst /* load inst code to register */ + or INST, INST, INST_MASK /* mask instr to stqd or lqd */ + il REGS_INC, 1 /* set bit in reg incrementer */ + shlqbyi REGS_INC, REGS_INC, 12 /* shift to correct word slot */ + il TEMP, NUM_REGS - 1 /* initialize loop counter */ + sync /* wait till loop code stored */ + bisl $LR, CODE_PTR /* jump and return */ + + brnz INST_MASK, done /* restore called so done */ + + ila $3, __work_stack + 48 /* ptr = __work_stack */ + il $4, 1 /* regs save so put = 1 */ + brsl $LR, __dma_registers /* call __dma_registers(1) */ + +done: + ai $SP, $SP, 32 /* pop stack frame */ + lqd $LR, 16($SP) /* load saved link register */ + bi $LR /* done so return to caller */ + + .balignl 16, 0 /* align self modifying code */ +loop: + stqd INST, 16(CODE_PTR) /* store inst code to stack */ + a INST, INST, REGS_INC /* increment register number */ + ai TEMP, TEMP, -1 /* decrment loop counter */ + sync /* wait till inst code stored */ + +inst: + stqd $80, 0(REGS_PTR) /* store reg to stack */ + ai REGS_PTR, REGS_PTR, 16 /* increment regs pointer */ + biz TEMP, $LR /* if (TEMP == 0) done */ + br loop /* if (TEMP != 0) loop */ diff --git a/common/libspumars/task/common/task_barrier_internal_types.h b/common/libspumars/task/common/task_barrier_internal_types.h new file mode 100644 index 00000000..b973c66d --- /dev/null +++ b/common/libspumars/task/common/task_barrier_internal_types.h @@ -0,0 +1,22 @@ +#ifndef __MARS_TASK_BARRIER_INTERNAL_TYPES_H__ +#define __MARS_TASK_BARRIER_INTERNAL_TYPES_H__ + +#include + +#define MARS_TASK_BARRIER_SIZE 128 +#define MARS_TASK_BARRIER_ALIGN 128 +#define MARS_TASK_BARRIER_ALIGN_MASK 0x7f + +struct mars_task_barrier { + uint32_t lock; + uint32_t total; + uint32_t notified_count; + uint32_t waited_count; + uint16_t notify_wait_count; + uint16_t notify_wait_id[MARS_TASK_BARRIER_WAIT_MAX]; + uint16_t wait_count; + uint16_t wait_id[MARS_TASK_BARRIER_WAIT_MAX]; + uint64_t mars_context_ea; +} __attribute__((aligned(MARS_TASK_BARRIER_ALIGN))); + +#endif diff --git a/common/libspumars/task/common/task_event_flag_internal_types.h b/common/libspumars/task/common/task_event_flag_internal_types.h new file mode 100644 index 00000000..f5fae5e1 --- /dev/null +++ b/common/libspumars/task/common/task_event_flag_internal_types.h @@ -0,0 +1,22 @@ +#ifndef __MARS_TASK_EVENT_FLAG_INTERNAL_TYPES_H__ +#define __MARS_TASK_EVENT_FLAG_INTERNAL_TYPES_H__ + +#include + +#define MARS_TASK_EVENT_FLAG_SIZE 128 +#define MARS_TASK_EVENT_FLAG_ALIGN 128 +#define MARS_TASK_EVENT_FLAG_ALIGN_MASK 0x7f + +struct mars_task_event_flag { + uint32_t lock; + uint32_t bits; + uint8_t direction; + uint8_t clear_mode; + uint16_t wait_count; + uint16_t wait_id[MARS_TASK_EVENT_FLAG_WAIT_MAX + 1]; + uint32_t wait_mask[MARS_TASK_EVENT_FLAG_WAIT_MAX]; + uint8_t wait_mask_mode[MARS_TASK_EVENT_FLAG_WAIT_MAX + 1]; + uint64_t mars_context_ea; +} __attribute__((aligned(MARS_TASK_EVENT_FLAG_ALIGN))); + +#endif diff --git a/common/libspumars/task/common/task_internal_types.h b/common/libspumars/task/common/task_internal_types.h new file mode 100644 index 00000000..e6db0416 --- /dev/null +++ b/common/libspumars/task/common/task_internal_types.h @@ -0,0 +1,44 @@ +#ifndef __MARS_TASK_INTERNAL_TYPES_H__ +#define __MARS_TASK_INTERNAL_TYPES_H__ + +#include + +#include "mars/workload_types.h" + +#define MARS_TASK_MODULE_NAME "MARS TASK" + +#define MARS_TASK_CONTEXT_SIZE MARS_WORKLOAD_CONTEXT_SIZE +#define MARS_TASK_CONTEXT_ALIGN MARS_WORKLOAD_CONTEXT_ALIGN +#define MARS_TASK_CONTEXT_SAVE_ALIGN 128 + +#define MARS_TASK_REGISTER_SAVE_AREA_SIZE (16 * (127 - 80)) + +struct mars_task_context { + uint8_t workload_reserved[MARS_WORKLOAD_RESERVED_SIZE]; + + uint64_t text_ea; /* ea of text segment */ + uint64_t data_ea; /* ea of data segment */ + uint32_t text_vaddr; /* vaddr of text segment */ + uint32_t data_vaddr; /* vaddr of data segment */ + uint32_t text_size; /* size of text segment */ + uint32_t data_size; /* size of data segment */ + uint32_t bss_size; /* size of bss segment */ + uint32_t entry; /* entry address of exec */ + uint32_t stack; /* stack pointer of exec */ + uint32_t exit_code; /* exit code */ + uint64_t context_save_area_ea; /* context save area */ + uint32_t context_save_area_low_size; /* size of low save area */ + uint32_t context_save_area_high_size; /* size of high save area */ + struct mars_task_id id; /* task id */ + struct mars_task_args args; /* task args */ + + uint8_t pad[MARS_TASK_CONTEXT_SIZE - + (MARS_WORKLOAD_RESERVED_SIZE + + sizeof(uint64_t)*3 + + sizeof(uint32_t)*10 + + sizeof(struct mars_task_id) + + sizeof(struct mars_task_args)) + ]; +} __attribute__((aligned(MARS_TASK_CONTEXT_ALIGN))); + +#endif diff --git a/common/libspumars/task/common/task_queue_internal_types.h b/common/libspumars/task/common/task_queue_internal_types.h new file mode 100644 index 00000000..7f428bb0 --- /dev/null +++ b/common/libspumars/task/common/task_queue_internal_types.h @@ -0,0 +1,34 @@ +#ifndef __MARS_TASK_QUEUE_INTERNAL_TYPES_H__ +#define __MARS_TASK_QUEUE_INTERNAL_TYPES_H__ + +#include + +#define MARS_TASK_QUEUE_SIZE 128 +#define MARS_TASK_QUEUE_ALIGN 128 +#define MARS_TASK_QUEUE_ALIGN_MASK 0x7f +#define MARS_TASK_QUEUE_ENTRY_SIZE_MASK 0xf +#define MARS_TASK_QUEUE_ENTRY_ALIGN 16 +#define MARS_TASK_QUEUE_ENTRY_ALIGN_MASK 0xf +#define MARS_TASK_QUEUE_BUFFER_ALIGN 16 +#define MARS_TASK_QUEUE_BUFFER_ALIGN_MASK 0xf + +struct mars_task_queue { + uint32_t lock; + uint32_t size; + uint32_t depth; + uint32_t count; + uint64_t buffer_ea; + uint64_t push_ea; + uint64_t pop_ea; + uint8_t pad; + uint8_t direction; + uint8_t push_wait_head; + uint8_t pop_wait_head; + uint16_t push_wait_count; + uint16_t pop_wait_count; + uint16_t push_wait_id[MARS_TASK_QUEUE_WAIT_MAX]; + uint16_t pop_wait_id[MARS_TASK_QUEUE_WAIT_MAX]; + uint64_t mars_context_ea; +} __attribute__((aligned(MARS_TASK_QUEUE_ALIGN))); + +#endif diff --git a/common/libspumars/task/common/task_semaphore_internal_types.h b/common/libspumars/task/common/task_semaphore_internal_types.h new file mode 100644 index 00000000..07c0f88b --- /dev/null +++ b/common/libspumars/task/common/task_semaphore_internal_types.h @@ -0,0 +1,20 @@ +#ifndef __MARS_TASK_SEMAPHORE_INTERNAL_TYPES_H__ +#define __MARS_TASK_SEMAPHORE_INTERNAL_TYPES_H__ + +#include + +#define MARS_TASK_SEMAPHORE_SIZE 128 +#define MARS_TASK_SEMAPHORE_ALIGN 128 +#define MARS_TASK_SEMAPHORE_ALIGN_MASK 0x7f + +struct mars_task_semaphore { + uint32_t lock; + int32_t count; + uint16_t wait_count; + uint16_t wait_id[MARS_TASK_SEMAPHORE_WAIT_MAX]; + uint8_t wait_head; + uint8_t pad; + uint64_t mars_context_ea; +} __attribute__((aligned(MARS_TASK_SEMAPHORE_ALIGN))); + +#endif diff --git a/common/vectormath/ppu/c/mat_aos.h b/common/vectormath/ppu/c/mat_aos.h index dbf1ab87..c0ce539e 100644 --- a/common/vectormath/ppu/c/mat_aos.h +++ b/common/vectormath/ppu/c/mat_aos.h @@ -1,1833 +1,1833 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_MAT_AOS_C_H -#define _VECTORMATH_MAT_AOS_C_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Constants - * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - */ -#define _VECTORMATH_PERM_ZBWX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XCYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_C, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B }) -#define _VECTORMATH_PERM_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W, _VECTORMATH_PERM_C, _VECTORMATH_PERM_D }) -#define _VECTORMATH_PERM_XZBX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_CXXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_YAXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W, _VECTORMATH_PERM_Z }) -#define _VECTORMATH_PERM_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_D }) -#define _VECTORMATH_PERM_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y }) -#define _VECTORMATH_PERM_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_ZAYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_BZXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A }) -#define _VECTORMATH_PERM_ZXXB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_B }) -#define _VECTORMATH_PERM_YXXC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_BBYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_B, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PI_OVER_2 1.570796327f - -/*----------------------------------------------------------------------------- - * Definitions - */ -static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( &result->col0, &mat->col0 ); - vmathV3Copy( &result->col1, &mat->col1 ); - vmathV3Copy( &result->col2, &mat->col2 ); -} - -static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ) -{ - vmathV3MakeFromScalar( &result->col0, scalar ); - vmathV3MakeFromScalar( &result->col1, scalar ); - vmathV3MakeFromScalar( &result->col2, scalar ); -} - -static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) -{ - vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - vec_uint4 select_x = _VECTORMATH_MASK_0xF000; - vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; - xyzw_2 = vec_add( unitQuat->vec128, unitQuat->vec128 ); - wwww = vec_splat( unitQuat->vec128, 3 ); - yzxw = vec_perm( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_PERM_YZXW ); - zxyw = vec_perm( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_PERM_ZXYW ); - yzxw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_YZXW ); - zxyw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_ZXYW ); - tmp0 = vec_madd( yzxw_2, wwww, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - tmp1 = vec_nmsub( yzxw, yzxw_2, ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); - tmp2 = vec_madd( yzxw, xyzw_2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - tmp0 = vec_madd( zxyw, xyzw_2, tmp0 ); - tmp1 = vec_nmsub( zxyw, zxyw_2, tmp1 ); - tmp2 = vec_nmsub( zxyw_2, wwww, tmp2 ); - tmp3 = vec_sel( tmp0, tmp1, select_x ); - tmp4 = vec_sel( tmp1, tmp2, select_x ); - tmp5 = vec_sel( tmp2, tmp0, select_x ); - result->col0.vec128 = vec_sel( tmp3, tmp2, select_z ); - result->col1.vec128 = vec_sel( tmp4, tmp0, select_z ); - result->col2.vec128 = vec_sel( tmp5, tmp1, select_z ); -} - -static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col0, _col0 ); - vmathV3Copy( &result->col1, _col1 ); - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *_col0 ) -{ - vmathV3Copy( &result->col0, _col0 ); -} - -static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *_col1 ) -{ - vmathV3Copy( &result->col1, _col1 ); -} - -static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ) -{ - vmathV3Copy( (&result->col0 + col), vec ); -} - -static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ) -{ - vmathV3SetElem( &result->col0, row, vmathV3GetElem( vec, 0 ) ); - vmathV3SetElem( &result->col1, row, vmathV3GetElem( vec, 1 ) ); - vmathV3SetElem( &result->col2, row, vmathV3GetElem( vec, 2 ) ); -} - -static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ) -{ - VmathVector3 tmpV3_0; - vmathM3GetCol( &tmpV3_0, result, col ); - vmathV3SetElem( &tmpV3_0, row, val ); - vmathM3SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ) -{ - VmathVector3 tmpV3_0; - vmathM3GetCol( &tmpV3_0, mat, col ); - return vmathV3GetElem( &tmpV3_0, row ); -} - -static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col0 ); -} - -static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col1 ); -} - -static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col2 ); -} - -static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ) -{ - vmathV3Copy( result, (&mat->col0 + col) ); -} - -static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ) -{ - vmathV3MakeFromElems( result, vmathV3GetElem( &mat->col0, row ), vmathV3GetElem( &mat->col1, row ), vmathV3GetElem( &mat->col2, row ) ); -} - -static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, res0, res1, res2; - tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); - tmp1 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); - res0 = vec_mergeh( tmp0, mat->col1.vec128 ); - res1 = vec_perm( tmp0, mat->col1.vec128, _VECTORMATH_PERM_ZBWX ); - res2 = vec_perm( tmp1, mat->col1.vec128, _VECTORMATH_PERM_XCYX ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp2 = _vmathVfCross( mat->col0.vec128, mat->col1.vec128 ); - tmp0 = _vmathVfCross( mat->col1.vec128, mat->col2.vec128 ); - tmp1 = _vmathVfCross( mat->col2.vec128, mat->col0.vec128 ); - dot = _vmathVfDot3( tmp2, mat->col2.vec128 ); - dot = vec_splat( dot, 0 ); - invdet = recipf4( dot ); - tmp3 = vec_mergeh( tmp0, tmp2 ); - tmp4 = vec_mergel( tmp0, tmp2 ); - inv0 = vec_mergeh( tmp3, tmp1 ); - inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); - inv0 = vec_madd( inv0, invdet, zero ); - inv1 = vec_madd( inv1, invdet, zero ); - inv2 = vec_madd( inv2, invdet, zero ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; -} - -static inline float vmathM3Determinant( const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0; - vmathV3Cross( &tmpV3_0, &mat->col0, &mat->col1 ); - return vmathV3Dot( &mat->col2, &tmpV3_0 ); -} - -static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3Add( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3Add( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3Add( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3Sub( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3Sub( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3Sub( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Neg( &result->col0, &mat->col0 ); - vmathV3Neg( &result->col1, &mat->col1 ); - vmathV3Neg( &result->col2, &mat->col2 ); -} - -static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3AbsPerElem( &result->col0, &mat->col0 ); - vmathV3AbsPerElem( &result->col1, &mat->col1 ); - vmathV3AbsPerElem( &result->col2, &mat->col2 ); -} - -static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ) -{ - vmathV3ScalarMul( &result->col0, &mat->col0, scalar ); - vmathV3ScalarMul( &result->col1, &mat->col1, scalar ); - vmathV3ScalarMul( &result->col2, &mat->col2, scalar ); -} - -static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec->vec128, 0 ); - yyyy = vec_splat( vec->vec128, 1 ); - zzzz = vec_splat( vec->vec128, 2 ); - res = vec_madd( mat->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( mat->col1.vec128, yyyy, res ); - res = vec_madd( mat->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - VmathMatrix3 tmpResult; - vmathM3MulV3( &tmpResult.col0, mat0, &mat1->col0 ); - vmathM3MulV3( &tmpResult.col1, mat0, &mat1->col1 ); - vmathM3MulV3( &tmpResult.col2, mat0, &mat1->col2 ); - vmathM3Copy( result, &tmpResult ); -} - -static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3MakeIdentity( VmathMatrix3 *result ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); -} - -static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - vmathV3MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV3MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; -} - -static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV3MakeZAxis( &result->col2 ); -} - -static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ) -{ - VmathVector4 tmpV4_0; - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); - angles = tmpV4_0.vec128; - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - result->col0.vec128 = vec_madd( Z0, Y0, zero ); - result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); - result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); -} - -static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - axis = unitVec->vec128; - sincosf4( (vec_float4){radians,radians,radians,radians}, &s, &c ); - xxxx = vec_splat( axis, 0 ); - yyyy = vec_splat( axis, 1 ); - zzzz = vec_splat( axis, 2 ); - oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); - axisS = vec_madd( axis, s, zero ); - negAxisS = negatef4( axisS ); - tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); - tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); - tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); - tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); - tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); - tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); - result->col0.vec128 = vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ); - result->col1.vec128 = vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ); - result->col2.vec128 = vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ); -} - -static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) -{ - vmathM3MakeFromQ( result, unitQuat ); -} - -static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); - result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); - result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); -} - -static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ) -{ - vmathV3ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); - vmathV3ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); - vmathV3ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); -} - -static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ) -{ - vmathV3MulPerElem( &result->col0, &mat->col0, scaleVec ); - vmathV3MulPerElem( &result->col1, &mat->col1, scaleVec ); - vmathV3MulPerElem( &result->col2, &mat->col2, scaleVec ); -} - -static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ) -{ - vmathV3Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); - vmathV3Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); - vmathV3Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathM3Print( const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; - vmathM3GetRow( &tmpV3_0, mat, 0 ); - vmathV3Print( &tmpV3_0 ); - vmathM3GetRow( &tmpV3_1, mat, 1 ); - vmathV3Print( &tmpV3_1 ); - vmathM3GetRow( &tmpV3_2, mat, 2 ); - vmathV3Print( &tmpV3_2 ); -} - -static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ) -{ - printf("%s:\n", name); - vmathM3Print( mat ); -} - -#endif - -static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( &result->col0, &mat->col0 ); - vmathV4Copy( &result->col1, &mat->col1 ); - vmathV4Copy( &result->col2, &mat->col2 ); - vmathV4Copy( &result->col3, &mat->col3 ); -} - -static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ) -{ - vmathV4MakeFromScalar( &result->col0, scalar ); - vmathV4MakeFromScalar( &result->col1, scalar ); - vmathV4MakeFromScalar( &result->col2, scalar ); - vmathV4MakeFromScalar( &result->col3, scalar ); -} - -static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ) -{ - vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, &mat->col3, 1.0f ); -} - -static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *_col0, const VmathVector4 *_col1, const VmathVector4 *_col2, const VmathVector4 *_col3 ) -{ - vmathV4Copy( &result->col0, _col0 ); - vmathV4Copy( &result->col1, _col1 ); - vmathV4Copy( &result->col2, _col2 ); - vmathV4Copy( &result->col3, _col3 ); -} - -static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ) -{ - vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) -{ - VmathMatrix3 mat; - vmathM3MakeFromQ( &mat, unitQuat ); - vmathV4MakeFromV3Scalar( &result->col0, &mat.col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat.col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat.col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *_col0 ) -{ - vmathV4Copy( &result->col0, _col0 ); -} - -static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *_col1 ) -{ - vmathV4Copy( &result->col1, _col1 ); -} - -static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *_col2 ) -{ - vmathV4Copy( &result->col2, _col2 ); -} - -static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *_col3 ) -{ - vmathV4Copy( &result->col3, _col3 ); -} - -static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ) -{ - vmathV4Copy( (&result->col0 + col), vec ); -} - -static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ) -{ - vmathV4SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); - vmathV4SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); - vmathV4SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); - vmathV4SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); -} - -static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ) -{ - VmathVector4 tmpV3_0; - vmathM4GetCol( &tmpV3_0, result, col ); - vmathV4SetElem( &tmpV3_0, row, val ); - vmathM4SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ) -{ - VmathVector4 tmpV4_0; - vmathM4GetCol( &tmpV4_0, mat, col ); - return vmathV4GetElem( &tmpV4_0, row ); -} - -static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col0 ); -} - -static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col1 ); -} - -static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col2 ); -} - -static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col3 ); -} - -static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ) -{ - vmathV4Copy( result, (&mat->col0 + col) ); -} - -static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ) -{ - vmathV4MakeFromElems( result, vmathV4GetElem( &mat->col0, row ), vmathV4GetElem( &mat->col1, row ), vmathV4GetElem( &mat->col2, row ), vmathV4GetElem( &mat->col3, row ) ); -} - -static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; - tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); - tmp1 = vec_mergeh( mat->col1.vec128, mat->col3.vec128 ); - tmp2 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); - tmp3 = vec_mergel( mat->col1.vec128, mat->col3.vec128 ); - res0 = vec_mergeh( tmp0, tmp1 ); - res1 = vec_mergel( tmp0, tmp1 ); - res2 = vec_mergeh( tmp2, tmp3 ); - res3 = vec_mergel( tmp2, tmp3 ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; - result->col3.vec128 = res3; -} - -static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vector float in0, in1, in2, in3; - vector float tmp0, tmp1, tmp2, tmp3; - vector float cof0, cof1, cof2, cof3; - vector float t0, t1, t2, t3; - vector float t01, t02, t03, t12, t23; - vector float t1r, t2r; - vector float t01r, t02r, t03r, t12r, t23r; - vector float t1r3, t1r3r; - vector float det, det0, det1, det2, det3, invdet; - vector float vzero = (vector float){0.0}; - in0 = mat->col0.vec128; - in1 = mat->col1.vec128; - in2 = mat->col2.vec128; - in3 = mat->col3.vec128; - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ - tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ - tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ - tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ - t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ - t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ - t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ - t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ - t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ - cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ - cof1 = vec_nmsub(t0, t23, vzero); /* -(AGP ECL IOH MKD) */ - t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ - cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ - cof1 = vec_madd(t0, t23r, cof1); /* AOH EKD IGP MCL + cof1 */ - cof1 = vec_sld(cof1, cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ - t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ - t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ - cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - cof3 = vec_madd(t0, t12, vzero); /* ANG EJC IFO MBK */ - t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ - cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - cof3 = vec_nmsub(t0, t12r, cof3); /* cof3 - AFO EBK ING MJC */ - cof3 = vec_sld(cof3, cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ - t1r = vec_sld(t1, t1, 8); /* B F J N */ - t2r = vec_sld(t2, t2, 8); /* K O C G */ - t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ - t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ - cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - cof2 = vec_madd(t0, t1r3, vzero); /* AFP EBL INH MJD */ - t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ - cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - cof2 = vec_nmsub(t0, t1r3r, cof2); /* cof2 - ANH EJD IFP MBL */ - cof2 = vec_sld(cof2, cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ - t01 = vec_madd(t0, t1, vzero); /* AJ EN IB MF */ - t01 = vec_perm(t01, t01, _VECTORMATH_PERM_YXWZ); /* EN AJ MF IB */ - cof2 = vec_nmsub(t3, t01, cof2); /* cof2 - LEN PAJ DMF HIB */ - cof3 = vec_madd(t2r, t01, cof3); /* KEN OAJ CMF GIB + cof3 */ - t01r = vec_sld(t01, t01, 8); /* MF IB EN AJ */ - cof2 = vec_madd(t3, t01r, cof2); /* LMF PIB DEN HAJ + cof2 */ - cof3 = vec_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ - t03 = vec_madd(t0, t3, vzero); /* AL EP ID MH */ - t03 = vec_perm(t03, t03, _VECTORMATH_PERM_YXWZ); /* EP AL MH ID */ - cof1 = vec_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ - cof2 = vec_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ - t03r = vec_sld(t03, t03, 8); /* MH ID EP AL */ - cof1 = vec_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ - cof2 = vec_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ - t02 = vec_madd(t0, t2r, vzero); /* AK EO IC MG */ - t02 = vec_perm(t02, t02, _VECTORMATH_PERM_YXWZ); /* E0 AK MG IC */ - cof1 = vec_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ - cof3 = vec_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ - t02r = vec_sld(t02, t02, 8); /* MG IC EO AK */ - cof1 = vec_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ - cof3 = vec_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ - /* Compute the determinant of the matrix - * - * det = sum_across(t0 * cof0); - * - * We perform a sum across the entire vector so that - * we don't have to splat the result when multiplying the - * cofactors by the inverse of the determinant. - */ - det = vec_madd(t0, cof0, vzero); - det0 = vec_splat(det, 0); - det1 = vec_splat(det, 1); - det2 = vec_splat(det, 2); - det3 = vec_splat(det, 3); - det = vec_add(det0, det1); - det2 = vec_add(det2, det3); - det = vec_add(det, det2); - /* Compute the reciprocal of the determinant. - */ - invdet = recipf4(det); - /* Multiply the cofactors by the reciprocal of the determinant. - */ - result->col0.vec128 = vec_madd(cof0, invdet, vzero); - result->col1.vec128 = vec_madd(cof1, invdet, vzero); - result->col2.vec128 = vec_madd(cof2, invdet, vzero); - result->col3.vec128 = vec_madd(cof3, invdet, vzero); -} - -static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - VmathTransform3 affineMat, tmpT3_0; - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; - vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); - vmathT3SetCol0( &affineMat, &tmpV3_0 ); - vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); - vmathT3SetCol1( &affineMat, &tmpV3_1 ); - vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); - vmathT3SetCol2( &affineMat, &tmpV3_2 ); - vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); - vmathT3SetCol3( &affineMat, &tmpV3_3 ); - vmathT3Inverse( &tmpT3_0, &affineMat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - VmathTransform3 affineMat, tmpT3_0; - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; - vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); - vmathT3SetCol0( &affineMat, &tmpV3_0 ); - vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); - vmathT3SetCol1( &affineMat, &tmpV3_1 ); - vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); - vmathT3SetCol2( &affineMat, &tmpV3_2 ); - vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); - vmathT3SetCol3( &affineMat, &tmpV3_3 ); - vmathT3OrthoInverse( &tmpT3_0, &affineMat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline float vmathM4Determinant( const VmathMatrix4 *mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vector float in0, in1, in2, in3; - vector float tmp0, tmp1, tmp2, tmp3; - vector float cof0; - vector float t0, t1, t2, t3; - vector float t12, t23; - vector float t1r, t2r; - vector float t12r, t23r; - vector float t1r3, t1r3r; - vector float vzero = (vector float){0.0}; - union { vec_float4 v; float s[4]; } tmp; - in0 = mat->col0.vec128; - in1 = mat->col1.vec128; - in2 = mat->col2.vec128; - in3 = mat->col3.vec128; - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ - tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ - tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ - tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ - t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ - t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ - t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ - t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ - t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ - cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ - t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ - cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ - t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ - t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ - cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ - cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - t1r = vec_sld(t1, t1, 8); /* B F J N */ - t2r = vec_sld(t2, t2, 8); /* K O C G */ - t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ - t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ - cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ - cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - tmp.v = _vmathVfDot4(t0,cof0); - return tmp.s[0]; -} - -static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4Add( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4Add( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4Add( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4Add( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4Sub( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4Sub( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4Sub( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4Sub( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Neg( &result->col0, &mat->col0 ); - vmathV4Neg( &result->col1, &mat->col1 ); - vmathV4Neg( &result->col2, &mat->col2 ); - vmathV4Neg( &result->col3, &mat->col3 ); -} - -static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4AbsPerElem( &result->col0, &mat->col0 ); - vmathV4AbsPerElem( &result->col1, &mat->col1 ); - vmathV4AbsPerElem( &result->col2, &mat->col2 ); - vmathV4AbsPerElem( &result->col3, &mat->col3 ); -} - -static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ) -{ - vmathV4ScalarMul( &result->col0, &mat->col0, scalar ); - vmathV4ScalarMul( &result->col1, &mat->col1, scalar ); - vmathV4ScalarMul( &result->col2, &mat->col2, scalar ); - vmathV4ScalarMul( &result->col3, &mat->col3, scalar ); -} - -static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz, wwww; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( vec->vec128, 0 ); - yyyy = vec_splat( vec->vec128, 1 ); - zzzz = vec_splat( vec->vec128, 2 ); - wwww = vec_splat( vec->vec128, 3 ); - tmp0 = vec_madd( mat->col0.vec128, xxxx, zero ); - tmp1 = vec_madd( mat->col1.vec128, yyyy, zero ); - tmp0 = vec_madd( mat->col2.vec128, zzzz, tmp0 ); - tmp1 = vec_madd( mat->col3.vec128, wwww, tmp1 ); - res = vec_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec->vec128, 0 ); - yyyy = vec_splat( vec->vec128, 1 ); - zzzz = vec_splat( vec->vec128, 2 ); - res = vec_madd( mat->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( mat->col1.vec128, yyyy, res ); - res = vec_madd( mat->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( pnt->vec128, 0 ); - yyyy = vec_splat( pnt->vec128, 1 ); - zzzz = vec_splat( pnt->vec128, 2 ); - tmp0 = vec_madd( mat->col0.vec128, xxxx, zero ); - tmp1 = vec_madd( mat->col1.vec128, yyyy, zero ); - tmp0 = vec_madd( mat->col2.vec128, zzzz, tmp0 ); - tmp1 = vec_add( mat->col3.vec128, tmp1 ); - res = vec_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - VmathMatrix4 tmpResult; - vmathM4MulV4( &tmpResult.col0, mat0, &mat1->col0 ); - vmathM4MulV4( &tmpResult.col1, mat0, &mat1->col1 ); - vmathM4MulV4( &tmpResult.col2, mat0, &mat1->col2 ); - vmathM4MulV4( &tmpResult.col3, mat0, &mat1->col3 ); - vmathM4Copy( result, &tmpResult ); -} - -static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm1 ) -{ - VmathMatrix4 tmpResult; - VmathPoint3 tmpP3_0; - vmathM4MulV3( &tmpResult.col0, mat, &tfrm1->col0 ); - vmathM4MulV3( &tmpResult.col1, mat, &tfrm1->col1 ); - vmathM4MulV3( &tmpResult.col2, mat, &tfrm1->col2 ); - vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); - vmathM4MulP3( &tmpResult.col3, mat, &tmpP3_0 ); - vmathM4Copy( result, &tmpResult ); -} - -static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4MulPerElem( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4MakeIdentity( VmathMatrix4 *result ) -{ - vmathV4MakeXAxis( &result->col0 ); - vmathV4MakeYAxis( &result->col1 ); - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ) -{ - vmathV4SetXYZ( &result->col0, &mat3->col0 ); - vmathV4SetXYZ( &result->col1, &mat3->col1 ); - vmathV4SetXYZ( &result->col2, &mat3->col2 ); -} - -static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ) -{ - vmathV4GetXYZ( &result->col0, &mat->col0 ); - vmathV4GetXYZ( &result->col1, &mat->col1 ); - vmathV4GetXYZ( &result->col2, &mat->col2 ); -} - -static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) -{ - vmathV4SetXYZ( &result->col3, translateVec ); -} - -static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ) -{ - vmathV4GetXYZ( result, &mat->col3 ); -} - -static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - vmathV4MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV4MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ) -{ - VmathVector4 tmpV4_0; - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); - angles = tmpV4_0.vec128; - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - result->col0.vec128 = vec_madd( Z0, Y0, zero ); - result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); - result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - axis = unitVec->vec128; - sincosf4( (vec_float4){radians,radians,radians,radians}, &s, &c ); - xxxx = vec_splat( axis, 0 ); - yyyy = vec_splat( axis, 1 ); - zzzz = vec_splat( axis, 2 ); - oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); - axisS = vec_madd( axis, s, zero ); - negAxisS = negatef4( axisS ); - tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); - tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); - tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); - tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); - tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); - tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); - zeroW = (vec_float4)_VECTORMATH_MASK_0x000F; - axis = vec_andc( axis, zeroW ); - tmp0 = vec_andc( tmp0, zeroW ); - tmp1 = vec_andc( tmp1, zeroW ); - tmp2 = vec_andc( tmp2, zeroW ); - result->col0.vec128 = vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ); - result->col1.vec128 = vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ); - result->col2.vec128 = vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ) -{ - VmathTransform3 tmpT3_0; - vmathT3MakeRotationQ( &tmpT3_0, unitQuat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); - result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); - result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ) -{ - vmathV4ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); - vmathV4ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); - vmathV4ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); - vmathV4Copy( &result->col3, &mat->col3 ); -} - -static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ) -{ - VmathVector4 scale4; - vmathV4MakeFromV3Scalar( &scale4, scaleVec, 1.0f ); - vmathV4MulPerElem( &result->col0, &mat->col0, &scale4 ); - vmathV4MulPerElem( &result->col1, &mat->col1, &scale4 ); - vmathV4MulPerElem( &result->col2, &mat->col2, &scale4 ); - vmathV4MulPerElem( &result->col3, &mat->col3, &scale4 ); -} - -static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) -{ - vmathV4MakeXAxis( &result->col0 ); - vmathV4MakeYAxis( &result->col1 ); - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ) -{ - VmathMatrix4 m4EyeFrame; - VmathVector3 v3X, v3Y, v3Z, tmpV3_0, tmpV3_1; - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; - vmathV3Normalize( &v3Y, upVec ); - vmathP3Sub( &tmpV3_0, eyePos, lookAtPos ); - vmathV3Normalize( &v3Z, &tmpV3_0 ); - vmathV3Cross( &tmpV3_1, &v3Y, &v3Z ); - vmathV3Normalize( &v3X, &tmpV3_1 ); - vmathV3Cross( &v3Y, &v3Z, &v3X ); - vmathV4MakeFromV3( &tmpV4_0, &v3X ); - vmathV4MakeFromV3( &tmpV4_1, &v3Y ); - vmathV4MakeFromV3( &tmpV4_2, &v3Z ); - vmathV4MakeFromP3( &tmpV4_3, eyePos ); - vmathM4MakeFromCols( &m4EyeFrame, &tmpV4_0, &tmpV4_1, &tmpV4_2, &tmpV4_3 ); - vmathM4OrthoInverse( result, &m4EyeFrame ); -} - -static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ) -{ - float f, rangeInv; - vec_float4 zero, col0, col1, col2, col3; - union { vec_float4 v; float s[4]; } tmp; - f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); - rangeInv = 1.0f / ( zNear - zFar ); - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp.v = zero; - tmp.s[0] = f / aspect; - col0 = tmp.v; - tmp.v = zero; - tmp.s[1] = f; - col1 = tmp.v; - tmp.v = zero; - tmp.s[2] = ( zNear + zFar ) * rangeInv; - tmp.s[3] = -1.0f; - col2 = tmp.v; - tmp.v = zero; - tmp.s[2] = zNear * zFar * rangeInv * 2.0f; - col3 = tmp.v; - result->col0.vec128 = col0; - result->col1.vec128 = col1; - result->col2.vec128 = col2; - result->col3.vec128 = col3; -} - -static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff; - vec_float4 diagonal, column, near2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - union { vec_float4 v; float s[4]; } l, f, r, n, b, t; - l.s[0] = left; - f.s[0] = zFar; - r.s[0] = right; - n.s[0] = zNear; - b.s[0] = bottom; - t.s[0] = top; - lbf = vec_mergeh( l.v, f.v ); - rtn = vec_mergeh( r.v, n.v ); - lbf = vec_mergeh( lbf, b.v ); - rtn = vec_mergeh( rtn, t.v ); - diff = vec_sub( rtn, lbf ); - sum = vec_add( rtn, lbf ); - inv_diff = recipf4( diff ); - near2 = vec_splat( n.v, 0 ); - near2 = vec_add( near2, near2 ); - diagonal = vec_madd( near2, inv_diff, zero ); - column = vec_madd( sum, inv_diff, zero ); - result->col0.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ); - result->col1.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ); - result->col2.vec128 = vec_sel( column, ((vec_float4){-1.0f,-1.0f,-1.0f,-1.0f}), _VECTORMATH_MASK_0x000F ); - result->col3.vec128 = vec_sel( zero, vec_madd( diagonal, vec_splat( f.v, 0 ), zero ), _VECTORMATH_MASK_0x00F0 ); -} - -static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff, neg_inv_diff; - vec_float4 diagonal, column; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - union { vec_float4 v; float s[4]; } l, f, r, n, b, t; - l.s[0] = left; - f.s[0] = zFar; - r.s[0] = right; - n.s[0] = zNear; - b.s[0] = bottom; - t.s[0] = top; - lbf = vec_mergeh( l.v, f.v ); - rtn = vec_mergeh( r.v, n.v ); - lbf = vec_mergeh( lbf, b.v ); - rtn = vec_mergeh( rtn, t.v ); - diff = vec_sub( rtn, lbf ); - sum = vec_add( rtn, lbf ); - inv_diff = recipf4( diff ); - neg_inv_diff = negatef4( inv_diff ); - diagonal = vec_add( inv_diff, inv_diff ); - column = vec_madd( sum, vec_sel( neg_inv_diff, inv_diff, _VECTORMATH_MASK_0x00F0 ), zero ); - result->col0.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ); - result->col1.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ); - result->col2.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x00F0 ); - result->col3.vec128 = vec_sel( column, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F ); -} - -static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ) -{ - vmathV4Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); - vmathV4Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); - vmathV4Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); - vmathV4Select( &result->col3, &mat0->col3, &mat1->col3, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathM4Print( const VmathMatrix4 *mat ) -{ - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; - vmathM4GetRow( &tmpV4_0, mat, 0 ); - vmathV4Print( &tmpV4_0 ); - vmathM4GetRow( &tmpV4_1, mat, 1 ); - vmathV4Print( &tmpV4_1 ); - vmathM4GetRow( &tmpV4_2, mat, 2 ); - vmathV4Print( &tmpV4_2 ); - vmathM4GetRow( &tmpV4_3, mat, 3 ); - vmathV4Print( &tmpV4_3 ); -} - -static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ) -{ - printf("%s:\n", name); - vmathM4Print( mat ); -} - -#endif - -static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( &result->col0, &tfrm->col0 ); - vmathV3Copy( &result->col1, &tfrm->col1 ); - vmathV3Copy( &result->col2, &tfrm->col2 ); - vmathV3Copy( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ) -{ - vmathV3MakeFromScalar( &result->col0, scalar ); - vmathV3MakeFromScalar( &result->col1, scalar ); - vmathV3MakeFromScalar( &result->col2, scalar ); - vmathV3MakeFromScalar( &result->col3, scalar ); -} - -static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2, const VmathVector3 *_col3 ) -{ - vmathV3Copy( &result->col0, _col0 ); - vmathV3Copy( &result->col1, _col1 ); - vmathV3Copy( &result->col2, _col2 ); - vmathV3Copy( &result->col3, _col3 ); -} - -static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ) -{ - vmathT3SetUpper3x3( result, tfrm ); - vmathT3SetTranslation( result, translateVec ); -} - -static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) -{ - VmathMatrix3 tmpM3_0; - vmathM3MakeFromQ( &tmpM3_0, unitQuat ); - vmathT3SetUpper3x3( result, &tmpM3_0 ); - vmathT3SetTranslation( result, translateVec ); -} - -static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *_col0 ) -{ - vmathV3Copy( &result->col0, _col0 ); -} - -static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *_col1 ) -{ - vmathV3Copy( &result->col1, _col1 ); -} - -static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *_col3 ) -{ - vmathV3Copy( &result->col3, _col3 ); -} - -static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ) -{ - vmathV3Copy( (&result->col0 + col), vec ); -} - -static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ) -{ - vmathV3SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); - vmathV3SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); - vmathV3SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); - vmathV3SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); -} - -static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ) -{ - VmathVector3 tmpV3_0; - vmathT3GetCol( &tmpV3_0, result, col ); - vmathV3SetElem( &tmpV3_0, row, val ); - vmathT3SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ) -{ - VmathVector3 tmpV3_0; - vmathT3GetCol( &tmpV3_0, tfrm, col ); - return vmathV3GetElem( &tmpV3_0, row ); -} - -static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col0 ); -} - -static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col1 ); -} - -static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col2 ); -} - -static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col3 ); -} - -static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ) -{ - vmathV3Copy( result, (&tfrm->col0 + col) ); -} - -static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ) -{ - vmathV4MakeFromElems( result, vmathV3GetElem( &tfrm->col0, row ), vmathV3GetElem( &tfrm->col1, row ), vmathV3GetElem( &tfrm->col2, row ), vmathV3GetElem( &tfrm->col3, row ) ); -} - -static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp2 = _vmathVfCross( tfrm->col0.vec128, tfrm->col1.vec128 ); - tmp0 = _vmathVfCross( tfrm->col1.vec128, tfrm->col2.vec128 ); - tmp1 = _vmathVfCross( tfrm->col2.vec128, tfrm->col0.vec128 ); - inv3 = negatef4( tfrm->col3.vec128 ); - dot = _vmathVfDot3( tmp2, tfrm->col2.vec128 ); - dot = vec_splat( dot, 0 ); - invdet = recipf4( dot ); - tmp3 = vec_mergeh( tmp0, tmp2 ); - tmp4 = vec_mergel( tmp0, tmp2 ); - inv0 = vec_mergeh( tmp3, tmp1 ); - xxxx = vec_splat( inv3, 0 ); - inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( inv3, 1 ); - zzzz = vec_splat( inv3, 2 ); - inv3 = vec_madd( inv0, xxxx, zero ); - inv3 = vec_madd( inv1, yyyy, inv3 ); - inv3 = vec_madd( inv2, zzzz, inv3 ); - inv0 = vec_madd( inv0, invdet, zero ); - inv1 = vec_madd( inv1, invdet, zero ); - inv2 = vec_madd( inv2, invdet, zero ); - inv3 = vec_madd( inv3, invdet, zero ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; - result->col3.vec128 = inv3; -} - -static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1; - vec_float4 xxxx, yyyy, zzzz; - tmp0 = vec_mergeh( tfrm->col0.vec128, tfrm->col2.vec128 ); - tmp1 = vec_mergel( tfrm->col0.vec128, tfrm->col2.vec128 ); - inv3 = negatef4( tfrm->col3.vec128 ); - inv0 = vec_mergeh( tmp0, tfrm->col1.vec128 ); - xxxx = vec_splat( inv3, 0 ); - inv1 = vec_perm( tmp0, tfrm->col1.vec128, _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp1, tfrm->col1.vec128, _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( inv3, 1 ); - zzzz = vec_splat( inv3, 2 ); - inv3 = vec_madd( inv0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - inv3 = vec_madd( inv1, yyyy, inv3 ); - inv3 = vec_madd( inv2, zzzz, inv3 ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; - result->col3.vec128 = inv3; -} - -static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3AbsPerElem( &result->col0, &tfrm->col0 ); - vmathV3AbsPerElem( &result->col1, &tfrm->col1 ); - vmathV3AbsPerElem( &result->col2, &tfrm->col2 ); - vmathV3AbsPerElem( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec->vec128, 0 ); - yyyy = vec_splat( vec->vec128, 1 ); - zzzz = vec_splat( vec->vec128, 2 ); - res = vec_madd( tfrm->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( tfrm->col1.vec128, yyyy, res ); - res = vec_madd( tfrm->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( pnt->vec128, 0 ); - yyyy = vec_splat( pnt->vec128, 1 ); - zzzz = vec_splat( pnt->vec128, 2 ); - tmp0 = vec_madd( tfrm->col0.vec128, xxxx, zero ); - tmp1 = vec_madd( tfrm->col1.vec128, yyyy, zero ); - tmp0 = vec_madd( tfrm->col2.vec128, zzzz, tmp0 ); - tmp1 = vec_add( tfrm->col3.vec128, tmp1 ); - res = vec_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) -{ - VmathTransform3 tmpResult; - VmathPoint3 tmpP3_0, tmpP3_1; - vmathT3MulV3( &tmpResult.col0, tfrm0, &tfrm1->col0 ); - vmathT3MulV3( &tmpResult.col1, tfrm0, &tfrm1->col1 ); - vmathT3MulV3( &tmpResult.col2, tfrm0, &tfrm1->col2 ); - vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); - vmathT3MulP3( &tmpP3_1, tfrm0, &tmpP3_0 ); - vmathV3MakeFromP3( &tmpResult.col3, &tmpP3_1 ); - vmathT3Copy( result, &tmpResult ); -} - -static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) -{ - vmathV3MulPerElem( &result->col0, &tfrm0->col0, &tfrm1->col0 ); - vmathV3MulPerElem( &result->col1, &tfrm0->col1, &tfrm1->col1 ); - vmathV3MulPerElem( &result->col2, &tfrm0->col2, &tfrm1->col2 ); - vmathV3MulPerElem( &result->col3, &tfrm0->col3, &tfrm1->col3 ); -} - -static inline void vmathT3MakeIdentity( VmathTransform3 *result ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *tfrm ) -{ - vmathV3Copy( &result->col0, &tfrm->col0 ); - vmathV3Copy( &result->col1, &tfrm->col1 ); - vmathV3Copy( &result->col2, &tfrm->col2 ); -} - -static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ) -{ - vmathM3MakeFromCols( result, &tfrm->col0, &tfrm->col1, &tfrm->col2 ); -} - -static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) -{ - vmathV3Copy( &result->col3, translateVec ); -} - -static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col3 ); -} - -static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - vmathV3MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV3MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( _vmathVfSplatScalar(radians), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV3MakeZAxis( &result->col2 ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ) -{ - VmathVector4 tmpV4_0; - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); - angles = tmpV4_0.vec128; - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - result->col0.vec128 = vec_madd( Z0, Y0, zero ); - result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); - result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ) -{ - VmathMatrix3 tmpM3_0; - VmathVector3 tmpV3_0; - vmathM3MakeRotationAxis( &tmpM3_0, radians, unitVec ); - vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); - vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); -} - -static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ) -{ - VmathMatrix3 tmpM3_0; - VmathVector3 tmpV3_0; - vmathM3MakeFromQ( &tmpM3_0, unitQuat ); - vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); - vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); -} - -static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); - result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); - result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ) -{ - vmathV3ScalarMul( &result->col0, &tfrm->col0, vmathV3GetX( scaleVec ) ); - vmathV3ScalarMul( &result->col1, &tfrm->col1, vmathV3GetY( scaleVec ) ); - vmathV3ScalarMul( &result->col2, &tfrm->col2, vmathV3GetZ( scaleVec ) ); - vmathV3Copy( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ) -{ - vmathV3MulPerElem( &result->col0, &tfrm->col0, scaleVec ); - vmathV3MulPerElem( &result->col1, &tfrm->col1, scaleVec ); - vmathV3MulPerElem( &result->col2, &tfrm->col2, scaleVec ); - vmathV3MulPerElem( &result->col3, &tfrm->col3, scaleVec ); -} - -static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); - vmathV3Copy( &result->col3, translateVec ); -} - -static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ) -{ - vmathV3Select( &result->col0, &tfrm0->col0, &tfrm1->col0, select1 ); - vmathV3Select( &result->col1, &tfrm0->col1, &tfrm1->col1, select1 ); - vmathV3Select( &result->col2, &tfrm0->col2, &tfrm1->col2, select1 ); - vmathV3Select( &result->col3, &tfrm0->col3, &tfrm1->col3, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathT3Print( const VmathTransform3 *tfrm ) -{ - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2; - vmathT3GetRow( &tmpV4_0, tfrm, 0 ); - vmathV4Print( &tmpV4_0 ); - vmathT3GetRow( &tmpV4_1, tfrm, 1 ); - vmathV4Print( &tmpV4_1 ); - vmathT3GetRow( &tmpV4_2, tfrm, 2 ); - vmathV4Print( &tmpV4_2 ); -} - -static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ) -{ - printf("%s:\n", name); - vmathT3Print( tfrm ); -} - -#endif - -static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *tfrm ) -{ - vec_float4 res; - vec_float4 col0, col1, col2; - vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; - vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; - vec_float4 radicand, invSqrt, scale; - vec_float4 res0, res1, res2, res3; - vec_float4 xx, yy, zz; - vec_uint4 select_x = _VECTORMATH_MASK_0xF000; - vec_uint4 select_y = _VECTORMATH_MASK_0x0F00; - vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; - vec_uint4 select_w = _VECTORMATH_MASK_0x000F; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - - col0 = tfrm->col0.vec128; - col1 = tfrm->col1.vec128; - col2 = tfrm->col2.vec128; - - /* four cases: */ - /* trace > 0 */ - /* else */ - /* xx largest diagonal element */ - /* yy largest diagonal element */ - /* zz largest diagonal element */ - - /* compute quaternion for each case */ - - xx_yy = vec_sel( col0, col1, select_y ); - xx_yy_zz_xx = vec_perm( xx_yy, col2, _VECTORMATH_PERM_XYCX ); - yy_zz_xx_yy = vec_perm( xx_yy, col2, _VECTORMATH_PERM_YCXY ); - zz_xx_yy_zz = vec_perm( xx_yy, col2, _VECTORMATH_PERM_CXYC ); - - diagSum = vec_add( vec_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - diagDiff = vec_sub( vec_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - radicand = vec_add( vec_sel( diagDiff, diagSum, select_w ), ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); - invSqrt = rsqrtf4( radicand ); - - zy_xz_yx = vec_sel( col0, col1, select_z ); - zy_xz_yx = vec_perm( zy_xz_yx, col2, _VECTORMATH_PERM_ZAYX ); - yz_zx_xy = vec_sel( col0, col1, select_x ); - yz_zx_xy = vec_perm( yz_zx_xy, col2, _VECTORMATH_PERM_BZXX ); - - sum = vec_add( zy_xz_yx, yz_zx_xy ); - diff = vec_sub( zy_xz_yx, yz_zx_xy ); - - scale = vec_madd( invSqrt, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), zero ); - res0 = vec_perm( sum, diff, _VECTORMATH_PERM_XZYA ); - res1 = vec_perm( sum, diff, _VECTORMATH_PERM_ZXXB ); - res2 = vec_perm( sum, diff, _VECTORMATH_PERM_YXXC ); - res3 = diff; - res0 = vec_sel( res0, radicand, select_x ); - res1 = vec_sel( res1, radicand, select_y ); - res2 = vec_sel( res2, radicand, select_z ); - res3 = vec_sel( res3, radicand, select_w ); - res0 = vec_madd( res0, vec_splat( scale, 0 ), zero ); - res1 = vec_madd( res1, vec_splat( scale, 1 ), zero ); - res2 = vec_madd( res2, vec_splat( scale, 2 ), zero ); - res3 = vec_madd( res3, vec_splat( scale, 3 ), zero ); - - /* determine case and select answer */ - - xx = vec_splat( col0, 0 ); - yy = vec_splat( col1, 1 ); - zz = vec_splat( col2, 2 ); - res = vec_sel( res0, res1, vec_cmpgt( yy, xx ) ); - res = vec_sel( res, res2, vec_and( vec_cmpgt( zz, xx ), vec_cmpgt( zz, yy ) ) ); - res = vec_sel( res, res3, vec_cmpgt( vec_splat( diagSum, 0 ), zero ) ); - result->vec128 = res; -} - -static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *tfrm0, const VmathVector3 *tfrm1 ) -{ - vmathV3ScalarMul( &result->col0, tfrm0, vmathV3GetX( tfrm1 ) ); - vmathV3ScalarMul( &result->col1, tfrm0, vmathV3GetY( tfrm1 ) ); - vmathV3ScalarMul( &result->col2, tfrm0, vmathV3GetZ( tfrm1 ) ); -} - -static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *tfrm0, const VmathVector4 *tfrm1 ) -{ - vmathV4ScalarMul( &result->col0, tfrm0, vmathV4GetX( tfrm1 ) ); - vmathV4ScalarMul( &result->col1, tfrm0, vmathV4GetY( tfrm1 ) ); - vmathV4ScalarMul( &result->col2, tfrm0, vmathV4GetZ( tfrm1 ) ); - vmathV4ScalarMul( &result->col3, tfrm0, vmathV4GetW( tfrm1 ) ); -} - -static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; - vec_float4 xxxx, yyyy, zzzz; - tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); - tmp1 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); - xxxx = vec_splat( vec->vec128, 0 ); - mcol0 = vec_mergeh( tmp0, mat->col1.vec128 ); - mcol1 = vec_perm( tmp0, mat->col1.vec128, _VECTORMATH_PERM_ZBWX ); - mcol2 = vec_perm( tmp1, mat->col1.vec128, _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( vec->vec128, 1 ); - res = vec_madd( mcol0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - zzzz = vec_splat( vec->vec128, 2 ); - res = vec_madd( mcol1, yyyy, res ); - res = vec_madd( mcol2, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ) -{ - vec_float4 neg, res0, res1, res2; - neg = negatef4( vec->vec128 ); - res0 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_XZBX ); - res1 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_CXXX ); - res2 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_YAXX ); - res0 = vec_andc( res0, (vec_float4)_VECTORMATH_MASK_0xF000 ); - res1 = vec_andc( res1, (vec_float4)_VECTORMATH_MASK_0x0F00 ); - res2 = vec_andc( res2, (vec_float4)_VECTORMATH_MASK_0x00F0 ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; - vmathV3Cross( &tmpV3_0, vec, &mat->col0 ); - vmathV3Cross( &tmpV3_1, vec, &mat->col1 ); - vmathV3Cross( &tmpV3_2, vec, &mat->col2 ); - vmathM3MakeFromCols( result, &tmpV3_0, &tmpV3_1, &tmpV3_2 ); -} - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_MAT_AOS_C_H +#define _VECTORMATH_MAT_AOS_C_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Constants + * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + */ +#define _VECTORMATH_PERM_ZBWX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XCYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_C, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B }) +#define _VECTORMATH_PERM_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W, _VECTORMATH_PERM_C, _VECTORMATH_PERM_D }) +#define _VECTORMATH_PERM_XZBX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_CXXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_YAXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W, _VECTORMATH_PERM_Z }) +#define _VECTORMATH_PERM_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_D }) +#define _VECTORMATH_PERM_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y }) +#define _VECTORMATH_PERM_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_ZAYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_BZXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A }) +#define _VECTORMATH_PERM_ZXXB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_B }) +#define _VECTORMATH_PERM_YXXC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_BBYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_B, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PI_OVER_2 1.570796327f + +/*----------------------------------------------------------------------------- + * Definitions + */ +static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( &result->col0, &mat->col0 ); + vmathV3Copy( &result->col1, &mat->col1 ); + vmathV3Copy( &result->col2, &mat->col2 ); +} + +static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ) +{ + vmathV3MakeFromScalar( &result->col0, scalar ); + vmathV3MakeFromScalar( &result->col1, scalar ); + vmathV3MakeFromScalar( &result->col2, scalar ); +} + +static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) +{ + vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + vec_uint4 select_x = _VECTORMATH_MASK_0xF000; + vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; + xyzw_2 = vec_add( unitQuat->vec128, unitQuat->vec128 ); + wwww = vec_splat( unitQuat->vec128, 3 ); + yzxw = vec_perm( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_PERM_YZXW ); + zxyw = vec_perm( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_PERM_ZXYW ); + yzxw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_YZXW ); + zxyw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_ZXYW ); + tmp0 = vec_madd( yzxw_2, wwww, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + tmp1 = vec_nmsub( yzxw, yzxw_2, ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); + tmp2 = vec_madd( yzxw, xyzw_2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + tmp0 = vec_madd( zxyw, xyzw_2, tmp0 ); + tmp1 = vec_nmsub( zxyw, zxyw_2, tmp1 ); + tmp2 = vec_nmsub( zxyw_2, wwww, tmp2 ); + tmp3 = vec_sel( tmp0, tmp1, select_x ); + tmp4 = vec_sel( tmp1, tmp2, select_x ); + tmp5 = vec_sel( tmp2, tmp0, select_x ); + result->col0.vec128 = vec_sel( tmp3, tmp2, select_z ); + result->col1.vec128 = vec_sel( tmp4, tmp0, select_z ); + result->col2.vec128 = vec_sel( tmp5, tmp1, select_z ); +} + +static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col0, _col0 ); + vmathV3Copy( &result->col1, _col1 ); + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *_col0 ) +{ + vmathV3Copy( &result->col0, _col0 ); +} + +static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *_col1 ) +{ + vmathV3Copy( &result->col1, _col1 ); +} + +static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ) +{ + vmathV3Copy( (&result->col0 + col), vec ); +} + +static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ) +{ + vmathV3SetElem( &result->col0, row, vmathV3GetElem( vec, 0 ) ); + vmathV3SetElem( &result->col1, row, vmathV3GetElem( vec, 1 ) ); + vmathV3SetElem( &result->col2, row, vmathV3GetElem( vec, 2 ) ); +} + +static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ) +{ + VmathVector3 tmpV3_0; + vmathM3GetCol( &tmpV3_0, result, col ); + vmathV3SetElem( &tmpV3_0, row, val ); + vmathM3SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ) +{ + VmathVector3 tmpV3_0; + vmathM3GetCol( &tmpV3_0, mat, col ); + return vmathV3GetElem( &tmpV3_0, row ); +} + +static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col0 ); +} + +static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col1 ); +} + +static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col2 ); +} + +static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ) +{ + vmathV3Copy( result, (&mat->col0 + col) ); +} + +static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ) +{ + vmathV3MakeFromElems( result, vmathV3GetElem( &mat->col0, row ), vmathV3GetElem( &mat->col1, row ), vmathV3GetElem( &mat->col2, row ) ); +} + +static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, res0, res1, res2; + tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); + tmp1 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); + res0 = vec_mergeh( tmp0, mat->col1.vec128 ); + res1 = vec_perm( tmp0, mat->col1.vec128, _VECTORMATH_PERM_ZBWX ); + res2 = vec_perm( tmp1, mat->col1.vec128, _VECTORMATH_PERM_XCYX ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp2 = _vmathVfCross( mat->col0.vec128, mat->col1.vec128 ); + tmp0 = _vmathVfCross( mat->col1.vec128, mat->col2.vec128 ); + tmp1 = _vmathVfCross( mat->col2.vec128, mat->col0.vec128 ); + dot = _vmathVfDot3( tmp2, mat->col2.vec128 ); + dot = vec_splat( dot, 0 ); + invdet = recipf4( dot ); + tmp3 = vec_mergeh( tmp0, tmp2 ); + tmp4 = vec_mergel( tmp0, tmp2 ); + inv0 = vec_mergeh( tmp3, tmp1 ); + inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); + inv0 = vec_madd( inv0, invdet, zero ); + inv1 = vec_madd( inv1, invdet, zero ); + inv2 = vec_madd( inv2, invdet, zero ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; +} + +static inline float vmathM3Determinant( const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0; + vmathV3Cross( &tmpV3_0, &mat->col0, &mat->col1 ); + return vmathV3Dot( &mat->col2, &tmpV3_0 ); +} + +static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3Add( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3Add( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3Add( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3Sub( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3Sub( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3Sub( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Neg( &result->col0, &mat->col0 ); + vmathV3Neg( &result->col1, &mat->col1 ); + vmathV3Neg( &result->col2, &mat->col2 ); +} + +static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3AbsPerElem( &result->col0, &mat->col0 ); + vmathV3AbsPerElem( &result->col1, &mat->col1 ); + vmathV3AbsPerElem( &result->col2, &mat->col2 ); +} + +static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ) +{ + vmathV3ScalarMul( &result->col0, &mat->col0, scalar ); + vmathV3ScalarMul( &result->col1, &mat->col1, scalar ); + vmathV3ScalarMul( &result->col2, &mat->col2, scalar ); +} + +static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec->vec128, 0 ); + yyyy = vec_splat( vec->vec128, 1 ); + zzzz = vec_splat( vec->vec128, 2 ); + res = vec_madd( mat->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( mat->col1.vec128, yyyy, res ); + res = vec_madd( mat->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + VmathMatrix3 tmpResult; + vmathM3MulV3( &tmpResult.col0, mat0, &mat1->col0 ); + vmathM3MulV3( &tmpResult.col1, mat0, &mat1->col1 ); + vmathM3MulV3( &tmpResult.col2, mat0, &mat1->col2 ); + vmathM3Copy( result, &tmpResult ); +} + +static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3MakeIdentity( VmathMatrix3 *result ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); +} + +static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + vmathV3MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV3MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; +} + +static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV3MakeZAxis( &result->col2 ); +} + +static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ) +{ + VmathVector4 tmpV4_0; + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); + angles = tmpV4_0.vec128; + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + result->col0.vec128 = vec_madd( Z0, Y0, zero ); + result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); + result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); +} + +static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + axis = unitVec->vec128; + sincosf4( (vec_float4){radians,radians,radians,radians}, &s, &c ); + xxxx = vec_splat( axis, 0 ); + yyyy = vec_splat( axis, 1 ); + zzzz = vec_splat( axis, 2 ); + oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); + axisS = vec_madd( axis, s, zero ); + negAxisS = negatef4( axisS ); + tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); + tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); + tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); + tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); + tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); + tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); + result->col0.vec128 = vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ); + result->col1.vec128 = vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ); + result->col2.vec128 = vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ); +} + +static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) +{ + vmathM3MakeFromQ( result, unitQuat ); +} + +static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); + result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); + result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); +} + +static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ) +{ + vmathV3ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); + vmathV3ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); + vmathV3ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); +} + +static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ) +{ + vmathV3MulPerElem( &result->col0, &mat->col0, scaleVec ); + vmathV3MulPerElem( &result->col1, &mat->col1, scaleVec ); + vmathV3MulPerElem( &result->col2, &mat->col2, scaleVec ); +} + +static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ) +{ + vmathV3Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); + vmathV3Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); + vmathV3Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathM3Print( const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; + vmathM3GetRow( &tmpV3_0, mat, 0 ); + vmathV3Print( &tmpV3_0 ); + vmathM3GetRow( &tmpV3_1, mat, 1 ); + vmathV3Print( &tmpV3_1 ); + vmathM3GetRow( &tmpV3_2, mat, 2 ); + vmathV3Print( &tmpV3_2 ); +} + +static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ) +{ + printf("%s:\n", name); + vmathM3Print( mat ); +} + +#endif + +static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( &result->col0, &mat->col0 ); + vmathV4Copy( &result->col1, &mat->col1 ); + vmathV4Copy( &result->col2, &mat->col2 ); + vmathV4Copy( &result->col3, &mat->col3 ); +} + +static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ) +{ + vmathV4MakeFromScalar( &result->col0, scalar ); + vmathV4MakeFromScalar( &result->col1, scalar ); + vmathV4MakeFromScalar( &result->col2, scalar ); + vmathV4MakeFromScalar( &result->col3, scalar ); +} + +static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ) +{ + vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, &mat->col3, 1.0f ); +} + +static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *_col0, const VmathVector4 *_col1, const VmathVector4 *_col2, const VmathVector4 *_col3 ) +{ + vmathV4Copy( &result->col0, _col0 ); + vmathV4Copy( &result->col1, _col1 ); + vmathV4Copy( &result->col2, _col2 ); + vmathV4Copy( &result->col3, _col3 ); +} + +static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ) +{ + vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) +{ + VmathMatrix3 mat; + vmathM3MakeFromQ( &mat, unitQuat ); + vmathV4MakeFromV3Scalar( &result->col0, &mat.col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat.col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat.col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *_col0 ) +{ + vmathV4Copy( &result->col0, _col0 ); +} + +static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *_col1 ) +{ + vmathV4Copy( &result->col1, _col1 ); +} + +static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *_col2 ) +{ + vmathV4Copy( &result->col2, _col2 ); +} + +static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *_col3 ) +{ + vmathV4Copy( &result->col3, _col3 ); +} + +static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ) +{ + vmathV4Copy( (&result->col0 + col), vec ); +} + +static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ) +{ + vmathV4SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); + vmathV4SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); + vmathV4SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); + vmathV4SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); +} + +static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ) +{ + VmathVector4 tmpV3_0; + vmathM4GetCol( &tmpV3_0, result, col ); + vmathV4SetElem( &tmpV3_0, row, val ); + vmathM4SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ) +{ + VmathVector4 tmpV4_0; + vmathM4GetCol( &tmpV4_0, mat, col ); + return vmathV4GetElem( &tmpV4_0, row ); +} + +static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col0 ); +} + +static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col1 ); +} + +static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col2 ); +} + +static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col3 ); +} + +static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ) +{ + vmathV4Copy( result, (&mat->col0 + col) ); +} + +static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ) +{ + vmathV4MakeFromElems( result, vmathV4GetElem( &mat->col0, row ), vmathV4GetElem( &mat->col1, row ), vmathV4GetElem( &mat->col2, row ), vmathV4GetElem( &mat->col3, row ) ); +} + +static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; + tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); + tmp1 = vec_mergeh( mat->col1.vec128, mat->col3.vec128 ); + tmp2 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); + tmp3 = vec_mergel( mat->col1.vec128, mat->col3.vec128 ); + res0 = vec_mergeh( tmp0, tmp1 ); + res1 = vec_mergel( tmp0, tmp1 ); + res2 = vec_mergeh( tmp2, tmp3 ); + res3 = vec_mergel( tmp2, tmp3 ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; + result->col3.vec128 = res3; +} + +static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vector float in0, in1, in2, in3; + vector float tmp0, tmp1, tmp2, tmp3; + vector float cof0, cof1, cof2, cof3; + vector float t0, t1, t2, t3; + vector float t01, t02, t03, t12, t23; + vector float t1r, t2r; + vector float t01r, t02r, t03r, t12r, t23r; + vector float t1r3, t1r3r; + vector float det, det0, det1, det2, det3, invdet; + vector float vzero = (vector float){0.0}; + in0 = mat->col0.vec128; + in1 = mat->col1.vec128; + in2 = mat->col2.vec128; + in3 = mat->col3.vec128; + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ + tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ + tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ + tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ + t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ + t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ + t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ + t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ + t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ + cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ + cof1 = vec_nmsub(t0, t23, vzero); /* -(AGP ECL IOH MKD) */ + t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ + cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ + cof1 = vec_madd(t0, t23r, cof1); /* AOH EKD IGP MCL + cof1 */ + cof1 = vec_sld(cof1, cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ + t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ + t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ + cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + cof3 = vec_madd(t0, t12, vzero); /* ANG EJC IFO MBK */ + t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ + cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + cof3 = vec_nmsub(t0, t12r, cof3); /* cof3 - AFO EBK ING MJC */ + cof3 = vec_sld(cof3, cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ + t1r = vec_sld(t1, t1, 8); /* B F J N */ + t2r = vec_sld(t2, t2, 8); /* K O C G */ + t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ + t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ + cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + cof2 = vec_madd(t0, t1r3, vzero); /* AFP EBL INH MJD */ + t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ + cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + cof2 = vec_nmsub(t0, t1r3r, cof2); /* cof2 - ANH EJD IFP MBL */ + cof2 = vec_sld(cof2, cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ + t01 = vec_madd(t0, t1, vzero); /* AJ EN IB MF */ + t01 = vec_perm(t01, t01, _VECTORMATH_PERM_YXWZ); /* EN AJ MF IB */ + cof2 = vec_nmsub(t3, t01, cof2); /* cof2 - LEN PAJ DMF HIB */ + cof3 = vec_madd(t2r, t01, cof3); /* KEN OAJ CMF GIB + cof3 */ + t01r = vec_sld(t01, t01, 8); /* MF IB EN AJ */ + cof2 = vec_madd(t3, t01r, cof2); /* LMF PIB DEN HAJ + cof2 */ + cof3 = vec_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ + t03 = vec_madd(t0, t3, vzero); /* AL EP ID MH */ + t03 = vec_perm(t03, t03, _VECTORMATH_PERM_YXWZ); /* EP AL MH ID */ + cof1 = vec_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ + cof2 = vec_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ + t03r = vec_sld(t03, t03, 8); /* MH ID EP AL */ + cof1 = vec_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ + cof2 = vec_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ + t02 = vec_madd(t0, t2r, vzero); /* AK EO IC MG */ + t02 = vec_perm(t02, t02, _VECTORMATH_PERM_YXWZ); /* E0 AK MG IC */ + cof1 = vec_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ + cof3 = vec_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ + t02r = vec_sld(t02, t02, 8); /* MG IC EO AK */ + cof1 = vec_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ + cof3 = vec_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ + /* Compute the determinant of the matrix + * + * det = sum_across(t0 * cof0); + * + * We perform a sum across the entire vector so that + * we don't have to splat the result when multiplying the + * cofactors by the inverse of the determinant. + */ + det = vec_madd(t0, cof0, vzero); + det0 = vec_splat(det, 0); + det1 = vec_splat(det, 1); + det2 = vec_splat(det, 2); + det3 = vec_splat(det, 3); + det = vec_add(det0, det1); + det2 = vec_add(det2, det3); + det = vec_add(det, det2); + /* Compute the reciprocal of the determinant. + */ + invdet = recipf4(det); + /* Multiply the cofactors by the reciprocal of the determinant. + */ + result->col0.vec128 = vec_madd(cof0, invdet, vzero); + result->col1.vec128 = vec_madd(cof1, invdet, vzero); + result->col2.vec128 = vec_madd(cof2, invdet, vzero); + result->col3.vec128 = vec_madd(cof3, invdet, vzero); +} + +static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + VmathTransform3 affineMat, tmpT3_0; + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; + vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); + vmathT3SetCol0( &affineMat, &tmpV3_0 ); + vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); + vmathT3SetCol1( &affineMat, &tmpV3_1 ); + vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); + vmathT3SetCol2( &affineMat, &tmpV3_2 ); + vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); + vmathT3SetCol3( &affineMat, &tmpV3_3 ); + vmathT3Inverse( &tmpT3_0, &affineMat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + VmathTransform3 affineMat, tmpT3_0; + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; + vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); + vmathT3SetCol0( &affineMat, &tmpV3_0 ); + vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); + vmathT3SetCol1( &affineMat, &tmpV3_1 ); + vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); + vmathT3SetCol2( &affineMat, &tmpV3_2 ); + vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); + vmathT3SetCol3( &affineMat, &tmpV3_3 ); + vmathT3OrthoInverse( &tmpT3_0, &affineMat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline float vmathM4Determinant( const VmathMatrix4 *mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vector float in0, in1, in2, in3; + vector float tmp0, tmp1, tmp2, tmp3; + vector float cof0; + vector float t0, t1, t2, t3; + vector float t12, t23; + vector float t1r, t2r; + vector float t12r, t23r; + vector float t1r3, t1r3r; + vector float vzero = (vector float){0.0}; + union { vec_float4 v; float s[4]; } tmp; + in0 = mat->col0.vec128; + in1 = mat->col1.vec128; + in2 = mat->col2.vec128; + in3 = mat->col3.vec128; + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ + tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ + tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ + tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ + t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ + t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ + t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ + t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ + t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ + cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ + t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ + cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ + t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ + t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ + cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ + cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + t1r = vec_sld(t1, t1, 8); /* B F J N */ + t2r = vec_sld(t2, t2, 8); /* K O C G */ + t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ + t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ + cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ + cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + tmp.v = _vmathVfDot4(t0,cof0); + return tmp.s[0]; +} + +static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4Add( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4Add( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4Add( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4Add( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4Sub( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4Sub( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4Sub( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4Sub( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Neg( &result->col0, &mat->col0 ); + vmathV4Neg( &result->col1, &mat->col1 ); + vmathV4Neg( &result->col2, &mat->col2 ); + vmathV4Neg( &result->col3, &mat->col3 ); +} + +static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4AbsPerElem( &result->col0, &mat->col0 ); + vmathV4AbsPerElem( &result->col1, &mat->col1 ); + vmathV4AbsPerElem( &result->col2, &mat->col2 ); + vmathV4AbsPerElem( &result->col3, &mat->col3 ); +} + +static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ) +{ + vmathV4ScalarMul( &result->col0, &mat->col0, scalar ); + vmathV4ScalarMul( &result->col1, &mat->col1, scalar ); + vmathV4ScalarMul( &result->col2, &mat->col2, scalar ); + vmathV4ScalarMul( &result->col3, &mat->col3, scalar ); +} + +static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz, wwww; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( vec->vec128, 0 ); + yyyy = vec_splat( vec->vec128, 1 ); + zzzz = vec_splat( vec->vec128, 2 ); + wwww = vec_splat( vec->vec128, 3 ); + tmp0 = vec_madd( mat->col0.vec128, xxxx, zero ); + tmp1 = vec_madd( mat->col1.vec128, yyyy, zero ); + tmp0 = vec_madd( mat->col2.vec128, zzzz, tmp0 ); + tmp1 = vec_madd( mat->col3.vec128, wwww, tmp1 ); + res = vec_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec->vec128, 0 ); + yyyy = vec_splat( vec->vec128, 1 ); + zzzz = vec_splat( vec->vec128, 2 ); + res = vec_madd( mat->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( mat->col1.vec128, yyyy, res ); + res = vec_madd( mat->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( pnt->vec128, 0 ); + yyyy = vec_splat( pnt->vec128, 1 ); + zzzz = vec_splat( pnt->vec128, 2 ); + tmp0 = vec_madd( mat->col0.vec128, xxxx, zero ); + tmp1 = vec_madd( mat->col1.vec128, yyyy, zero ); + tmp0 = vec_madd( mat->col2.vec128, zzzz, tmp0 ); + tmp1 = vec_add( mat->col3.vec128, tmp1 ); + res = vec_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + VmathMatrix4 tmpResult; + vmathM4MulV4( &tmpResult.col0, mat0, &mat1->col0 ); + vmathM4MulV4( &tmpResult.col1, mat0, &mat1->col1 ); + vmathM4MulV4( &tmpResult.col2, mat0, &mat1->col2 ); + vmathM4MulV4( &tmpResult.col3, mat0, &mat1->col3 ); + vmathM4Copy( result, &tmpResult ); +} + +static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm1 ) +{ + VmathMatrix4 tmpResult; + VmathPoint3 tmpP3_0; + vmathM4MulV3( &tmpResult.col0, mat, &tfrm1->col0 ); + vmathM4MulV3( &tmpResult.col1, mat, &tfrm1->col1 ); + vmathM4MulV3( &tmpResult.col2, mat, &tfrm1->col2 ); + vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); + vmathM4MulP3( &tmpResult.col3, mat, &tmpP3_0 ); + vmathM4Copy( result, &tmpResult ); +} + +static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4MulPerElem( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4MakeIdentity( VmathMatrix4 *result ) +{ + vmathV4MakeXAxis( &result->col0 ); + vmathV4MakeYAxis( &result->col1 ); + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ) +{ + vmathV4SetXYZ( &result->col0, &mat3->col0 ); + vmathV4SetXYZ( &result->col1, &mat3->col1 ); + vmathV4SetXYZ( &result->col2, &mat3->col2 ); +} + +static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ) +{ + vmathV4GetXYZ( &result->col0, &mat->col0 ); + vmathV4GetXYZ( &result->col1, &mat->col1 ); + vmathV4GetXYZ( &result->col2, &mat->col2 ); +} + +static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) +{ + vmathV4SetXYZ( &result->col3, translateVec ); +} + +static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ) +{ + vmathV4GetXYZ( result, &mat->col3 ); +} + +static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + vmathV4MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV4MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ) +{ + VmathVector4 tmpV4_0; + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); + angles = tmpV4_0.vec128; + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + result->col0.vec128 = vec_madd( Z0, Y0, zero ); + result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); + result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + axis = unitVec->vec128; + sincosf4( (vec_float4){radians,radians,radians,radians}, &s, &c ); + xxxx = vec_splat( axis, 0 ); + yyyy = vec_splat( axis, 1 ); + zzzz = vec_splat( axis, 2 ); + oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); + axisS = vec_madd( axis, s, zero ); + negAxisS = negatef4( axisS ); + tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); + tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); + tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); + tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); + tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); + tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); + zeroW = (vec_float4)_VECTORMATH_MASK_0x000F; + axis = vec_andc( axis, zeroW ); + tmp0 = vec_andc( tmp0, zeroW ); + tmp1 = vec_andc( tmp1, zeroW ); + tmp2 = vec_andc( tmp2, zeroW ); + result->col0.vec128 = vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ); + result->col1.vec128 = vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ); + result->col2.vec128 = vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ) +{ + VmathTransform3 tmpT3_0; + vmathT3MakeRotationQ( &tmpT3_0, unitQuat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); + result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); + result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ) +{ + vmathV4ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); + vmathV4ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); + vmathV4ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); + vmathV4Copy( &result->col3, &mat->col3 ); +} + +static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ) +{ + VmathVector4 scale4; + vmathV4MakeFromV3Scalar( &scale4, scaleVec, 1.0f ); + vmathV4MulPerElem( &result->col0, &mat->col0, &scale4 ); + vmathV4MulPerElem( &result->col1, &mat->col1, &scale4 ); + vmathV4MulPerElem( &result->col2, &mat->col2, &scale4 ); + vmathV4MulPerElem( &result->col3, &mat->col3, &scale4 ); +} + +static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) +{ + vmathV4MakeXAxis( &result->col0 ); + vmathV4MakeYAxis( &result->col1 ); + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ) +{ + VmathMatrix4 m4EyeFrame; + VmathVector3 v3X, v3Y, v3Z, tmpV3_0, tmpV3_1; + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; + vmathV3Normalize( &v3Y, upVec ); + vmathP3Sub( &tmpV3_0, eyePos, lookAtPos ); + vmathV3Normalize( &v3Z, &tmpV3_0 ); + vmathV3Cross( &tmpV3_1, &v3Y, &v3Z ); + vmathV3Normalize( &v3X, &tmpV3_1 ); + vmathV3Cross( &v3Y, &v3Z, &v3X ); + vmathV4MakeFromV3( &tmpV4_0, &v3X ); + vmathV4MakeFromV3( &tmpV4_1, &v3Y ); + vmathV4MakeFromV3( &tmpV4_2, &v3Z ); + vmathV4MakeFromP3( &tmpV4_3, eyePos ); + vmathM4MakeFromCols( &m4EyeFrame, &tmpV4_0, &tmpV4_1, &tmpV4_2, &tmpV4_3 ); + vmathM4OrthoInverse( result, &m4EyeFrame ); +} + +static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ) +{ + float f, rangeInv; + vec_float4 zero, col0, col1, col2, col3; + union { vec_float4 v; float s[4]; } tmp; + f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); + rangeInv = 1.0f / ( zNear - zFar ); + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp.v = zero; + tmp.s[0] = f / aspect; + col0 = tmp.v; + tmp.v = zero; + tmp.s[1] = f; + col1 = tmp.v; + tmp.v = zero; + tmp.s[2] = ( zNear + zFar ) * rangeInv; + tmp.s[3] = -1.0f; + col2 = tmp.v; + tmp.v = zero; + tmp.s[2] = zNear * zFar * rangeInv * 2.0f; + col3 = tmp.v; + result->col0.vec128 = col0; + result->col1.vec128 = col1; + result->col2.vec128 = col2; + result->col3.vec128 = col3; +} + +static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff; + vec_float4 diagonal, column, near2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + union { vec_float4 v; float s[4]; } l, f, r, n, b, t; + l.s[0] = left; + f.s[0] = zFar; + r.s[0] = right; + n.s[0] = zNear; + b.s[0] = bottom; + t.s[0] = top; + lbf = vec_mergeh( l.v, f.v ); + rtn = vec_mergeh( r.v, n.v ); + lbf = vec_mergeh( lbf, b.v ); + rtn = vec_mergeh( rtn, t.v ); + diff = vec_sub( rtn, lbf ); + sum = vec_add( rtn, lbf ); + inv_diff = recipf4( diff ); + near2 = vec_splat( n.v, 0 ); + near2 = vec_add( near2, near2 ); + diagonal = vec_madd( near2, inv_diff, zero ); + column = vec_madd( sum, inv_diff, zero ); + result->col0.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ); + result->col1.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ); + result->col2.vec128 = vec_sel( column, ((vec_float4){-1.0f,-1.0f,-1.0f,-1.0f}), _VECTORMATH_MASK_0x000F ); + result->col3.vec128 = vec_sel( zero, vec_madd( diagonal, vec_splat( f.v, 0 ), zero ), _VECTORMATH_MASK_0x00F0 ); +} + +static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff, neg_inv_diff; + vec_float4 diagonal, column; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + union { vec_float4 v; float s[4]; } l, f, r, n, b, t; + l.s[0] = left; + f.s[0] = zFar; + r.s[0] = right; + n.s[0] = zNear; + b.s[0] = bottom; + t.s[0] = top; + lbf = vec_mergeh( l.v, f.v ); + rtn = vec_mergeh( r.v, n.v ); + lbf = vec_mergeh( lbf, b.v ); + rtn = vec_mergeh( rtn, t.v ); + diff = vec_sub( rtn, lbf ); + sum = vec_add( rtn, lbf ); + inv_diff = recipf4( diff ); + neg_inv_diff = negatef4( inv_diff ); + diagonal = vec_add( inv_diff, inv_diff ); + column = vec_madd( sum, vec_sel( neg_inv_diff, inv_diff, _VECTORMATH_MASK_0x00F0 ), zero ); + result->col0.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ); + result->col1.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ); + result->col2.vec128 = vec_sel( zero, diagonal, _VECTORMATH_MASK_0x00F0 ); + result->col3.vec128 = vec_sel( column, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F ); +} + +static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ) +{ + vmathV4Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); + vmathV4Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); + vmathV4Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); + vmathV4Select( &result->col3, &mat0->col3, &mat1->col3, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathM4Print( const VmathMatrix4 *mat ) +{ + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; + vmathM4GetRow( &tmpV4_0, mat, 0 ); + vmathV4Print( &tmpV4_0 ); + vmathM4GetRow( &tmpV4_1, mat, 1 ); + vmathV4Print( &tmpV4_1 ); + vmathM4GetRow( &tmpV4_2, mat, 2 ); + vmathV4Print( &tmpV4_2 ); + vmathM4GetRow( &tmpV4_3, mat, 3 ); + vmathV4Print( &tmpV4_3 ); +} + +static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ) +{ + printf("%s:\n", name); + vmathM4Print( mat ); +} + +#endif + +static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( &result->col0, &tfrm->col0 ); + vmathV3Copy( &result->col1, &tfrm->col1 ); + vmathV3Copy( &result->col2, &tfrm->col2 ); + vmathV3Copy( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ) +{ + vmathV3MakeFromScalar( &result->col0, scalar ); + vmathV3MakeFromScalar( &result->col1, scalar ); + vmathV3MakeFromScalar( &result->col2, scalar ); + vmathV3MakeFromScalar( &result->col3, scalar ); +} + +static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2, const VmathVector3 *_col3 ) +{ + vmathV3Copy( &result->col0, _col0 ); + vmathV3Copy( &result->col1, _col1 ); + vmathV3Copy( &result->col2, _col2 ); + vmathV3Copy( &result->col3, _col3 ); +} + +static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ) +{ + vmathT3SetUpper3x3( result, tfrm ); + vmathT3SetTranslation( result, translateVec ); +} + +static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) +{ + VmathMatrix3 tmpM3_0; + vmathM3MakeFromQ( &tmpM3_0, unitQuat ); + vmathT3SetUpper3x3( result, &tmpM3_0 ); + vmathT3SetTranslation( result, translateVec ); +} + +static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *_col0 ) +{ + vmathV3Copy( &result->col0, _col0 ); +} + +static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *_col1 ) +{ + vmathV3Copy( &result->col1, _col1 ); +} + +static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *_col3 ) +{ + vmathV3Copy( &result->col3, _col3 ); +} + +static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ) +{ + vmathV3Copy( (&result->col0 + col), vec ); +} + +static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ) +{ + vmathV3SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); + vmathV3SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); + vmathV3SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); + vmathV3SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); +} + +static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ) +{ + VmathVector3 tmpV3_0; + vmathT3GetCol( &tmpV3_0, result, col ); + vmathV3SetElem( &tmpV3_0, row, val ); + vmathT3SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ) +{ + VmathVector3 tmpV3_0; + vmathT3GetCol( &tmpV3_0, tfrm, col ); + return vmathV3GetElem( &tmpV3_0, row ); +} + +static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col0 ); +} + +static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col1 ); +} + +static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col2 ); +} + +static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col3 ); +} + +static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ) +{ + vmathV3Copy( result, (&tfrm->col0 + col) ); +} + +static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ) +{ + vmathV4MakeFromElems( result, vmathV3GetElem( &tfrm->col0, row ), vmathV3GetElem( &tfrm->col1, row ), vmathV3GetElem( &tfrm->col2, row ), vmathV3GetElem( &tfrm->col3, row ) ); +} + +static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp2 = _vmathVfCross( tfrm->col0.vec128, tfrm->col1.vec128 ); + tmp0 = _vmathVfCross( tfrm->col1.vec128, tfrm->col2.vec128 ); + tmp1 = _vmathVfCross( tfrm->col2.vec128, tfrm->col0.vec128 ); + inv3 = negatef4( tfrm->col3.vec128 ); + dot = _vmathVfDot3( tmp2, tfrm->col2.vec128 ); + dot = vec_splat( dot, 0 ); + invdet = recipf4( dot ); + tmp3 = vec_mergeh( tmp0, tmp2 ); + tmp4 = vec_mergel( tmp0, tmp2 ); + inv0 = vec_mergeh( tmp3, tmp1 ); + xxxx = vec_splat( inv3, 0 ); + inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( inv3, 1 ); + zzzz = vec_splat( inv3, 2 ); + inv3 = vec_madd( inv0, xxxx, zero ); + inv3 = vec_madd( inv1, yyyy, inv3 ); + inv3 = vec_madd( inv2, zzzz, inv3 ); + inv0 = vec_madd( inv0, invdet, zero ); + inv1 = vec_madd( inv1, invdet, zero ); + inv2 = vec_madd( inv2, invdet, zero ); + inv3 = vec_madd( inv3, invdet, zero ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; + result->col3.vec128 = inv3; +} + +static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1; + vec_float4 xxxx, yyyy, zzzz; + tmp0 = vec_mergeh( tfrm->col0.vec128, tfrm->col2.vec128 ); + tmp1 = vec_mergel( tfrm->col0.vec128, tfrm->col2.vec128 ); + inv3 = negatef4( tfrm->col3.vec128 ); + inv0 = vec_mergeh( tmp0, tfrm->col1.vec128 ); + xxxx = vec_splat( inv3, 0 ); + inv1 = vec_perm( tmp0, tfrm->col1.vec128, _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp1, tfrm->col1.vec128, _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( inv3, 1 ); + zzzz = vec_splat( inv3, 2 ); + inv3 = vec_madd( inv0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + inv3 = vec_madd( inv1, yyyy, inv3 ); + inv3 = vec_madd( inv2, zzzz, inv3 ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; + result->col3.vec128 = inv3; +} + +static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3AbsPerElem( &result->col0, &tfrm->col0 ); + vmathV3AbsPerElem( &result->col1, &tfrm->col1 ); + vmathV3AbsPerElem( &result->col2, &tfrm->col2 ); + vmathV3AbsPerElem( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec->vec128, 0 ); + yyyy = vec_splat( vec->vec128, 1 ); + zzzz = vec_splat( vec->vec128, 2 ); + res = vec_madd( tfrm->col0.vec128, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( tfrm->col1.vec128, yyyy, res ); + res = vec_madd( tfrm->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( pnt->vec128, 0 ); + yyyy = vec_splat( pnt->vec128, 1 ); + zzzz = vec_splat( pnt->vec128, 2 ); + tmp0 = vec_madd( tfrm->col0.vec128, xxxx, zero ); + tmp1 = vec_madd( tfrm->col1.vec128, yyyy, zero ); + tmp0 = vec_madd( tfrm->col2.vec128, zzzz, tmp0 ); + tmp1 = vec_add( tfrm->col3.vec128, tmp1 ); + res = vec_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) +{ + VmathTransform3 tmpResult; + VmathPoint3 tmpP3_0, tmpP3_1; + vmathT3MulV3( &tmpResult.col0, tfrm0, &tfrm1->col0 ); + vmathT3MulV3( &tmpResult.col1, tfrm0, &tfrm1->col1 ); + vmathT3MulV3( &tmpResult.col2, tfrm0, &tfrm1->col2 ); + vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); + vmathT3MulP3( &tmpP3_1, tfrm0, &tmpP3_0 ); + vmathV3MakeFromP3( &tmpResult.col3, &tmpP3_1 ); + vmathT3Copy( result, &tmpResult ); +} + +static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) +{ + vmathV3MulPerElem( &result->col0, &tfrm0->col0, &tfrm1->col0 ); + vmathV3MulPerElem( &result->col1, &tfrm0->col1, &tfrm1->col1 ); + vmathV3MulPerElem( &result->col2, &tfrm0->col2, &tfrm1->col2 ); + vmathV3MulPerElem( &result->col3, &tfrm0->col3, &tfrm1->col3 ); +} + +static inline void vmathT3MakeIdentity( VmathTransform3 *result ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *tfrm ) +{ + vmathV3Copy( &result->col0, &tfrm->col0 ); + vmathV3Copy( &result->col1, &tfrm->col1 ); + vmathV3Copy( &result->col2, &tfrm->col2 ); +} + +static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ) +{ + vmathM3MakeFromCols( result, &tfrm->col0, &tfrm->col1, &tfrm->col2 ); +} + +static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) +{ + vmathV3Copy( &result->col3, translateVec ); +} + +static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col3 ); +} + +static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + vmathV3MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV3MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( _vmathVfSplatScalar(radians), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV3MakeZAxis( &result->col2 ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ) +{ + VmathVector4 tmpV4_0; + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + vmathV4MakeFromV3Scalar( &tmpV4_0, radiansXYZ, 0.0f ); + angles = tmpV4_0.vec128; + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + result->col0.vec128 = vec_madd( Z0, Y0, zero ); + result->col1.vec128 = vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ); + result->col2.vec128 = vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ) +{ + VmathMatrix3 tmpM3_0; + VmathVector3 tmpV3_0; + vmathM3MakeRotationAxis( &tmpM3_0, radians, unitVec ); + vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); + vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); +} + +static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ) +{ + VmathMatrix3 tmpM3_0; + VmathVector3 tmpV3_0; + vmathM3MakeFromQ( &tmpM3_0, unitQuat ); + vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); + vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); +} + +static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + result->col0.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0xF000 ); + result->col1.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x0F00 ); + result->col2.vec128 = vec_sel( zero, scaleVec->vec128, _VECTORMATH_MASK_0x00F0 ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ) +{ + vmathV3ScalarMul( &result->col0, &tfrm->col0, vmathV3GetX( scaleVec ) ); + vmathV3ScalarMul( &result->col1, &tfrm->col1, vmathV3GetY( scaleVec ) ); + vmathV3ScalarMul( &result->col2, &tfrm->col2, vmathV3GetZ( scaleVec ) ); + vmathV3Copy( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ) +{ + vmathV3MulPerElem( &result->col0, &tfrm->col0, scaleVec ); + vmathV3MulPerElem( &result->col1, &tfrm->col1, scaleVec ); + vmathV3MulPerElem( &result->col2, &tfrm->col2, scaleVec ); + vmathV3MulPerElem( &result->col3, &tfrm->col3, scaleVec ); +} + +static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); + vmathV3Copy( &result->col3, translateVec ); +} + +static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ) +{ + vmathV3Select( &result->col0, &tfrm0->col0, &tfrm1->col0, select1 ); + vmathV3Select( &result->col1, &tfrm0->col1, &tfrm1->col1, select1 ); + vmathV3Select( &result->col2, &tfrm0->col2, &tfrm1->col2, select1 ); + vmathV3Select( &result->col3, &tfrm0->col3, &tfrm1->col3, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathT3Print( const VmathTransform3 *tfrm ) +{ + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2; + vmathT3GetRow( &tmpV4_0, tfrm, 0 ); + vmathV4Print( &tmpV4_0 ); + vmathT3GetRow( &tmpV4_1, tfrm, 1 ); + vmathV4Print( &tmpV4_1 ); + vmathT3GetRow( &tmpV4_2, tfrm, 2 ); + vmathV4Print( &tmpV4_2 ); +} + +static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ) +{ + printf("%s:\n", name); + vmathT3Print( tfrm ); +} + +#endif + +static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *tfrm ) +{ + vec_float4 res; + vec_float4 col0, col1, col2; + vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; + vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; + vec_float4 radicand, invSqrt, scale; + vec_float4 res0, res1, res2, res3; + vec_float4 xx, yy, zz; + vec_uint4 select_x = _VECTORMATH_MASK_0xF000; + vec_uint4 select_y = _VECTORMATH_MASK_0x0F00; + vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; + vec_uint4 select_w = _VECTORMATH_MASK_0x000F; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + + col0 = tfrm->col0.vec128; + col1 = tfrm->col1.vec128; + col2 = tfrm->col2.vec128; + + /* four cases: */ + /* trace > 0 */ + /* else */ + /* xx largest diagonal element */ + /* yy largest diagonal element */ + /* zz largest diagonal element */ + + /* compute quaternion for each case */ + + xx_yy = vec_sel( col0, col1, select_y ); + xx_yy_zz_xx = vec_perm( xx_yy, col2, _VECTORMATH_PERM_XYCX ); + yy_zz_xx_yy = vec_perm( xx_yy, col2, _VECTORMATH_PERM_YCXY ); + zz_xx_yy_zz = vec_perm( xx_yy, col2, _VECTORMATH_PERM_CXYC ); + + diagSum = vec_add( vec_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + diagDiff = vec_sub( vec_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + radicand = vec_add( vec_sel( diagDiff, diagSum, select_w ), ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); + invSqrt = rsqrtf4( radicand ); + + zy_xz_yx = vec_sel( col0, col1, select_z ); + zy_xz_yx = vec_perm( zy_xz_yx, col2, _VECTORMATH_PERM_ZAYX ); + yz_zx_xy = vec_sel( col0, col1, select_x ); + yz_zx_xy = vec_perm( yz_zx_xy, col2, _VECTORMATH_PERM_BZXX ); + + sum = vec_add( zy_xz_yx, yz_zx_xy ); + diff = vec_sub( zy_xz_yx, yz_zx_xy ); + + scale = vec_madd( invSqrt, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), zero ); + res0 = vec_perm( sum, diff, _VECTORMATH_PERM_XZYA ); + res1 = vec_perm( sum, diff, _VECTORMATH_PERM_ZXXB ); + res2 = vec_perm( sum, diff, _VECTORMATH_PERM_YXXC ); + res3 = diff; + res0 = vec_sel( res0, radicand, select_x ); + res1 = vec_sel( res1, radicand, select_y ); + res2 = vec_sel( res2, radicand, select_z ); + res3 = vec_sel( res3, radicand, select_w ); + res0 = vec_madd( res0, vec_splat( scale, 0 ), zero ); + res1 = vec_madd( res1, vec_splat( scale, 1 ), zero ); + res2 = vec_madd( res2, vec_splat( scale, 2 ), zero ); + res3 = vec_madd( res3, vec_splat( scale, 3 ), zero ); + + /* determine case and select answer */ + + xx = vec_splat( col0, 0 ); + yy = vec_splat( col1, 1 ); + zz = vec_splat( col2, 2 ); + res = vec_sel( res0, res1, vec_cmpgt( yy, xx ) ); + res = vec_sel( res, res2, vec_and( vec_cmpgt( zz, xx ), vec_cmpgt( zz, yy ) ) ); + res = vec_sel( res, res3, vec_cmpgt( vec_splat( diagSum, 0 ), zero ) ); + result->vec128 = res; +} + +static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *tfrm0, const VmathVector3 *tfrm1 ) +{ + vmathV3ScalarMul( &result->col0, tfrm0, vmathV3GetX( tfrm1 ) ); + vmathV3ScalarMul( &result->col1, tfrm0, vmathV3GetY( tfrm1 ) ); + vmathV3ScalarMul( &result->col2, tfrm0, vmathV3GetZ( tfrm1 ) ); +} + +static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *tfrm0, const VmathVector4 *tfrm1 ) +{ + vmathV4ScalarMul( &result->col0, tfrm0, vmathV4GetX( tfrm1 ) ); + vmathV4ScalarMul( &result->col1, tfrm0, vmathV4GetY( tfrm1 ) ); + vmathV4ScalarMul( &result->col2, tfrm0, vmathV4GetZ( tfrm1 ) ); + vmathV4ScalarMul( &result->col3, tfrm0, vmathV4GetW( tfrm1 ) ); +} + +static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; + vec_float4 xxxx, yyyy, zzzz; + tmp0 = vec_mergeh( mat->col0.vec128, mat->col2.vec128 ); + tmp1 = vec_mergel( mat->col0.vec128, mat->col2.vec128 ); + xxxx = vec_splat( vec->vec128, 0 ); + mcol0 = vec_mergeh( tmp0, mat->col1.vec128 ); + mcol1 = vec_perm( tmp0, mat->col1.vec128, _VECTORMATH_PERM_ZBWX ); + mcol2 = vec_perm( tmp1, mat->col1.vec128, _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( vec->vec128, 1 ); + res = vec_madd( mcol0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + zzzz = vec_splat( vec->vec128, 2 ); + res = vec_madd( mcol1, yyyy, res ); + res = vec_madd( mcol2, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ) +{ + vec_float4 neg, res0, res1, res2; + neg = negatef4( vec->vec128 ); + res0 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_XZBX ); + res1 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_CXXX ); + res2 = vec_perm( vec->vec128, neg, _VECTORMATH_PERM_YAXX ); + res0 = vec_andc( res0, (vec_float4)_VECTORMATH_MASK_0xF000 ); + res1 = vec_andc( res1, (vec_float4)_VECTORMATH_MASK_0x0F00 ); + res2 = vec_andc( res2, (vec_float4)_VECTORMATH_MASK_0x00F0 ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; + vmathV3Cross( &tmpV3_0, vec, &mat->col0 ); + vmathV3Cross( &tmpV3_1, vec, &mat->col1 ); + vmathV3Cross( &tmpV3_2, vec, &mat->col2 ); + vmathM3MakeFromCols( result, &tmpV3_0, &tmpV3_1, &tmpV3_2 ); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/ppu/c/quat_aos.h b/common/vectormath/ppu/c/quat_aos.h index 2915f4f0..e5202649 100644 --- a/common/vectormath/ppu/c/quat_aos.h +++ b/common/vectormath/ppu/c/quat_aos.h @@ -1,379 +1,379 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_QUAT_AOS_C_H -#define _VECTORMATH_QUAT_AOS_C_H -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Definitions - */ -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -#endif - -static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathQMakeFromElems( VmathQuat *result, float _x, float _y, float _z, float _w ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & - __builtin_constant_p(_z) & __builtin_constant_p(_w)) { - result->vec128 = (vec_float4){_x, _y, _z, _w}; - } else { - float *pf = (float *)&result->vec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - pf[3] = _w; - } -} - -static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float _w ) -{ - result->vec128 = xyz->vec128; - _vmathVfSetElement(result->vec128, _w, 3); -} - -static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ) -{ - result->vec128 = _vmathVfSplatScalar(scalar); -} - -static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathQMakeIdentity( VmathQuat *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0001; -} - -static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - VmathQuat tmpQ_0, tmpQ_1; - vmathQSub( &tmpQ_0, quat1, quat0 ); - vmathQScalarMul( &tmpQ_1, &tmpQ_0, t ); - vmathQAdd( result, quat0, &tmpQ_1 ); -} - -static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ) -{ - VmathQuat start; - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot4( unitQuat0->vec128, unitQuat1->vec128 ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), cosAngle ); - cosAngle = vec_sel( cosAngle, negatef4( cosAngle ), selectMask ); - start.vec128 = vec_sel( unitQuat0->vec128, negatef4( unitQuat0->vec128 ), selectMask ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = _vmathVfSplatScalar(t); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - result->vec128 = vec_madd( start.vec128, scale0, vec_madd( unitQuat1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ) -{ - VmathQuat tmp0, tmp1; - vmathQSlerp( &tmp0, t, unitQuat0, unitQuat3 ); - vmathQSlerp( &tmp1, t, unitQuat1, unitQuat2 ); - vmathQSlerp( result, ( ( 2.0f * t ) * ( 1.0f - t ) ), &tmp0, &tmp1 ); -} - -static inline vec_float4 vmathQGet128( const VmathQuat *quat ) -{ - return quat->vec128; -} - -static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ) -{ - result->vec128 = vec_sel( vec->vec128, result->vec128, _VECTORMATH_MASK_0x000F ); -} - -static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathQSetX( VmathQuat *result, float _x ) -{ - _vmathVfSetElement(result->vec128, _x, 0); -} - -static inline float vmathQGetX( const VmathQuat *quat ) -{ - return _vmathVfGetElement(quat->vec128, 0); -} - -static inline void vmathQSetY( VmathQuat *result, float _y ) -{ - _vmathVfSetElement(result->vec128, _y, 1); -} - -static inline float vmathQGetY( const VmathQuat *quat ) -{ - return _vmathVfGetElement(quat->vec128, 1); -} - -static inline void vmathQSetZ( VmathQuat *result, float _z ) -{ - _vmathVfSetElement(result->vec128, _z, 2); -} - -static inline float vmathQGetZ( const VmathQuat *quat ) -{ - return _vmathVfGetElement(quat->vec128, 2); -} - -static inline void vmathQSetW( VmathQuat *result, float _w ) -{ - _vmathVfSetElement(result->vec128, _w, 3); -} - -static inline float vmathQGetW( const VmathQuat *quat ) -{ - return _vmathVfGetElement(quat->vec128, 3); -} - -static inline void vmathQSetElem( VmathQuat *result, int idx, float value ) -{ - _vmathVfSetElement(result->vec128, value, idx); -} - -static inline float vmathQGetElem( const VmathQuat *quat, int idx ) -{ - return _vmathVfGetElement(quat->vec128, idx); -} - -static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - result->vec128 = vec_add( quat0->vec128, quat1->vec128 ); -} - -static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - result->vec128 = vec_sub( quat0->vec128, quat1->vec128 ); -} - -static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ) -{ - result->vec128 = vec_madd( quat->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ) -{ - result->vec128 = divf4( quat->vec128, _vmathVfSplatScalar(scalar) ); -} - -static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = negatef4( quat->vec128 ); -} - -static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - vec_float4 result = _vmathVfDot4( quat0->vec128, quat1->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathQNorm( const VmathQuat *quat ) -{ - vec_float4 result = _vmathVfDot4( quat->vec128, quat->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathQLength( const VmathQuat *quat ) -{ - return sqrtf( vmathQNorm( quat ) ); -} - -static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ) -{ - vec_float4 dot = _vmathVfDot4( quat->vec128, quat->vec128 ); - result->vec128 = vec_madd( quat->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) -{ - VmathVector3 crossVec, tmpV3_0; - vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; - cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = vec_splat( cosAngle, 0 ); - cosAngleX2Plus2 = vec_madd( cosAngle, ((vec_float4){2.0f,2.0f,2.0f,2.0f}), ((vec_float4){2.0f,2.0f,2.0f,2.0f}) ); - recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); - cosHalfAngleX2 = vec_madd( recipCosHalfAngleX2, cosAngleX2Plus2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - vmathV3Cross( &tmpV3_0, unitVec0, unitVec1 ); - crossVec = tmpV3_0; - res = vec_madd( crossVec.vec128, recipCosHalfAngleX2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_sel( res, vec_madd( cosHalfAngleX2, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), _VECTORMATH_MASK_0x000F ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( vec_madd( unitVec->vec128, s, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), c, _VECTORMATH_MASK_0x000F ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationX( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0xF000 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationY( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x0F00 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x00F0 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - result->vec128 = res; -} - -static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; - vec_float4 product, l_wxyz, r_wxyz, xy, qw; - ldata = quat0->vec128; - rdata = quat1->vec128; - tmp0 = vec_perm( ldata, ldata, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( rdata, rdata, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( ldata, ldata, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( rdata, rdata, _VECTORMATH_PERM_YZXW ); - qv = vec_madd( vec_splat( ldata, 3 ), rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qv = vec_madd( vec_splat( rdata, 3 ), ldata, qv ); - qv = vec_madd( tmp0, tmp1, qv ); - qv = vec_nmsub( tmp2, tmp3, qv ); - product = vec_madd( ldata, rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - l_wxyz = vec_sld( ldata, ldata, 12 ); - r_wxyz = vec_sld( rdata, rdata, 12 ); - qw = vec_nmsub( l_wxyz, r_wxyz, product ); - xy = vec_madd( l_wxyz, r_wxyz, product ); - qw = vec_sub( qw, vec_sld( xy, xy, 8 ) ); - result->vec128 = vec_sel( qv, qw, _VECTORMATH_MASK_0x000F ); -} - -static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *quat, const VmathVector3 *vec ) -{ - vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; - qdata = quat->vec128; - vdata = vec->vec128; - tmp0 = vec_perm( qdata, qdata, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( vdata, vdata, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( qdata, qdata, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( vdata, vdata, _VECTORMATH_PERM_YZXW ); - wwww = vec_splat( qdata, 3 ); - qv = vec_madd( wwww, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qv = vec_madd( tmp0, tmp1, qv ); - qv = vec_nmsub( tmp2, tmp3, qv ); - product = vec_madd( qdata, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qw = vec_madd( vec_sld( qdata, qdata, 4 ), vec_sld( vdata, vdata, 4 ), product ); - qw = vec_add( vec_sld( product, product, 8 ), qw ); - tmp1 = vec_perm( qv, qv, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( qv, qv, _VECTORMATH_PERM_YZXW ); - res = vec_madd( vec_splat( qw, 0 ), qdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( wwww, qv, res ); - res = vec_madd( tmp0, tmp1, res ); - res = vec_nmsub( tmp2, tmp3, res ); - result->vec128 = res; -} - -static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = vec_xor( quat->vec128, ((vec_float4)(vec_int4){0x80000000,0x80000000,0x80000000,0}) ); -} - -static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ) -{ - unsigned int tmp; - tmp = (unsigned int)-(select1 > 0); - result->vec128 = vec_sel( quat0->vec128, quat1->vec128, _vmathVuiSplatScalar(tmp) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathQPrint( const VmathQuat *quat ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat->vec128; - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -static inline void vmathQPrints( const VmathQuat *quat, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat->vec128; - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_QUAT_AOS_C_H +#define _VECTORMATH_QUAT_AOS_C_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Definitions + */ +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +#endif + +static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathQMakeFromElems( VmathQuat *result, float _x, float _y, float _z, float _w ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & + __builtin_constant_p(_z) & __builtin_constant_p(_w)) { + result->vec128 = (vec_float4){_x, _y, _z, _w}; + } else { + float *pf = (float *)&result->vec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = _w; + } +} + +static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float _w ) +{ + result->vec128 = xyz->vec128; + _vmathVfSetElement(result->vec128, _w, 3); +} + +static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ) +{ + result->vec128 = _vmathVfSplatScalar(scalar); +} + +static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathQMakeIdentity( VmathQuat *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0001; +} + +static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + VmathQuat tmpQ_0, tmpQ_1; + vmathQSub( &tmpQ_0, quat1, quat0 ); + vmathQScalarMul( &tmpQ_1, &tmpQ_0, t ); + vmathQAdd( result, quat0, &tmpQ_1 ); +} + +static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ) +{ + VmathQuat start; + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot4( unitQuat0->vec128, unitQuat1->vec128 ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), cosAngle ); + cosAngle = vec_sel( cosAngle, negatef4( cosAngle ), selectMask ); + start.vec128 = vec_sel( unitQuat0->vec128, negatef4( unitQuat0->vec128 ), selectMask ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = _vmathVfSplatScalar(t); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + result->vec128 = vec_madd( start.vec128, scale0, vec_madd( unitQuat1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ) +{ + VmathQuat tmp0, tmp1; + vmathQSlerp( &tmp0, t, unitQuat0, unitQuat3 ); + vmathQSlerp( &tmp1, t, unitQuat1, unitQuat2 ); + vmathQSlerp( result, ( ( 2.0f * t ) * ( 1.0f - t ) ), &tmp0, &tmp1 ); +} + +static inline vec_float4 vmathQGet128( const VmathQuat *quat ) +{ + return quat->vec128; +} + +static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ) +{ + result->vec128 = vec_sel( vec->vec128, result->vec128, _VECTORMATH_MASK_0x000F ); +} + +static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathQSetX( VmathQuat *result, float _x ) +{ + _vmathVfSetElement(result->vec128, _x, 0); +} + +static inline float vmathQGetX( const VmathQuat *quat ) +{ + return _vmathVfGetElement(quat->vec128, 0); +} + +static inline void vmathQSetY( VmathQuat *result, float _y ) +{ + _vmathVfSetElement(result->vec128, _y, 1); +} + +static inline float vmathQGetY( const VmathQuat *quat ) +{ + return _vmathVfGetElement(quat->vec128, 1); +} + +static inline void vmathQSetZ( VmathQuat *result, float _z ) +{ + _vmathVfSetElement(result->vec128, _z, 2); +} + +static inline float vmathQGetZ( const VmathQuat *quat ) +{ + return _vmathVfGetElement(quat->vec128, 2); +} + +static inline void vmathQSetW( VmathQuat *result, float _w ) +{ + _vmathVfSetElement(result->vec128, _w, 3); +} + +static inline float vmathQGetW( const VmathQuat *quat ) +{ + return _vmathVfGetElement(quat->vec128, 3); +} + +static inline void vmathQSetElem( VmathQuat *result, int idx, float value ) +{ + _vmathVfSetElement(result->vec128, value, idx); +} + +static inline float vmathQGetElem( const VmathQuat *quat, int idx ) +{ + return _vmathVfGetElement(quat->vec128, idx); +} + +static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + result->vec128 = vec_add( quat0->vec128, quat1->vec128 ); +} + +static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + result->vec128 = vec_sub( quat0->vec128, quat1->vec128 ); +} + +static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ) +{ + result->vec128 = vec_madd( quat->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ) +{ + result->vec128 = divf4( quat->vec128, _vmathVfSplatScalar(scalar) ); +} + +static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = negatef4( quat->vec128 ); +} + +static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + vec_float4 result = _vmathVfDot4( quat0->vec128, quat1->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathQNorm( const VmathQuat *quat ) +{ + vec_float4 result = _vmathVfDot4( quat->vec128, quat->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathQLength( const VmathQuat *quat ) +{ + return sqrtf( vmathQNorm( quat ) ); +} + +static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ) +{ + vec_float4 dot = _vmathVfDot4( quat->vec128, quat->vec128 ); + result->vec128 = vec_madd( quat->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) +{ + VmathVector3 crossVec, tmpV3_0; + vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; + cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = vec_splat( cosAngle, 0 ); + cosAngleX2Plus2 = vec_madd( cosAngle, ((vec_float4){2.0f,2.0f,2.0f,2.0f}), ((vec_float4){2.0f,2.0f,2.0f,2.0f}) ); + recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); + cosHalfAngleX2 = vec_madd( recipCosHalfAngleX2, cosAngleX2Plus2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + vmathV3Cross( &tmpV3_0, unitVec0, unitVec1 ); + crossVec = tmpV3_0; + res = vec_madd( crossVec.vec128, recipCosHalfAngleX2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_sel( res, vec_madd( cosHalfAngleX2, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), _VECTORMATH_MASK_0x000F ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( vec_madd( unitVec->vec128, s, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), c, _VECTORMATH_MASK_0x000F ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationX( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0xF000 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationY( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x0F00 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( _vmathVfSplatScalar(radians), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x00F0 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + result->vec128 = res; +} + +static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; + vec_float4 product, l_wxyz, r_wxyz, xy, qw; + ldata = quat0->vec128; + rdata = quat1->vec128; + tmp0 = vec_perm( ldata, ldata, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( rdata, rdata, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( ldata, ldata, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( rdata, rdata, _VECTORMATH_PERM_YZXW ); + qv = vec_madd( vec_splat( ldata, 3 ), rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qv = vec_madd( vec_splat( rdata, 3 ), ldata, qv ); + qv = vec_madd( tmp0, tmp1, qv ); + qv = vec_nmsub( tmp2, tmp3, qv ); + product = vec_madd( ldata, rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + l_wxyz = vec_sld( ldata, ldata, 12 ); + r_wxyz = vec_sld( rdata, rdata, 12 ); + qw = vec_nmsub( l_wxyz, r_wxyz, product ); + xy = vec_madd( l_wxyz, r_wxyz, product ); + qw = vec_sub( qw, vec_sld( xy, xy, 8 ) ); + result->vec128 = vec_sel( qv, qw, _VECTORMATH_MASK_0x000F ); +} + +static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *quat, const VmathVector3 *vec ) +{ + vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; + qdata = quat->vec128; + vdata = vec->vec128; + tmp0 = vec_perm( qdata, qdata, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( vdata, vdata, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( qdata, qdata, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( vdata, vdata, _VECTORMATH_PERM_YZXW ); + wwww = vec_splat( qdata, 3 ); + qv = vec_madd( wwww, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qv = vec_madd( tmp0, tmp1, qv ); + qv = vec_nmsub( tmp2, tmp3, qv ); + product = vec_madd( qdata, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qw = vec_madd( vec_sld( qdata, qdata, 4 ), vec_sld( vdata, vdata, 4 ), product ); + qw = vec_add( vec_sld( product, product, 8 ), qw ); + tmp1 = vec_perm( qv, qv, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( qv, qv, _VECTORMATH_PERM_YZXW ); + res = vec_madd( vec_splat( qw, 0 ), qdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( wwww, qv, res ); + res = vec_madd( tmp0, tmp1, res ); + res = vec_nmsub( tmp2, tmp3, res ); + result->vec128 = res; +} + +static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = vec_xor( quat->vec128, ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ); +} + +static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ) +{ + unsigned int tmp; + tmp = (unsigned int)-(select1 > 0); + result->vec128 = vec_sel( quat0->vec128, quat1->vec128, _vmathVuiSplatScalar(tmp) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathQPrint( const VmathQuat *quat ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat->vec128; + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +static inline void vmathQPrints( const VmathQuat *quat, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat->vec128; + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/ppu/c/vec_aos.h b/common/vectormath/ppu/c/vec_aos.h index 58427a22..25682841 100644 --- a/common/vectormath/ppu/c/vec_aos.h +++ b/common/vectormath/ppu/c/vec_aos.h @@ -1,1125 +1,1125 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VEC_AOS_C_H -#define _VECTORMATH_VEC_AOS_C_H -#include -#include -#include -#include "vec_types.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Constants - * for permutes words are labeled [x,y,z,w] [a,b,c,d] - */ -#define _VECTORMATH_PERM_X 0x00010203 -#define _VECTORMATH_PERM_Y 0x04050607 -#define _VECTORMATH_PERM_Z 0x08090a0b -#define _VECTORMATH_PERM_W 0x0c0d0e0f -#define _VECTORMATH_PERM_A 0x10111213 -#define _VECTORMATH_PERM_B 0x14151617 -#define _VECTORMATH_PERM_C 0x18191a1b -#define _VECTORMATH_PERM_D 0x1c1d1e1f -#define _VECTORMATH_PERM_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A } -#define _VECTORMATH_PERM_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B } -#define _VECTORMATH_PERM_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B, _VECTORMATH_PERM_C } -#define _VECTORMATH_PERM_XYAW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_XAZW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W } -#define _VECTORMATH_MASK_0xF000 (vec_uint4){ 0xffffffff, 0, 0, 0 } -#define _VECTORMATH_MASK_0x0F00 (vec_uint4){ 0, 0xffffffff, 0, 0 } -#define _VECTORMATH_MASK_0x00F0 (vec_uint4){ 0, 0, 0xffffffff, 0 } -#define _VECTORMATH_MASK_0x000F (vec_uint4){ 0, 0, 0, 0xffffffff } -#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } -#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } -#define _VECTORMATH_SLERP_TOL 0.999f - -/*----------------------------------------------------------------------------- - * Definitions - */ -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); - return vec_madd( vec_sld( vec0, vec0, 8 ), vec_sld( vec1, vec1, 8 ), result ); -} - -static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); - return vec_add( vec_sld( result, result, 8 ), result ); -} - -static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, result; - tmp0 = vec_perm( vec0, vec0, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( vec1, vec1, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( vec0, vec0, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( vec1, vec1, _VECTORMATH_PERM_YZXW ); - result = vec_madd( tmp0, tmp1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_nmsub( tmp2, tmp3, result ); - return result; -} - -static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) -{ - vec_int4 bexp; - vec_uint4 mant, sign, hfloat; - vec_uint4 notZero, isInf; - const vec_uint4 hfloatInf = (vec_uint4){0x00007c00u,0x00007c00u,0x00007c00u,0x00007c00u}; - const vec_uint4 mergeMant = (vec_uint4){0x000003ffu,0x000003ffu,0x000003ffu,0x000003ffu}; - const vec_uint4 mergeSign = (vec_uint4){0x00008000u,0x00008000u,0x00008000u,0x00008000u}; - - sign = vec_sr((vec_uint4)v, (vec_uint4){16,16,16,16}); - mant = vec_sr((vec_uint4)v, (vec_uint4){13,13,13,13}); - bexp = vec_and(vec_sr((vec_int4)v, (vec_uint4){23,23,23,23}), (vec_int4){0xff,0xff,0xff,0xff}); - - notZero = (vec_uint4)vec_cmpgt(bexp, (vec_int4){112,112,112,112}); - isInf = (vec_uint4)vec_cmpgt(bexp, (vec_int4){142,142,142,142}); - - bexp = vec_add(bexp, (vec_int4){-112,-112,-112,-112}); - bexp = vec_sl(bexp, (vec_uint4){10,10,10,10}); - - hfloat = vec_sel((vec_uint4)bexp, mant, mergeMant); - hfloat = vec_sel((vec_uint4){0,0,0,0}, hfloat, notZero); - hfloat = vec_sel(hfloat, hfloatInf, isInf); - hfloat = vec_sel(hfloat, sign, mergeSign); - - return hfloat; -} - -static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) -{ - vec_uint4 hfloat_u, hfloat_v; - const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; - hfloat_u = _vmathVfToHalfFloatsUnpacked(u); - hfloat_v = _vmathVfToHalfFloatsUnpacked(v); - return (vec_ushort8)vec_perm(hfloat_u, hfloat_v, pack); -} - -#ifndef __GNUC__ -#define __builtin_constant_p(x) 0 -#endif - -static inline vec_float4 _vmathVfInsert(vec_float4 dst, vec_float4 src, int slot) -{ -#ifdef __GNUC__ - if (__builtin_constant_p(slot)) { - dst = vec_sld(dst, dst, slot<<2); - dst = vec_sld(dst, src, 4); - if (slot != 3) dst = vec_sld(dst, dst, (3-slot)<<2); - return dst; - } else -#endif - { - vec_uchar16 shiftpattern = vec_lvsr( 0, (float *)(size_t)(slot<<2) ); - vec_uint4 selectmask = (vec_uint4)vec_perm( (vec_uint4){0,0,0,0}, _VECTORMATH_MASK_0xF000, shiftpattern ); - return vec_sel( dst, src, selectmask ); - } -} - -#define _vmathVfGetElement(vec, slot) ((float *)&(vec))[slot] -#ifdef _VECTORMATH_SET_CONSTS_IN_MEM -#define _vmathVfSetElement(vec, scalar, slot) ((float *)&(vec))[slot] = scalar -#else -#define _vmathVfSetElement(vec, scalar, slot) \ -{ \ - if (__builtin_constant_p(scalar)) { \ - (vec) = _vmathVfInsert(vec, (vec_float4){scalar, scalar, scalar, scalar}, slot); \ - } else { \ - ((float *)&(vec))[slot] = scalar; \ - } \ -} -#endif - -static inline vec_float4 _vmathVfSplatScalar(float scalar) -{ - vec_float4 result; - if (__builtin_constant_p(scalar)) { - result = (vec_float4){scalar, scalar, scalar, scalar}; - } else { - result = vec_ld(0, &scalar); - result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); - } - return result; -} - -static inline vec_uint4 _vmathVuiSplatScalar(unsigned int scalar) -{ - vec_uint4 result; - if (__builtin_constant_p(scalar)) { - result = (vec_uint4){scalar, scalar, scalar, scalar}; - } else { - result = vec_ld(0, &scalar); - result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); - } - return result; -} - -#endif - -static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV3MakeFromElems( VmathVector3 *result, float _x, float _y, float _z ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { - result->vec128 = (vec_float4){_x, _y, _z, 0.0f}; - } else { - float *pf = (float *)&result->vec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - } -} - -static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = pnt->vec128; -} - -static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ) -{ - result->vec128 = _vmathVfSplatScalar(scalar); -} - -static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathV3MakeXAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_1000; -} - -static inline void vmathV3MakeYAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0100; -} - -static inline void vmathV3MakeZAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0010; -} - -static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - VmathVector3 tmpV3_0, tmpV3_1; - vmathV3Sub( &tmpV3_0, vec1, vec0 ); - vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); - vmathV3Add( result, vec0, &tmpV3_1 ); -} - -static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = _vmathVfSplatScalar(t); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - result->vec128 = vec_madd( unitVec0->vec128, scale0, vec_madd( unitVec1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ) -{ - return vec->vec128; -} - -static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = _VECTORMATH_MASK_0x000F; - dstVec = vec_sel(vec->vec128, dstVec, mask); - *quad = dstVec; -} - -static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = vec_sld( xyzx, yzxy, 12 ); - xyz2 = vec_sld( yzxy, zxyz, 8 ); - xyz3 = vec_sld( zxyz, zxyz, 4 ); - vec0->vec128 = xyzx; - vec1->vec128 = xyz1; - vec2->vec128 = xyz2; - vec3->vec128 = xyz3; -} - -static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = vec_perm( vec0->vec128, vec1->vec128, _VECTORMATH_PERM_XYZA ); - yzxy = vec_perm( vec1->vec128, vec2->vec128, _VECTORMATH_PERM_YZAB ); - zxyz = vec_perm( vec2->vec128, vec3->vec128, _VECTORMATH_PERM_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - vmathV3StoreXYZArray( vec0, vec1, vec2, vec3, xyz0 ); - vmathV3StoreXYZArray( vec4, vec5, vec6, vec7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -static inline void vmathV3SetX( VmathVector3 *result, float _x ) -{ - _vmathVfSetElement(result->vec128, _x, 0); -} - -static inline float vmathV3GetX( const VmathVector3 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 0); -} - -static inline void vmathV3SetY( VmathVector3 *result, float _y ) -{ - _vmathVfSetElement(result->vec128, _y, 1); -} - -static inline float vmathV3GetY( const VmathVector3 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 1); -} - -static inline void vmathV3SetZ( VmathVector3 *result, float _z ) -{ - _vmathVfSetElement(result->vec128, _z, 2); -} - -static inline float vmathV3GetZ( const VmathVector3 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 2); -} - -static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ) -{ - _vmathVfSetElement(result->vec128, value, idx); -} - -static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ) -{ - return _vmathVfGetElement(vec->vec128, idx); -} - -static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = vec_add( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = vec_sub( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt1 ) -{ - result->vec128 = vec_add( vec->vec128, pnt1->vec128 ); -} - -static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ) -{ - result->vec128 = vec_madd( vec->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ) -{ - result->vec128 = divf4( vec->vec128, _vmathVfSplatScalar(scalar) ); -} - -static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = negatef4( vec->vec128 ); -} - -static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = vec_madd( vec0->vec128, vec1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = divf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = recipf4( vec->vec128 ); -} - -static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = sqrtf4( vec->vec128 ); -} - -static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = rsqrtf4( vec->vec128 ); -} - -static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = fabsf4( vec->vec128 ); -} - -static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV3MaxElem( const VmathVector3 *vec ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = fmaxf4( vec_splat( vec->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV3MinElem( const VmathVector3 *vec ) -{ - vec_float4 result; - result = fminf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = fminf4( vec_splat( vec->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV3Sum( const VmathVector3 *vec ) -{ - vec_float4 result; - result = vec_add( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = vec_add( vec_splat( vec->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - vec_float4 result = _vmathVfDot3( vec0->vec128, vec1->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV3LengthSqr( const VmathVector3 *vec ) -{ - vec_float4 result = _vmathVfDot3( vec->vec128, vec->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV3Length( const VmathVector3 *vec ) -{ - return sqrtf( vmathV3LengthSqr( vec ) ); -} - -static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ) -{ - vec_float4 dot = _vmathVfDot3( vec->vec128, vec->vec128 ); - dot = vec_splat( dot, 0 ); - result->vec128 = vec_madd( vec->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = _vmathVfCross( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ) -{ - unsigned int tmp; - tmp = (unsigned int)-(select1 > 0); - result->vec128 = vec_sel( vec0->vec128, vec1->vec128, _vmathVuiSplatScalar(tmp) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathV3Print( const VmathVector3 *vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV4MakeFromElems( VmathVector4 *result, float _x, float _y, float _z, float _w ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & - __builtin_constant_p(_z) & __builtin_constant_p(_w)) { - result->vec128 = (vec_float4){_x, _y, _z, _w}; - } else { - float *pf = (float *)&result->vec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - pf[3] = _w; - } -} - -static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float _w ) -{ - result->vec128 = xyz->vec128; - _vmathVfSetElement(result->vec128, _w, 3); -} - -static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec->vec128; - result->vec128 = _vmathVfInsert(result->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), 3); -} - -static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = pnt->vec128; - result->vec128 = _vmathVfInsert(result->vec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), 3); -} - -static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ) -{ - result->vec128 = _vmathVfSplatScalar(scalar); -} - -static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathV4MakeXAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_1000; -} - -static inline void vmathV4MakeYAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0100; -} - -static inline void vmathV4MakeZAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0010; -} - -static inline void vmathV4MakeWAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0001; -} - -static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - VmathVector4 tmpV4_0, tmpV4_1; - vmathV4Sub( &tmpV4_0, vec1, vec0 ); - vmathV4ScalarMul( &tmpV4_1, &tmpV4_0, t ); - vmathV4Add( result, vec0, &tmpV4_1 ); -} - -static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot4( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = _vmathVfSplatScalar(t); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - result->vec128 = vec_madd( unitVec0->vec128, scale0, vec_madd( unitVec1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ) -{ - return vec->vec128; -} - -static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ) -{ - twoQuads[0] = _vmath2VfToHalfFloats(vec0->vec128, vec1->vec128); - twoQuads[1] = _vmath2VfToHalfFloats(vec2->vec128, vec3->vec128); -} - -static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec_sel( vec->vec128, result->vec128, _VECTORMATH_MASK_0x000F ); -} - -static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV4SetX( VmathVector4 *result, float _x ) -{ - _vmathVfSetElement(result->vec128, _x, 0); -} - -static inline float vmathV4GetX( const VmathVector4 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 0); -} - -static inline void vmathV4SetY( VmathVector4 *result, float _y ) -{ - _vmathVfSetElement(result->vec128, _y, 1); -} - -static inline float vmathV4GetY( const VmathVector4 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 1); -} - -static inline void vmathV4SetZ( VmathVector4 *result, float _z ) -{ - _vmathVfSetElement(result->vec128, _z, 2); -} - -static inline float vmathV4GetZ( const VmathVector4 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 2); -} - -static inline void vmathV4SetW( VmathVector4 *result, float _w ) -{ - _vmathVfSetElement(result->vec128, _w, 3); -} - -static inline float vmathV4GetW( const VmathVector4 *vec ) -{ - return _vmathVfGetElement(vec->vec128, 3); -} - -static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ) -{ - _vmathVfSetElement(result->vec128, value, idx); -} - -static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ) -{ - return _vmathVfGetElement(vec->vec128, idx); -} - -static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = vec_add( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = vec_sub( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ) -{ - result->vec128 = vec_madd( vec->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ) -{ - result->vec128 = divf4( vec->vec128, _vmathVfSplatScalar(scalar) ); -} - -static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = negatef4( vec->vec128 ); -} - -static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = vec_madd( vec0->vec128, vec1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = divf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = recipf4( vec->vec128 ); -} - -static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = sqrtf4( vec->vec128 ); -} - -static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = rsqrtf4( vec->vec128 ); -} - -static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = fabsf4( vec->vec128 ); -} - -static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV4MaxElem( const VmathVector4 *vec ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = fmaxf4( vec_splat( vec->vec128, 2 ), result ); - result = fmaxf4( vec_splat( vec->vec128, 3 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV4MinElem( const VmathVector4 *vec ) -{ - vec_float4 result; - result = fminf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = fminf4( vec_splat( vec->vec128, 2 ), result ); - result = fminf4( vec_splat( vec->vec128, 3 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV4Sum( const VmathVector4 *vec ) -{ - vec_float4 result; - result = vec_add( vec_splat( vec->vec128, 1 ), vec->vec128 ); - result = vec_add( vec_splat( vec->vec128, 2 ), result ); - result = vec_add( vec_splat( vec->vec128, 3 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - vec_float4 result = _vmathVfDot4( vec0->vec128, vec1->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV4LengthSqr( const VmathVector4 *vec ) -{ - vec_float4 result = _vmathVfDot4( vec->vec128, vec->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathV4Length( const VmathVector4 *vec ) -{ - return sqrtf( vmathV4LengthSqr( vec ) ); -} - -static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ) -{ - vec_float4 dot = _vmathVfDot4( vec->vec128, vec->vec128 ); - result->vec128 = vec_madd( vec->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ) -{ - unsigned int tmp; - tmp = (unsigned int)-(select1 > 0); - result->vec128 = vec_sel( vec0->vec128, vec1->vec128, _vmathVuiSplatScalar(tmp) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathV4Print( const VmathVector4 *vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = pnt->vec128; -} - -static inline void vmathP3MakeFromElems( VmathPoint3 *result, float _x, float _y, float _z ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { - result->vec128 = (vec_float4){_x, _y, _z, 0.0f}; - } else { - float *pf = (float *)&result->vec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - } -} - -static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ) -{ - result->vec128 = _vmathVfSplatScalar(scalar); -} - -static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0, tmpV3_1; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); - vmathP3AddV3( result, pnt0, &tmpV3_1 ); -} - -static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ) -{ - return pnt->vec128; -} - -static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = _VECTORMATH_MASK_0x000F; - dstVec = vec_sel(pnt->vec128, dstVec, mask); - *quad = dstVec; -} - -static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = vec_sld( xyzx, yzxy, 12 ); - xyz2 = vec_sld( yzxy, zxyz, 8 ); - xyz3 = vec_sld( zxyz, zxyz, 4 ); - pnt0->vec128 = xyzx; - pnt1->vec128 = xyz1; - pnt2->vec128 = xyz2; - pnt3->vec128 = xyz3; -} - -static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = vec_perm( pnt0->vec128, pnt1->vec128, _VECTORMATH_PERM_XYZA ); - yzxy = vec_perm( pnt1->vec128, pnt2->vec128, _VECTORMATH_PERM_YZAB ); - zxyz = vec_perm( pnt2->vec128, pnt3->vec128, _VECTORMATH_PERM_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - vmathP3StoreXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); - vmathP3StoreXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -static inline void vmathP3SetX( VmathPoint3 *result, float _x ) -{ - _vmathVfSetElement(result->vec128, _x, 0); -} - -static inline float vmathP3GetX( const VmathPoint3 *pnt ) -{ - return _vmathVfGetElement(pnt->vec128, 0); -} - -static inline void vmathP3SetY( VmathPoint3 *result, float _y ) -{ - _vmathVfSetElement(result->vec128, _y, 1); -} - -static inline float vmathP3GetY( const VmathPoint3 *pnt ) -{ - return _vmathVfGetElement(pnt->vec128, 1); -} - -static inline void vmathP3SetZ( VmathPoint3 *result, float _z ) -{ - _vmathVfSetElement(result->vec128, _z, 2); -} - -static inline float vmathP3GetZ( const VmathPoint3 *pnt ) -{ - return _vmathVfGetElement(pnt->vec128, 2); -} - -static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ) -{ - _vmathVfSetElement(result->vec128, value, idx); -} - -static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ) -{ - return _vmathVfGetElement(pnt->vec128, idx); -} - -static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = vec_sub( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) -{ - result->vec128 = vec_add( pnt->vec128, vec1->vec128 ); -} - -static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) -{ - result->vec128 = vec_sub( pnt->vec128, vec1->vec128 ); -} - -static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = vec_madd( pnt0->vec128, pnt1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); -} - -static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = divf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = recipf4( pnt->vec128 ); -} - -static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = sqrtf4( pnt->vec128 ); -} - -static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = rsqrtf4( pnt->vec128 ); -} - -static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = fabsf4( pnt->vec128 ); -} - -static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = copysignf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = fmaxf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline float vmathP3MaxElem( const VmathPoint3 *pnt ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); - result = fmaxf4( vec_splat( pnt->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = fminf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline float vmathP3MinElem( const VmathPoint3 *pnt ) -{ - vec_float4 result; - result = fminf4( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); - result = fminf4( vec_splat( pnt->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathP3Sum( const VmathPoint3 *pnt ) -{ - vec_float4 result; - result = vec_add( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); - result = vec_add( vec_splat( pnt->vec128, 2 ), result ); - return _vmathVfGetElement(result, 0); -} - -static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ) -{ - VmathPoint3 tmpP3_0; - vmathP3MakeFromScalar( &tmpP3_0, scaleVal ); - vmathP3MulPerElem( result, pnt, &tmpP3_0 ); -} - -static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ) -{ - VmathPoint3 tmpP3_0; - vmathP3MakeFromV3( &tmpP3_0, scaleVec ); - vmathP3MulPerElem( result, pnt, &tmpP3_0 ); -} - -static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ) -{ - vec_float4 result = _vmathVfDot3( pnt->vec128, unitVec->vec128 ); - return _vmathVfGetElement(result, 0); -} - -static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ) -{ - VmathVector3 tmpV3_0; - vmathV3MakeFromP3( &tmpV3_0, pnt ); - return vmathV3LengthSqr( &tmpV3_0 ); -} - -static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ) -{ - VmathVector3 tmpV3_0; - vmathV3MakeFromP3( &tmpV3_0, pnt ); - return vmathV3Length( &tmpV3_0 ); -} - -static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - return vmathV3LengthSqr( &tmpV3_0 ); -} - -static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - return vmathV3Length( &tmpV3_0 ); -} - -static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ) -{ - unsigned int tmp; - tmp = (unsigned int)-(select1 > 0); - result->vec128 = vec_sel( pnt0->vec128, pnt1->vec128, _vmathVuiSplatScalar(tmp) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathP3Print( const VmathPoint3 *pnt ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt->vec128; - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt->vec128; - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VEC_AOS_C_H +#define _VECTORMATH_VEC_AOS_C_H +#include +#include +#include +#include "vec_types.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Constants + * for permutes words are labeled [x,y,z,w] [a,b,c,d] + */ +#define _VECTORMATH_PERM_X 0x00010203 +#define _VECTORMATH_PERM_Y 0x04050607 +#define _VECTORMATH_PERM_Z 0x08090a0b +#define _VECTORMATH_PERM_W 0x0c0d0e0f +#define _VECTORMATH_PERM_A 0x10111213 +#define _VECTORMATH_PERM_B 0x14151617 +#define _VECTORMATH_PERM_C 0x18191a1b +#define _VECTORMATH_PERM_D 0x1c1d1e1f +#define _VECTORMATH_PERM_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A } +#define _VECTORMATH_PERM_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B } +#define _VECTORMATH_PERM_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B, _VECTORMATH_PERM_C } +#define _VECTORMATH_PERM_XYAW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_XAZW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W } +#define _VECTORMATH_MASK_0xF000 (vec_uint4){ 0xffffffff, 0, 0, 0 } +#define _VECTORMATH_MASK_0x0F00 (vec_uint4){ 0, 0xffffffff, 0, 0 } +#define _VECTORMATH_MASK_0x00F0 (vec_uint4){ 0, 0, 0xffffffff, 0 } +#define _VECTORMATH_MASK_0x000F (vec_uint4){ 0, 0, 0, 0xffffffff } +#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } +#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } +#define _VECTORMATH_SLERP_TOL 0.999f + +/*----------------------------------------------------------------------------- + * Definitions + */ +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); + return vec_madd( vec_sld( vec0, vec0, 8 ), vec_sld( vec1, vec1, 8 ), result ); +} + +static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); + return vec_add( vec_sld( result, result, 8 ), result ); +} + +static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, result; + tmp0 = vec_perm( vec0, vec0, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( vec1, vec1, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( vec0, vec0, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( vec1, vec1, _VECTORMATH_PERM_YZXW ); + result = vec_madd( tmp0, tmp1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_nmsub( tmp2, tmp3, result ); + return result; +} + +static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) +{ + vec_int4 bexp; + vec_uint4 mant, sign, hfloat; + vec_uint4 notZero, isInf; + const vec_uint4 hfloatInf = (vec_uint4){0x00007c00u,0x00007c00u,0x00007c00u,0x00007c00u}; + const vec_uint4 mergeMant = (vec_uint4){0x000003ffu,0x000003ffu,0x000003ffu,0x000003ffu}; + const vec_uint4 mergeSign = (vec_uint4){0x00008000u,0x00008000u,0x00008000u,0x00008000u}; + + sign = vec_sr((vec_uint4)v, (vec_uint4){16,16,16,16}); + mant = vec_sr((vec_uint4)v, (vec_uint4){13,13,13,13}); + bexp = vec_and(vec_sr((vec_int4)v, (vec_uint4){23,23,23,23}), (vec_int4){0xff,0xff,0xff,0xff}); + + notZero = (vec_uint4)vec_cmpgt(bexp, (vec_int4){112,112,112,112}); + isInf = (vec_uint4)vec_cmpgt(bexp, (vec_int4){142,142,142,142}); + + bexp = vec_add(bexp, (vec_int4){-112,-112,-112,-112}); + bexp = vec_sl(bexp, (vec_uint4){10,10,10,10}); + + hfloat = vec_sel((vec_uint4)bexp, mant, mergeMant); + hfloat = vec_sel((vec_uint4){0,0,0,0}, hfloat, notZero); + hfloat = vec_sel(hfloat, hfloatInf, isInf); + hfloat = vec_sel(hfloat, sign, mergeSign); + + return hfloat; +} + +static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) +{ + vec_uint4 hfloat_u, hfloat_v; + const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; + hfloat_u = _vmathVfToHalfFloatsUnpacked(u); + hfloat_v = _vmathVfToHalfFloatsUnpacked(v); + return (vec_ushort8)vec_perm(hfloat_u, hfloat_v, pack); +} + +#ifndef __GNUC__ +#define __builtin_constant_p(x) 0 +#endif + +static inline vec_float4 _vmathVfInsert(vec_float4 dst, vec_float4 src, int slot) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(slot)) { + dst = vec_sld(dst, dst, slot<<2); + dst = vec_sld(dst, src, 4); + if (slot != 3) dst = vec_sld(dst, dst, (3-slot)<<2); + return dst; + } else +#endif + { + vec_uchar16 shiftpattern = vec_lvsr( 0, (float *)(size_t)(slot<<2) ); + vec_uint4 selectmask = (vec_uint4)vec_perm( (vec_uint4){0,0,0,0}, _VECTORMATH_MASK_0xF000, shiftpattern ); + return vec_sel( dst, src, selectmask ); + } +} + +#define _vmathVfGetElement(vec, slot) ((float *)&(vec))[slot] +#ifdef _VECTORMATH_SET_CONSTS_IN_MEM +#define _vmathVfSetElement(vec, scalar, slot) ((float *)&(vec))[slot] = scalar +#else +#define _vmathVfSetElement(vec, scalar, slot) \ +{ \ + if (__builtin_constant_p(scalar)) { \ + (vec) = _vmathVfInsert(vec, (vec_float4){scalar, scalar, scalar, scalar}, slot); \ + } else { \ + ((float *)&(vec))[slot] = scalar; \ + } \ +} +#endif + +static inline vec_float4 _vmathVfSplatScalar(float scalar) +{ + vec_float4 result; + if (__builtin_constant_p(scalar)) { + result = (vec_float4){scalar, scalar, scalar, scalar}; + } else { + result = vec_ld(0, &scalar); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); + } + return result; +} + +static inline vec_uint4 _vmathVuiSplatScalar(unsigned int scalar) +{ + vec_uint4 result; + if (__builtin_constant_p(scalar)) { + result = (vec_uint4){scalar, scalar, scalar, scalar}; + } else { + result = vec_ld(0, &scalar); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); + } + return result; +} + +#endif + +static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV3MakeFromElems( VmathVector3 *result, float _x, float _y, float _z ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { + result->vec128 = (vec_float4){_x, _y, _z, 0.0f}; + } else { + float *pf = (float *)&result->vec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + } +} + +static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = pnt->vec128; +} + +static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ) +{ + result->vec128 = _vmathVfSplatScalar(scalar); +} + +static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathV3MakeXAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_1000; +} + +static inline void vmathV3MakeYAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0100; +} + +static inline void vmathV3MakeZAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0010; +} + +static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + VmathVector3 tmpV3_0, tmpV3_1; + vmathV3Sub( &tmpV3_0, vec1, vec0 ); + vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); + vmathV3Add( result, vec0, &tmpV3_1 ); +} + +static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = _vmathVfSplatScalar(t); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + result->vec128 = vec_madd( unitVec0->vec128, scale0, vec_madd( unitVec1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ) +{ + return vec->vec128; +} + +static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = _VECTORMATH_MASK_0x000F; + dstVec = vec_sel(vec->vec128, dstVec, mask); + *quad = dstVec; +} + +static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = vec_sld( xyzx, yzxy, 12 ); + xyz2 = vec_sld( yzxy, zxyz, 8 ); + xyz3 = vec_sld( zxyz, zxyz, 4 ); + vec0->vec128 = xyzx; + vec1->vec128 = xyz1; + vec2->vec128 = xyz2; + vec3->vec128 = xyz3; +} + +static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = vec_perm( vec0->vec128, vec1->vec128, _VECTORMATH_PERM_XYZA ); + yzxy = vec_perm( vec1->vec128, vec2->vec128, _VECTORMATH_PERM_YZAB ); + zxyz = vec_perm( vec2->vec128, vec3->vec128, _VECTORMATH_PERM_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + vmathV3StoreXYZArray( vec0, vec1, vec2, vec3, xyz0 ); + vmathV3StoreXYZArray( vec4, vec5, vec6, vec7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +static inline void vmathV3SetX( VmathVector3 *result, float _x ) +{ + _vmathVfSetElement(result->vec128, _x, 0); +} + +static inline float vmathV3GetX( const VmathVector3 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 0); +} + +static inline void vmathV3SetY( VmathVector3 *result, float _y ) +{ + _vmathVfSetElement(result->vec128, _y, 1); +} + +static inline float vmathV3GetY( const VmathVector3 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 1); +} + +static inline void vmathV3SetZ( VmathVector3 *result, float _z ) +{ + _vmathVfSetElement(result->vec128, _z, 2); +} + +static inline float vmathV3GetZ( const VmathVector3 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 2); +} + +static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ) +{ + _vmathVfSetElement(result->vec128, value, idx); +} + +static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ) +{ + return _vmathVfGetElement(vec->vec128, idx); +} + +static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = vec_add( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = vec_sub( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt1 ) +{ + result->vec128 = vec_add( vec->vec128, pnt1->vec128 ); +} + +static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ) +{ + result->vec128 = vec_madd( vec->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ) +{ + result->vec128 = divf4( vec->vec128, _vmathVfSplatScalar(scalar) ); +} + +static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = negatef4( vec->vec128 ); +} + +static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = vec_madd( vec0->vec128, vec1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = divf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = recipf4( vec->vec128 ); +} + +static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = sqrtf4( vec->vec128 ); +} + +static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = rsqrtf4( vec->vec128 ); +} + +static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = fabsf4( vec->vec128 ); +} + +static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV3MaxElem( const VmathVector3 *vec ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = fmaxf4( vec_splat( vec->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV3MinElem( const VmathVector3 *vec ) +{ + vec_float4 result; + result = fminf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = fminf4( vec_splat( vec->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV3Sum( const VmathVector3 *vec ) +{ + vec_float4 result; + result = vec_add( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = vec_add( vec_splat( vec->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + vec_float4 result = _vmathVfDot3( vec0->vec128, vec1->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV3LengthSqr( const VmathVector3 *vec ) +{ + vec_float4 result = _vmathVfDot3( vec->vec128, vec->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV3Length( const VmathVector3 *vec ) +{ + return sqrtf( vmathV3LengthSqr( vec ) ); +} + +static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ) +{ + vec_float4 dot = _vmathVfDot3( vec->vec128, vec->vec128 ); + dot = vec_splat( dot, 0 ); + result->vec128 = vec_madd( vec->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = _vmathVfCross( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ) +{ + unsigned int tmp; + tmp = (unsigned int)-(select1 > 0); + result->vec128 = vec_sel( vec0->vec128, vec1->vec128, _vmathVuiSplatScalar(tmp) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathV3Print( const VmathVector3 *vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV4MakeFromElems( VmathVector4 *result, float _x, float _y, float _z, float _w ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & + __builtin_constant_p(_z) & __builtin_constant_p(_w)) { + result->vec128 = (vec_float4){_x, _y, _z, _w}; + } else { + float *pf = (float *)&result->vec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = _w; + } +} + +static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float _w ) +{ + result->vec128 = xyz->vec128; + _vmathVfSetElement(result->vec128, _w, 3); +} + +static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec->vec128; + result->vec128 = _vmathVfInsert(result->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), 3); +} + +static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = pnt->vec128; + result->vec128 = _vmathVfInsert(result->vec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), 3); +} + +static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ) +{ + result->vec128 = _vmathVfSplatScalar(scalar); +} + +static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathV4MakeXAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_1000; +} + +static inline void vmathV4MakeYAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0100; +} + +static inline void vmathV4MakeZAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0010; +} + +static inline void vmathV4MakeWAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0001; +} + +static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + VmathVector4 tmpV4_0, tmpV4_1; + vmathV4Sub( &tmpV4_0, vec1, vec0 ); + vmathV4ScalarMul( &tmpV4_1, &tmpV4_0, t ); + vmathV4Add( result, vec0, &tmpV4_1 ); +} + +static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot4( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = _vmathVfSplatScalar(t); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + result->vec128 = vec_madd( unitVec0->vec128, scale0, vec_madd( unitVec1->vec128, scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ) +{ + return vec->vec128; +} + +static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ) +{ + twoQuads[0] = _vmath2VfToHalfFloats(vec0->vec128, vec1->vec128); + twoQuads[1] = _vmath2VfToHalfFloats(vec2->vec128, vec3->vec128); +} + +static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec_sel( vec->vec128, result->vec128, _VECTORMATH_MASK_0x000F ); +} + +static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV4SetX( VmathVector4 *result, float _x ) +{ + _vmathVfSetElement(result->vec128, _x, 0); +} + +static inline float vmathV4GetX( const VmathVector4 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 0); +} + +static inline void vmathV4SetY( VmathVector4 *result, float _y ) +{ + _vmathVfSetElement(result->vec128, _y, 1); +} + +static inline float vmathV4GetY( const VmathVector4 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 1); +} + +static inline void vmathV4SetZ( VmathVector4 *result, float _z ) +{ + _vmathVfSetElement(result->vec128, _z, 2); +} + +static inline float vmathV4GetZ( const VmathVector4 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 2); +} + +static inline void vmathV4SetW( VmathVector4 *result, float _w ) +{ + _vmathVfSetElement(result->vec128, _w, 3); +} + +static inline float vmathV4GetW( const VmathVector4 *vec ) +{ + return _vmathVfGetElement(vec->vec128, 3); +} + +static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ) +{ + _vmathVfSetElement(result->vec128, value, idx); +} + +static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ) +{ + return _vmathVfGetElement(vec->vec128, idx); +} + +static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = vec_add( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = vec_sub( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ) +{ + result->vec128 = vec_madd( vec->vec128, _vmathVfSplatScalar(scalar), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ) +{ + result->vec128 = divf4( vec->vec128, _vmathVfSplatScalar(scalar) ); +} + +static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = negatef4( vec->vec128 ); +} + +static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = vec_madd( vec0->vec128, vec1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = divf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = recipf4( vec->vec128 ); +} + +static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = sqrtf4( vec->vec128 ); +} + +static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = rsqrtf4( vec->vec128 ); +} + +static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = fabsf4( vec->vec128 ); +} + +static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV4MaxElem( const VmathVector4 *vec ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = fmaxf4( vec_splat( vec->vec128, 2 ), result ); + result = fmaxf4( vec_splat( vec->vec128, 3 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV4MinElem( const VmathVector4 *vec ) +{ + vec_float4 result; + result = fminf4( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = fminf4( vec_splat( vec->vec128, 2 ), result ); + result = fminf4( vec_splat( vec->vec128, 3 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV4Sum( const VmathVector4 *vec ) +{ + vec_float4 result; + result = vec_add( vec_splat( vec->vec128, 1 ), vec->vec128 ); + result = vec_add( vec_splat( vec->vec128, 2 ), result ); + result = vec_add( vec_splat( vec->vec128, 3 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + vec_float4 result = _vmathVfDot4( vec0->vec128, vec1->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV4LengthSqr( const VmathVector4 *vec ) +{ + vec_float4 result = _vmathVfDot4( vec->vec128, vec->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathV4Length( const VmathVector4 *vec ) +{ + return sqrtf( vmathV4LengthSqr( vec ) ); +} + +static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ) +{ + vec_float4 dot = _vmathVfDot4( vec->vec128, vec->vec128 ); + result->vec128 = vec_madd( vec->vec128, rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ) +{ + unsigned int tmp; + tmp = (unsigned int)-(select1 > 0); + result->vec128 = vec_sel( vec0->vec128, vec1->vec128, _vmathVuiSplatScalar(tmp) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathV4Print( const VmathVector4 *vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = pnt->vec128; +} + +static inline void vmathP3MakeFromElems( VmathPoint3 *result, float _x, float _y, float _z ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { + result->vec128 = (vec_float4){_x, _y, _z, 0.0f}; + } else { + float *pf = (float *)&result->vec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + } +} + +static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ) +{ + result->vec128 = _vmathVfSplatScalar(scalar); +} + +static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0, tmpV3_1; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); + vmathP3AddV3( result, pnt0, &tmpV3_1 ); +} + +static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ) +{ + return pnt->vec128; +} + +static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = _VECTORMATH_MASK_0x000F; + dstVec = vec_sel(pnt->vec128, dstVec, mask); + *quad = dstVec; +} + +static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = vec_sld( xyzx, yzxy, 12 ); + xyz2 = vec_sld( yzxy, zxyz, 8 ); + xyz3 = vec_sld( zxyz, zxyz, 4 ); + pnt0->vec128 = xyzx; + pnt1->vec128 = xyz1; + pnt2->vec128 = xyz2; + pnt3->vec128 = xyz3; +} + +static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = vec_perm( pnt0->vec128, pnt1->vec128, _VECTORMATH_PERM_XYZA ); + yzxy = vec_perm( pnt1->vec128, pnt2->vec128, _VECTORMATH_PERM_YZAB ); + zxyz = vec_perm( pnt2->vec128, pnt3->vec128, _VECTORMATH_PERM_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + vmathP3StoreXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); + vmathP3StoreXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +static inline void vmathP3SetX( VmathPoint3 *result, float _x ) +{ + _vmathVfSetElement(result->vec128, _x, 0); +} + +static inline float vmathP3GetX( const VmathPoint3 *pnt ) +{ + return _vmathVfGetElement(pnt->vec128, 0); +} + +static inline void vmathP3SetY( VmathPoint3 *result, float _y ) +{ + _vmathVfSetElement(result->vec128, _y, 1); +} + +static inline float vmathP3GetY( const VmathPoint3 *pnt ) +{ + return _vmathVfGetElement(pnt->vec128, 1); +} + +static inline void vmathP3SetZ( VmathPoint3 *result, float _z ) +{ + _vmathVfSetElement(result->vec128, _z, 2); +} + +static inline float vmathP3GetZ( const VmathPoint3 *pnt ) +{ + return _vmathVfGetElement(pnt->vec128, 2); +} + +static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ) +{ + _vmathVfSetElement(result->vec128, value, idx); +} + +static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ) +{ + return _vmathVfGetElement(pnt->vec128, idx); +} + +static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = vec_sub( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) +{ + result->vec128 = vec_add( pnt->vec128, vec1->vec128 ); +} + +static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) +{ + result->vec128 = vec_sub( pnt->vec128, vec1->vec128 ); +} + +static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = vec_madd( pnt0->vec128, pnt1->vec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); +} + +static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = divf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = recipf4( pnt->vec128 ); +} + +static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = sqrtf4( pnt->vec128 ); +} + +static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = rsqrtf4( pnt->vec128 ); +} + +static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = fabsf4( pnt->vec128 ); +} + +static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = copysignf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = fmaxf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline float vmathP3MaxElem( const VmathPoint3 *pnt ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); + result = fmaxf4( vec_splat( pnt->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = fminf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline float vmathP3MinElem( const VmathPoint3 *pnt ) +{ + vec_float4 result; + result = fminf4( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); + result = fminf4( vec_splat( pnt->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathP3Sum( const VmathPoint3 *pnt ) +{ + vec_float4 result; + result = vec_add( vec_splat( pnt->vec128, 1 ), pnt->vec128 ); + result = vec_add( vec_splat( pnt->vec128, 2 ), result ); + return _vmathVfGetElement(result, 0); +} + +static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ) +{ + VmathPoint3 tmpP3_0; + vmathP3MakeFromScalar( &tmpP3_0, scaleVal ); + vmathP3MulPerElem( result, pnt, &tmpP3_0 ); +} + +static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ) +{ + VmathPoint3 tmpP3_0; + vmathP3MakeFromV3( &tmpP3_0, scaleVec ); + vmathP3MulPerElem( result, pnt, &tmpP3_0 ); +} + +static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ) +{ + vec_float4 result = _vmathVfDot3( pnt->vec128, unitVec->vec128 ); + return _vmathVfGetElement(result, 0); +} + +static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ) +{ + VmathVector3 tmpV3_0; + vmathV3MakeFromP3( &tmpV3_0, pnt ); + return vmathV3LengthSqr( &tmpV3_0 ); +} + +static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ) +{ + VmathVector3 tmpV3_0; + vmathV3MakeFromP3( &tmpV3_0, pnt ); + return vmathV3Length( &tmpV3_0 ); +} + +static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + return vmathV3LengthSqr( &tmpV3_0 ); +} + +static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + return vmathV3Length( &tmpV3_0 ); +} + +static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ) +{ + unsigned int tmp; + tmp = (unsigned int)-(select1 > 0); + result->vec128 = vec_sel( pnt0->vec128, pnt1->vec128, _vmathVuiSplatScalar(tmp) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathP3Print( const VmathPoint3 *pnt ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt->vec128; + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt->vec128; + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/ppu/c/vectormath_aos.h b/common/vectormath/ppu/c/vectormath_aos.h index 6a6ccd28..119e2d29 100644 --- a/common/vectormath/ppu/c/vectormath_aos.h +++ b/common/vectormath/ppu/c/vectormath_aos.h @@ -1,1960 +1,1960 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_AOS_C_PPU_H -#define _VECTORMATH_AOS_C_PPU_H - -#include -#include -#include -#include "vec_types.h" - -#ifdef _VECTORMATH_DEBUG -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef _VECTORMATH_AOS_C_TYPES_H -#define _VECTORMATH_AOS_C_TYPES_H - -/* A 3-D vector in array-of-structures format - */ -typedef struct _VmathVector3 -{ - vec_float4 vec128; -} VmathVector3; - -/* A 4-D vector in array-of-structures format - */ -typedef struct _VmathVector4 -{ - vec_float4 vec128; -} VmathVector4; - -/* A 3-D point in array-of-structures format - */ -typedef struct _VmathPoint3 -{ - vec_float4 vec128; -} VmathPoint3; - -/* A quaternion in array-of-structures format - */ -typedef struct _VmathQuat -{ - vec_float4 vec128; -} VmathQuat; - -/* A 3x3 matrix in array-of-structures format - */ -typedef struct _VmathMatrix3 -{ - VmathVector3 col0; - VmathVector3 col1; - VmathVector3 col2; -} VmathMatrix3; - -/* A 4x4 matrix in array-of-structures format - */ -typedef struct _VmathMatrix4 -{ - VmathVector4 col0; - VmathVector4 col1; - VmathVector4 col2; - VmathVector4 col3; -} VmathMatrix4; - -/* A 3x4 transformation matrix in array-of-structures format - */ -typedef struct _VmathTransform3 -{ - VmathVector3 col0; - VmathVector3 col1; - VmathVector3 col2; - VmathVector3 col3; -} VmathTransform3; - -#endif - -/* - * Copy a 3-D vector - */ -static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Construct a 3-D vector from x, y, and z elements - */ -static inline void vmathV3MakeFromElems( VmathVector3 *result, float x, float y, float z ); - -/* - * Copy elements from a 3-D point into a 3-D vector - */ -static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ); - -/* - * Set all elements of a 3-D vector to the same scalar value - */ -static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ); - -/* - * Set vector float data in a 3-D vector - */ -static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 3-D vector - */ -static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ); - -/* - * Set the x element of a 3-D vector - */ -static inline void vmathV3SetX( VmathVector3 *result, float x ); - -/* - * Set the y element of a 3-D vector - */ -static inline void vmathV3SetY( VmathVector3 *result, float y ); - -/* - * Set the z element of a 3-D vector - */ -static inline void vmathV3SetZ( VmathVector3 *result, float z ); - -/* - * Get the x element of a 3-D vector - */ -static inline float vmathV3GetX( const VmathVector3 *vec ); - -/* - * Get the y element of a 3-D vector - */ -static inline float vmathV3GetY( const VmathVector3 *vec ); - -/* - * Get the z element of a 3-D vector - */ -static inline float vmathV3GetZ( const VmathVector3 *vec ); - -/* - * Set an x, y, or z element of a 3-D vector by index - */ -static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ); - -/* - * Get an x, y, or z element of a 3-D vector by index - */ -static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ); - -/* - * Add two 3-D vectors - */ -static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Subtract a 3-D vector from another 3-D vector - */ -static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Add a 3-D vector to a 3-D point - */ -static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt ); - -/* - * Multiply a 3-D vector by a scalar - */ -static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ); - -/* - * Divide a 3-D vector by a scalar - */ -static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ); - -/* - * Negate all elements of a 3-D vector - */ -static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Construct x axis - */ -static inline void vmathV3MakeXAxis( VmathVector3 *result ); - -/* - * Construct y axis - */ -static inline void vmathV3MakeYAxis( VmathVector3 *result ); - -/* - * Construct z axis - */ -static inline void vmathV3MakeZAxis( VmathVector3 *result ); - -/* - * Multiply two 3-D vectors per element - */ -static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Divide two 3-D vectors per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Compute the reciprocal of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the square root of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the reciprocal square root of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the absolute value of a 3-D vector per element - */ -static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Copy sign from one 3-D vector to another, per element - */ -static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Maximum of two 3-D vectors per element - */ -static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Minimum of two 3-D vectors per element - */ -static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Maximum element of a 3-D vector - */ -static inline float vmathV3MaxElem( const VmathVector3 *vec ); - -/* - * Minimum element of a 3-D vector - */ -static inline float vmathV3MinElem( const VmathVector3 *vec ); - -/* - * Compute the sum of all elements of a 3-D vector - */ -static inline float vmathV3Sum( const VmathVector3 *vec ); - -/* - * Compute the dot product of two 3-D vectors - */ -static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Compute the square of the length of a 3-D vector - */ -static inline float vmathV3LengthSqr( const VmathVector3 *vec ); - -/* - * Compute the length of a 3-D vector - */ -static inline float vmathV3Length( const VmathVector3 *vec ); - -/* - * Normalize a 3-D vector - * NOTE: - * The result is unpredictable when all elements of vec are at or near zero. - */ -static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute cross product of two 3-D vectors - */ -static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Outer product of two 3-D vectors - */ -static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Pre-multiply a row vector by a 3x3 matrix - * NOTE: - * Slower than column post-multiply. - */ -static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); - -/* - * Cross-product matrix of a 3-D vector - */ -static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ); - -/* - * Create cross-product matrix and multiply - * NOTE: - * Faster than separately creating a cross-product matrix and multiplying. - */ -static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); - -/* - * Linear interpolation between two 3-D vectors - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Spherical linear interpolation between two 3-D vectors - * NOTE: - * The result is unpredictable if the vectors point in opposite directions. - * Does not clamp t between 0 and 1. - */ -static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); - -/* - * Conditionally select between two 3-D vectors - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ); - -/* - * Store x, y, and z elements of a 3-D vector in the first three words of a quadword. - * The value of the fourth word (the word with the highest address) remains unchanged - */ -static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ); - -/* - * Load four three-float 3-D vectors, stored in three quadwords - */ -static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ); - -/* - * Store four 3-D vectors in three quadwords - */ -static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ); - -/* - * Store eight 3-D vectors as half-floats - */ -static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3-D vector - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV3Print( const VmathVector3 *vec ); - -/* - * Print a 3-D vector and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ); - -#endif - -/* - * Copy a 4-D vector - */ -static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Construct a 4-D vector from x, y, z, and w elements - */ -static inline void vmathV4MakeFromElems( VmathVector4 *result, float x, float y, float z, float w ); - -/* - * Construct a 4-D vector from a 3-D vector and a scalar - */ -static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float w ); - -/* - * Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 - */ -static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ); - -/* - * Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 - */ -static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ); - -/* - * Copy elements from a quaternion into a 4-D vector - */ -static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ); - -/* - * Set all elements of a 4-D vector to the same scalar value - */ -static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ); - -/* - * Set vector float data in a 4-D vector - */ -static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 4-D vector - */ -static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ); - -/* - * Set the x, y, and z elements of a 4-D vector - * NOTE: - * This function does not change the w element. - */ -static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ); - -/* - * Get the x, y, and z elements of a 4-D vector - */ -static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ); - -/* - * Set the x element of a 4-D vector - */ -static inline void vmathV4SetX( VmathVector4 *result, float x ); - -/* - * Set the y element of a 4-D vector - */ -static inline void vmathV4SetY( VmathVector4 *result, float y ); - -/* - * Set the z element of a 4-D vector - */ -static inline void vmathV4SetZ( VmathVector4 *result, float z ); - -/* - * Set the w element of a 4-D vector - */ -static inline void vmathV4SetW( VmathVector4 *result, float w ); - -/* - * Get the x element of a 4-D vector - */ -static inline float vmathV4GetX( const VmathVector4 *vec ); - -/* - * Get the y element of a 4-D vector - */ -static inline float vmathV4GetY( const VmathVector4 *vec ); - -/* - * Get the z element of a 4-D vector - */ -static inline float vmathV4GetZ( const VmathVector4 *vec ); - -/* - * Get the w element of a 4-D vector - */ -static inline float vmathV4GetW( const VmathVector4 *vec ); - -/* - * Set an x, y, z, or w element of a 4-D vector by index - */ -static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ); - -/* - * Get an x, y, z, or w element of a 4-D vector by index - */ -static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ); - -/* - * Add two 4-D vectors - */ -static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Subtract a 4-D vector from another 4-D vector - */ -static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Multiply a 4-D vector by a scalar - */ -static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ); - -/* - * Divide a 4-D vector by a scalar - */ -static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ); - -/* - * Negate all elements of a 4-D vector - */ -static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Construct x axis - */ -static inline void vmathV4MakeXAxis( VmathVector4 *result ); - -/* - * Construct y axis - */ -static inline void vmathV4MakeYAxis( VmathVector4 *result ); - -/* - * Construct z axis - */ -static inline void vmathV4MakeZAxis( VmathVector4 *result ); - -/* - * Construct w axis - */ -static inline void vmathV4MakeWAxis( VmathVector4 *result ); - -/* - * Multiply two 4-D vectors per element - */ -static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Divide two 4-D vectors per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Compute the reciprocal of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the square root of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the reciprocal square root of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the absolute value of a 4-D vector per element - */ -static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Copy sign from one 4-D vector to another, per element - */ -static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Maximum of two 4-D vectors per element - */ -static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Minimum of two 4-D vectors per element - */ -static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Maximum element of a 4-D vector - */ -static inline float vmathV4MaxElem( const VmathVector4 *vec ); - -/* - * Minimum element of a 4-D vector - */ -static inline float vmathV4MinElem( const VmathVector4 *vec ); - -/* - * Compute the sum of all elements of a 4-D vector - */ -static inline float vmathV4Sum( const VmathVector4 *vec ); - -/* - * Compute the dot product of two 4-D vectors - */ -static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Compute the square of the length of a 4-D vector - */ -static inline float vmathV4LengthSqr( const VmathVector4 *vec ); - -/* - * Compute the length of a 4-D vector - */ -static inline float vmathV4Length( const VmathVector4 *vec ); - -/* - * Normalize a 4-D vector - * NOTE: - * The result is unpredictable when all elements of vec are at or near zero. - */ -static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Outer product of two 4-D vectors - */ -static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Linear interpolation between two 4-D vectors - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Spherical linear interpolation between two 4-D vectors - * NOTE: - * The result is unpredictable if the vectors point in opposite directions. - * Does not clamp t between 0 and 1. - */ -static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ); - -/* - * Conditionally select between two 4-D vectors - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ); - -/* - * Store four 4-D vectors as half-floats - */ -static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 4-D vector - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV4Print( const VmathVector4 *vec ); - -/* - * Print a 4-D vector and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ); - -#endif - -/* - * Copy a 3-D point - */ -static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Construct a 3-D point from x, y, and z elements - */ -static inline void vmathP3MakeFromElems( VmathPoint3 *result, float x, float y, float z ); - -/* - * Copy elements from a 3-D vector into a 3-D point - */ -static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ); - -/* - * Set all elements of a 3-D point to the same scalar value - */ -static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ); - -/* - * Set vector float data in a 3-D point - */ -static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 3-D point - */ -static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ); - -/* - * Set the x element of a 3-D point - */ -static inline void vmathP3SetX( VmathPoint3 *result, float x ); - -/* - * Set the y element of a 3-D point - */ -static inline void vmathP3SetY( VmathPoint3 *result, float y ); - -/* - * Set the z element of a 3-D point - */ -static inline void vmathP3SetZ( VmathPoint3 *result, float z ); - -/* - * Get the x element of a 3-D point - */ -static inline float vmathP3GetX( const VmathPoint3 *pnt ); - -/* - * Get the y element of a 3-D point - */ -static inline float vmathP3GetY( const VmathPoint3 *pnt ); - -/* - * Get the z element of a 3-D point - */ -static inline float vmathP3GetZ( const VmathPoint3 *pnt ); - -/* - * Set an x, y, or z element of a 3-D point by index - */ -static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ); - -/* - * Get an x, y, or z element of a 3-D point by index - */ -static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ); - -/* - * Subtract a 3-D point from another 3-D point - */ -static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Add a 3-D point to a 3-D vector - */ -static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); - -/* - * Subtract a 3-D vector from a 3-D point - */ -static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); - -/* - * Multiply two 3-D points per element - */ -static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Divide two 3-D points per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Compute the reciprocal of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the square root of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the reciprocal square root of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the absolute value of a 3-D point per element - */ -static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Copy sign from one 3-D point to another, per element - */ -static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Maximum of two 3-D points per element - */ -static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Minimum of two 3-D points per element - */ -static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Maximum element of a 3-D point - */ -static inline float vmathP3MaxElem( const VmathPoint3 *pnt ); - -/* - * Minimum element of a 3-D point - */ -static inline float vmathP3MinElem( const VmathPoint3 *pnt ); - -/* - * Compute the sum of all elements of a 3-D point - */ -static inline float vmathP3Sum( const VmathPoint3 *pnt ); - -/* - * Apply uniform scale to a 3-D point - */ -static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ); - -/* - * Apply non-uniform scale to a 3-D point - */ -static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ); - -/* - * Scalar projection of a 3-D point on a unit-length 3-D vector - */ -static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ); - -/* - * Compute the square of the distance of a 3-D point from the coordinate-system origin - */ -static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ); - -/* - * Compute the distance of a 3-D point from the coordinate-system origin - */ -static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ); - -/* - * Compute the square of the distance between two 3-D points - */ -static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Compute the distance between two 3-D points - */ -static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Linear interpolation between two 3-D points - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Conditionally select between two 3-D points - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ); - -/* - * Store x, y, and z elements of a 3-D point in the first three words of a quadword. - * The value of the fourth word (the word with the highest address) remains unchanged - */ -static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ); - -/* - * Load four three-float 3-D points, stored in three quadwords - */ -static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ); - -/* - * Store four 3-D points in three quadwords - */ -static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ); - -/* - * Store eight 3-D points as half-floats - */ -static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3-D point - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathP3Print( const VmathPoint3 *pnt ); - -/* - * Print a 3-D point and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ); - -#endif - -/* - * Copy a quaternion - */ -static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ); - -/* - * Construct a quaternion from x, y, z, and w elements - */ -static inline void vmathQMakeFromElems( VmathQuat *result, float x, float y, float z, float w ); - -/* - * Construct a quaternion from a 3-D vector and a scalar - */ -static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float w ); - -/* - * Copy elements from a 4-D vector into a quaternion - */ -static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ); - -/* - * Convert a rotation matrix to a unit-length quaternion - */ -static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *rotMat ); - -/* - * Set all elements of a quaternion to the same scalar value - */ -static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ); - -/* - * Set vector float data in a quaternion - */ -static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ); - -/* - * Get vector float data from a quaternion - */ -static inline vec_float4 vmathQGet128( const VmathQuat *quat ); - -/* - * Set the x, y, and z elements of a quaternion - * NOTE: - * This function does not change the w element. - */ -static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ); - -/* - * Get the x, y, and z elements of a quaternion - */ -static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ); - -/* - * Set the x element of a quaternion - */ -static inline void vmathQSetX( VmathQuat *result, float x ); - -/* - * Set the y element of a quaternion - */ -static inline void vmathQSetY( VmathQuat *result, float y ); - -/* - * Set the z element of a quaternion - */ -static inline void vmathQSetZ( VmathQuat *result, float z ); - -/* - * Set the w element of a quaternion - */ -static inline void vmathQSetW( VmathQuat *result, float w ); - -/* - * Get the x element of a quaternion - */ -static inline float vmathQGetX( const VmathQuat *quat ); - -/* - * Get the y element of a quaternion - */ -static inline float vmathQGetY( const VmathQuat *quat ); - -/* - * Get the z element of a quaternion - */ -static inline float vmathQGetZ( const VmathQuat *quat ); - -/* - * Get the w element of a quaternion - */ -static inline float vmathQGetW( const VmathQuat *quat ); - -/* - * Set an x, y, z, or w element of a quaternion by index - */ -static inline void vmathQSetElem( VmathQuat *result, int idx, float value ); - -/* - * Get an x, y, z, or w element of a quaternion by index - */ -static inline float vmathQGetElem( const VmathQuat *quat, int idx ); - -/* - * Add two quaternions - */ -static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Subtract a quaternion from another quaternion - */ -static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Multiply two quaternions - */ -static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Multiply a quaternion by a scalar - */ -static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ); - -/* - * Divide a quaternion by a scalar - */ -static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ); - -/* - * Negate all elements of a quaternion - */ -static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ); - -/* - * Construct an identity quaternion - */ -static inline void vmathQMakeIdentity( VmathQuat *result ); - -/* - * Construct a quaternion to rotate between two unit-length 3-D vectors - * NOTE: - * The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. - */ -static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); - -/* - * Construct a quaternion to rotate around a unit-length 3-D vector - */ -static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a quaternion to rotate around the x axis - */ -static inline void vmathQMakeRotationX( VmathQuat *result, float radians ); - -/* - * Construct a quaternion to rotate around the y axis - */ -static inline void vmathQMakeRotationY( VmathQuat *result, float radians ); - -/* - * Construct a quaternion to rotate around the z axis - */ -static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ); - -/* - * Compute the conjugate of a quaternion - */ -static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ); - -/* - * Use a unit-length quaternion to rotate a 3-D vector - */ -static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *unitQuat, const VmathVector3 *vec ); - -/* - * Compute the dot product of two quaternions - */ -static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Compute the norm of a quaternion - */ -static inline float vmathQNorm( const VmathQuat *quat ); - -/* - * Compute the length of a quaternion - */ -static inline float vmathQLength( const VmathQuat *quat ); - -/* - * Normalize a quaternion - * NOTE: - * The result is unpredictable when all elements of quat are at or near zero. - */ -static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ); - -/* - * Linear interpolation between two quaternions - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Spherical linear interpolation between two quaternions - * NOTE: - * Interpolates along the shortest path between orientations. - * Does not clamp t between 0 and 1. - */ -static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ); - -/* - * Spherical quadrangle interpolation - */ -static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ); - -/* - * Conditionally select between two quaternions - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a quaternion - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathQPrint( const VmathQuat *quat ); - -/* - * Print a quaternion and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathQPrints( const VmathQuat *quat, const char *name ); - -#endif - -/* - * Copy a 3x3 matrix - */ -static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Construct a 3x3 matrix containing the specified columns - */ -static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2 ); - -/* - * Construct a 3x3 rotation matrix from a unit-length quaternion - */ -static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); - -/* - * Set all elements of a 3x3 matrix to the same scalar value - */ -static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ); - -/* - * Set column 0 of a 3x3 matrix - */ -static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *col0 ); - -/* - * Set column 1 of a 3x3 matrix - */ -static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *col1 ); - -/* - * Set column 2 of a 3x3 matrix - */ -static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *col2 ); - -/* - * Get column 0 of a 3x3 matrix - */ -static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Get column 1 of a 3x3 matrix - */ -static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Get column 2 of a 3x3 matrix - */ -static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Set the column of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ); - -/* - * Set the row of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ); - -/* - * Get the column of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ); - -/* - * Get the row of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ); - -/* - * Set the element of a 3x3 matrix referred to by column and row indices - */ -static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ); - -/* - * Get the element of a 3x3 matrix referred to by column and row indices - */ -static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ); - -/* - * Add two 3x3 matrices - */ -static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Subtract a 3x3 matrix from another 3x3 matrix - */ -static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Negate all elements of a 3x3 matrix - */ -static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Multiply a 3x3 matrix by a scalar - */ -static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ); - -/* - * Multiply a 3x3 matrix by a 3-D vector - */ -static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ); - -/* - * Multiply two 3x3 matrices - */ -static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Construct an identity 3x3 matrix - */ -static inline void vmathM3MakeIdentity( VmathMatrix3 *result ); - -/* - * Construct a 3x3 matrix to rotate around the x axis - */ -static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the y axis - */ -static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the z axis - */ -static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the x, y, and z axes - */ -static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 3x3 matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 3x3 matrix to perform scaling - */ -static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ); - -/* - * Append (post-multiply) a scale transformation to a 3x3 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 3x3 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ); - -/* - * Multiply two 3x3 matrices per element - */ -static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Compute the absolute value of a 3x3 matrix per element - */ -static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Transpose of a 3x3 matrix - */ -static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Compute the inverse of a 3x3 matrix - * NOTE: - * Result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Determinant of a 3x3 matrix - */ -static inline float vmathM3Determinant( const VmathMatrix3 *mat ); - -/* - * Conditionally select between two 3x3 matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3x3 matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM3Print( const VmathMatrix3 *mat ); - -/* - * Print a 3x3 matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ); - -#endif - -/* - * Copy a 4x4 matrix - */ -static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Construct a 4x4 matrix containing the specified columns - */ -static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *col0, const VmathVector4 *col1, const VmathVector4 *col2, const VmathVector4 *col3 ); - -/* - * Construct a 4x4 matrix from a 3x4 transformation matrix - */ -static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ); - -/* - * Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector - */ -static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ); - -/* - * Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector - */ -static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); - -/* - * Set all elements of a 4x4 matrix to the same scalar value - */ -static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ); - -/* - * Set the upper-left 3x3 submatrix - * NOTE: - * This function does not change the bottom row elements. - */ -static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ); - -/* - * Get the upper-left 3x3 submatrix of a 4x4 matrix - */ -static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ); - -/* - * Set translation component - * NOTE: - * This function does not change the bottom row elements. - */ -static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); - -/* - * Get the translation component of a 4x4 matrix - */ -static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ); - -/* - * Set column 0 of a 4x4 matrix - */ -static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *col0 ); - -/* - * Set column 1 of a 4x4 matrix - */ -static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *col1 ); - -/* - * Set column 2 of a 4x4 matrix - */ -static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *col2 ); - -/* - * Set column 3 of a 4x4 matrix - */ -static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *col3 ); - -/* - * Get column 0 of a 4x4 matrix - */ -static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 1 of a 4x4 matrix - */ -static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 2 of a 4x4 matrix - */ -static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 3 of a 4x4 matrix - */ -static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Set the column of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ); - -/* - * Set the row of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ); - -/* - * Get the column of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ); - -/* - * Get the row of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ); - -/* - * Set the element of a 4x4 matrix referred to by column and row indices - */ -static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ); - -/* - * Get the element of a 4x4 matrix referred to by column and row indices - */ -static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ); - -/* - * Add two 4x4 matrices - */ -static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Subtract a 4x4 matrix from another 4x4 matrix - */ -static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Negate all elements of a 4x4 matrix - */ -static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Multiply a 4x4 matrix by a scalar - */ -static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ); - -/* - * Multiply a 4x4 matrix by a 4-D vector - */ -static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ); - -/* - * Multiply a 4x4 matrix by a 3-D vector - */ -static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ); - -/* - * Multiply a 4x4 matrix by a 3-D point - */ -static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ); - -/* - * Multiply two 4x4 matrices - */ -static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Multiply a 4x4 matrix by a 3x4 transformation matrix - */ -static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm ); - -/* - * Construct an identity 4x4 matrix - */ -static inline void vmathM4MakeIdentity( VmathMatrix4 *result ); - -/* - * Construct a 4x4 matrix to rotate around the x axis - */ -static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the y axis - */ -static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the z axis - */ -static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the x, y, and z axes - */ -static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 4x4 matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 4x4 matrix to perform scaling - */ -static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ); - -/* - * Construct a 4x4 matrix to perform translation - */ -static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); - -/* - * Construct viewing matrix based on eye position, position looked at, and up direction - */ -static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ); - -/* - * Construct a perspective projection matrix - */ -static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ); - -/* - * Construct a perspective projection matrix based on frustum - */ -static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); - -/* - * Construct an orthographic projection matrix - */ -static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); - -/* - * Append (post-multiply) a scale transformation to a 4x4 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 4x4 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ); - -/* - * Multiply two 4x4 matrices per element - */ -static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Compute the absolute value of a 4x4 matrix per element - */ -static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Transpose of a 4x4 matrix - */ -static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix - * NOTE: - * Result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. - */ -static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Determinant of a 4x4 matrix - */ -static inline float vmathM4Determinant( const VmathMatrix4 *mat ); - -/* - * Conditionally select between two 4x4 matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 4x4 matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM4Print( const VmathMatrix4 *mat ); - -/* - * Print a 4x4 matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ); - -#endif - -/* - * Copy a 3x4 transformation matrix - */ -static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Construct a 3x4 transformation matrix containing the specified columns - */ -static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2, const VmathVector3 *col3 ); - -/* - * Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector - */ -static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ); - -/* - * Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector - */ -static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); - -/* - * Set all elements of a 3x4 transformation matrix to the same scalar value - */ -static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ); - -/* - * Set the upper-left 3x3 submatrix - */ -static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *mat3 ); - -/* - * Get the upper-left 3x3 submatrix of a 3x4 transformation matrix - */ -static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ); - -/* - * Set translation component - */ -static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); - -/* - * Get the translation component of a 3x4 transformation matrix - */ -static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Set column 0 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *col0 ); - -/* - * Set column 1 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *col1 ); - -/* - * Set column 2 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *col2 ); - -/* - * Set column 3 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *col3 ); - -/* - * Get column 0 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 1 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 2 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 3 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Set the column of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ); - -/* - * Set the row of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ); - -/* - * Get the column of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ); - -/* - * Get the row of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ); - -/* - * Set the element of a 3x4 transformation matrix referred to by column and row indices - */ -static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ); - -/* - * Get the element of a 3x4 transformation matrix referred to by column and row indices - */ -static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ); - -/* - * Multiply a 3x4 transformation matrix by a 3-D vector - */ -static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ); - -/* - * Multiply a 3x4 transformation matrix by a 3-D point - */ -static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ); - -/* - * Multiply two 3x4 transformation matrices - */ -static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); - -/* - * Construct an identity 3x4 transformation matrix - */ -static inline void vmathT3MakeIdentity( VmathTransform3 *result ); - -/* - * Construct a 3x4 transformation matrix to rotate around the x axis - */ -static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the y axis - */ -static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the z axis - */ -static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the x, y, and z axes - */ -static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 3x4 transformation matrix to perform scaling - */ -static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ); - -/* - * Construct a 3x4 transformation matrix to perform translation - */ -static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); - -/* - * Append (post-multiply) a scale transformation to a 3x4 transformation matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ); - -/* - * Multiply two 3x4 transformation matrices per element - */ -static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); - -/* - * Compute the absolute value of a 3x4 transformation matrix per element - */ -static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Inverse of a 3x4 transformation matrix - * NOTE: - * Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. - */ -static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. - */ -static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Conditionally select between two 3x4 transformation matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - * However, the transfer of select1 to a VMX register may use more processing time than a branch. - */ -static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3x4 transformation matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathT3Print( const VmathTransform3 *tfrm ); - -/* - * Print a 3x4 transformation matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ); - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#include "vec_aos.h" -#include "quat_aos.h" -#include "mat_aos.h" - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_AOS_C_PPU_H +#define _VECTORMATH_AOS_C_PPU_H + +#include +#include +#include +#include "vec_types.h" + +#ifdef _VECTORMATH_DEBUG +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef _VECTORMATH_AOS_C_TYPES_H +#define _VECTORMATH_AOS_C_TYPES_H + +/* A 3-D vector in array-of-structures format + */ +typedef struct _VmathVector3 +{ + vec_float4 vec128; +} VmathVector3; + +/* A 4-D vector in array-of-structures format + */ +typedef struct _VmathVector4 +{ + vec_float4 vec128; +} VmathVector4; + +/* A 3-D point in array-of-structures format + */ +typedef struct _VmathPoint3 +{ + vec_float4 vec128; +} VmathPoint3; + +/* A quaternion in array-of-structures format + */ +typedef struct _VmathQuat +{ + vec_float4 vec128; +} VmathQuat; + +/* A 3x3 matrix in array-of-structures format + */ +typedef struct _VmathMatrix3 +{ + VmathVector3 col0; + VmathVector3 col1; + VmathVector3 col2; +} VmathMatrix3; + +/* A 4x4 matrix in array-of-structures format + */ +typedef struct _VmathMatrix4 +{ + VmathVector4 col0; + VmathVector4 col1; + VmathVector4 col2; + VmathVector4 col3; +} VmathMatrix4; + +/* A 3x4 transformation matrix in array-of-structures format + */ +typedef struct _VmathTransform3 +{ + VmathVector3 col0; + VmathVector3 col1; + VmathVector3 col2; + VmathVector3 col3; +} VmathTransform3; + +#endif + +/* + * Copy a 3-D vector + */ +static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Construct a 3-D vector from x, y, and z elements + */ +static inline void vmathV3MakeFromElems( VmathVector3 *result, float x, float y, float z ); + +/* + * Copy elements from a 3-D point into a 3-D vector + */ +static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ); + +/* + * Set all elements of a 3-D vector to the same scalar value + */ +static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ); + +/* + * Set vector float data in a 3-D vector + */ +static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 3-D vector + */ +static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ); + +/* + * Set the x element of a 3-D vector + */ +static inline void vmathV3SetX( VmathVector3 *result, float x ); + +/* + * Set the y element of a 3-D vector + */ +static inline void vmathV3SetY( VmathVector3 *result, float y ); + +/* + * Set the z element of a 3-D vector + */ +static inline void vmathV3SetZ( VmathVector3 *result, float z ); + +/* + * Get the x element of a 3-D vector + */ +static inline float vmathV3GetX( const VmathVector3 *vec ); + +/* + * Get the y element of a 3-D vector + */ +static inline float vmathV3GetY( const VmathVector3 *vec ); + +/* + * Get the z element of a 3-D vector + */ +static inline float vmathV3GetZ( const VmathVector3 *vec ); + +/* + * Set an x, y, or z element of a 3-D vector by index + */ +static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ); + +/* + * Get an x, y, or z element of a 3-D vector by index + */ +static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ); + +/* + * Add two 3-D vectors + */ +static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Subtract a 3-D vector from another 3-D vector + */ +static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Add a 3-D vector to a 3-D point + */ +static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt ); + +/* + * Multiply a 3-D vector by a scalar + */ +static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ); + +/* + * Divide a 3-D vector by a scalar + */ +static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ); + +/* + * Negate all elements of a 3-D vector + */ +static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Construct x axis + */ +static inline void vmathV3MakeXAxis( VmathVector3 *result ); + +/* + * Construct y axis + */ +static inline void vmathV3MakeYAxis( VmathVector3 *result ); + +/* + * Construct z axis + */ +static inline void vmathV3MakeZAxis( VmathVector3 *result ); + +/* + * Multiply two 3-D vectors per element + */ +static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Divide two 3-D vectors per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Compute the reciprocal of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the square root of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the reciprocal square root of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the absolute value of a 3-D vector per element + */ +static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Copy sign from one 3-D vector to another, per element + */ +static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Maximum of two 3-D vectors per element + */ +static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Minimum of two 3-D vectors per element + */ +static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Maximum element of a 3-D vector + */ +static inline float vmathV3MaxElem( const VmathVector3 *vec ); + +/* + * Minimum element of a 3-D vector + */ +static inline float vmathV3MinElem( const VmathVector3 *vec ); + +/* + * Compute the sum of all elements of a 3-D vector + */ +static inline float vmathV3Sum( const VmathVector3 *vec ); + +/* + * Compute the dot product of two 3-D vectors + */ +static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Compute the square of the length of a 3-D vector + */ +static inline float vmathV3LengthSqr( const VmathVector3 *vec ); + +/* + * Compute the length of a 3-D vector + */ +static inline float vmathV3Length( const VmathVector3 *vec ); + +/* + * Normalize a 3-D vector + * NOTE: + * The result is unpredictable when all elements of vec are at or near zero. + */ +static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute cross product of two 3-D vectors + */ +static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Outer product of two 3-D vectors + */ +static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Pre-multiply a row vector by a 3x3 matrix + * NOTE: + * Slower than column post-multiply. + */ +static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); + +/* + * Cross-product matrix of a 3-D vector + */ +static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ); + +/* + * Create cross-product matrix and multiply + * NOTE: + * Faster than separately creating a cross-product matrix and multiplying. + */ +static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); + +/* + * Linear interpolation between two 3-D vectors + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Spherical linear interpolation between two 3-D vectors + * NOTE: + * The result is unpredictable if the vectors point in opposite directions. + * Does not clamp t between 0 and 1. + */ +static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); + +/* + * Conditionally select between two 3-D vectors + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ); + +/* + * Store x, y, and z elements of a 3-D vector in the first three words of a quadword. + * The value of the fourth word (the word with the highest address) remains unchanged + */ +static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ); + +/* + * Load four three-float 3-D vectors, stored in three quadwords + */ +static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ); + +/* + * Store four 3-D vectors in three quadwords + */ +static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ); + +/* + * Store eight 3-D vectors as half-floats + */ +static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3-D vector + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV3Print( const VmathVector3 *vec ); + +/* + * Print a 3-D vector and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ); + +#endif + +/* + * Copy a 4-D vector + */ +static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Construct a 4-D vector from x, y, z, and w elements + */ +static inline void vmathV4MakeFromElems( VmathVector4 *result, float x, float y, float z, float w ); + +/* + * Construct a 4-D vector from a 3-D vector and a scalar + */ +static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float w ); + +/* + * Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 + */ +static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ); + +/* + * Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 + */ +static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ); + +/* + * Copy elements from a quaternion into a 4-D vector + */ +static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ); + +/* + * Set all elements of a 4-D vector to the same scalar value + */ +static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ); + +/* + * Set vector float data in a 4-D vector + */ +static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 4-D vector + */ +static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ); + +/* + * Set the x, y, and z elements of a 4-D vector + * NOTE: + * This function does not change the w element. + */ +static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ); + +/* + * Get the x, y, and z elements of a 4-D vector + */ +static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ); + +/* + * Set the x element of a 4-D vector + */ +static inline void vmathV4SetX( VmathVector4 *result, float x ); + +/* + * Set the y element of a 4-D vector + */ +static inline void vmathV4SetY( VmathVector4 *result, float y ); + +/* + * Set the z element of a 4-D vector + */ +static inline void vmathV4SetZ( VmathVector4 *result, float z ); + +/* + * Set the w element of a 4-D vector + */ +static inline void vmathV4SetW( VmathVector4 *result, float w ); + +/* + * Get the x element of a 4-D vector + */ +static inline float vmathV4GetX( const VmathVector4 *vec ); + +/* + * Get the y element of a 4-D vector + */ +static inline float vmathV4GetY( const VmathVector4 *vec ); + +/* + * Get the z element of a 4-D vector + */ +static inline float vmathV4GetZ( const VmathVector4 *vec ); + +/* + * Get the w element of a 4-D vector + */ +static inline float vmathV4GetW( const VmathVector4 *vec ); + +/* + * Set an x, y, z, or w element of a 4-D vector by index + */ +static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ); + +/* + * Get an x, y, z, or w element of a 4-D vector by index + */ +static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ); + +/* + * Add two 4-D vectors + */ +static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Subtract a 4-D vector from another 4-D vector + */ +static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Multiply a 4-D vector by a scalar + */ +static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ); + +/* + * Divide a 4-D vector by a scalar + */ +static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ); + +/* + * Negate all elements of a 4-D vector + */ +static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Construct x axis + */ +static inline void vmathV4MakeXAxis( VmathVector4 *result ); + +/* + * Construct y axis + */ +static inline void vmathV4MakeYAxis( VmathVector4 *result ); + +/* + * Construct z axis + */ +static inline void vmathV4MakeZAxis( VmathVector4 *result ); + +/* + * Construct w axis + */ +static inline void vmathV4MakeWAxis( VmathVector4 *result ); + +/* + * Multiply two 4-D vectors per element + */ +static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Divide two 4-D vectors per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Compute the reciprocal of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the square root of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the reciprocal square root of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the absolute value of a 4-D vector per element + */ +static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Copy sign from one 4-D vector to another, per element + */ +static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Maximum of two 4-D vectors per element + */ +static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Minimum of two 4-D vectors per element + */ +static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Maximum element of a 4-D vector + */ +static inline float vmathV4MaxElem( const VmathVector4 *vec ); + +/* + * Minimum element of a 4-D vector + */ +static inline float vmathV4MinElem( const VmathVector4 *vec ); + +/* + * Compute the sum of all elements of a 4-D vector + */ +static inline float vmathV4Sum( const VmathVector4 *vec ); + +/* + * Compute the dot product of two 4-D vectors + */ +static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Compute the square of the length of a 4-D vector + */ +static inline float vmathV4LengthSqr( const VmathVector4 *vec ); + +/* + * Compute the length of a 4-D vector + */ +static inline float vmathV4Length( const VmathVector4 *vec ); + +/* + * Normalize a 4-D vector + * NOTE: + * The result is unpredictable when all elements of vec are at or near zero. + */ +static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Outer product of two 4-D vectors + */ +static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Linear interpolation between two 4-D vectors + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Spherical linear interpolation between two 4-D vectors + * NOTE: + * The result is unpredictable if the vectors point in opposite directions. + * Does not clamp t between 0 and 1. + */ +static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ); + +/* + * Conditionally select between two 4-D vectors + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ); + +/* + * Store four 4-D vectors as half-floats + */ +static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 4-D vector + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV4Print( const VmathVector4 *vec ); + +/* + * Print a 4-D vector and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ); + +#endif + +/* + * Copy a 3-D point + */ +static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Construct a 3-D point from x, y, and z elements + */ +static inline void vmathP3MakeFromElems( VmathPoint3 *result, float x, float y, float z ); + +/* + * Copy elements from a 3-D vector into a 3-D point + */ +static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ); + +/* + * Set all elements of a 3-D point to the same scalar value + */ +static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ); + +/* + * Set vector float data in a 3-D point + */ +static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 3-D point + */ +static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ); + +/* + * Set the x element of a 3-D point + */ +static inline void vmathP3SetX( VmathPoint3 *result, float x ); + +/* + * Set the y element of a 3-D point + */ +static inline void vmathP3SetY( VmathPoint3 *result, float y ); + +/* + * Set the z element of a 3-D point + */ +static inline void vmathP3SetZ( VmathPoint3 *result, float z ); + +/* + * Get the x element of a 3-D point + */ +static inline float vmathP3GetX( const VmathPoint3 *pnt ); + +/* + * Get the y element of a 3-D point + */ +static inline float vmathP3GetY( const VmathPoint3 *pnt ); + +/* + * Get the z element of a 3-D point + */ +static inline float vmathP3GetZ( const VmathPoint3 *pnt ); + +/* + * Set an x, y, or z element of a 3-D point by index + */ +static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ); + +/* + * Get an x, y, or z element of a 3-D point by index + */ +static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ); + +/* + * Subtract a 3-D point from another 3-D point + */ +static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Add a 3-D point to a 3-D vector + */ +static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); + +/* + * Subtract a 3-D vector from a 3-D point + */ +static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); + +/* + * Multiply two 3-D points per element + */ +static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Divide two 3-D points per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Compute the reciprocal of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the square root of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the reciprocal square root of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the absolute value of a 3-D point per element + */ +static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Copy sign from one 3-D point to another, per element + */ +static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Maximum of two 3-D points per element + */ +static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Minimum of two 3-D points per element + */ +static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Maximum element of a 3-D point + */ +static inline float vmathP3MaxElem( const VmathPoint3 *pnt ); + +/* + * Minimum element of a 3-D point + */ +static inline float vmathP3MinElem( const VmathPoint3 *pnt ); + +/* + * Compute the sum of all elements of a 3-D point + */ +static inline float vmathP3Sum( const VmathPoint3 *pnt ); + +/* + * Apply uniform scale to a 3-D point + */ +static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ); + +/* + * Apply non-uniform scale to a 3-D point + */ +static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ); + +/* + * Scalar projection of a 3-D point on a unit-length 3-D vector + */ +static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ); + +/* + * Compute the square of the distance of a 3-D point from the coordinate-system origin + */ +static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ); + +/* + * Compute the distance of a 3-D point from the coordinate-system origin + */ +static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ); + +/* + * Compute the square of the distance between two 3-D points + */ +static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Compute the distance between two 3-D points + */ +static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Linear interpolation between two 3-D points + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Conditionally select between two 3-D points + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ); + +/* + * Store x, y, and z elements of a 3-D point in the first three words of a quadword. + * The value of the fourth word (the word with the highest address) remains unchanged + */ +static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ); + +/* + * Load four three-float 3-D points, stored in three quadwords + */ +static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ); + +/* + * Store four 3-D points in three quadwords + */ +static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ); + +/* + * Store eight 3-D points as half-floats + */ +static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3-D point + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathP3Print( const VmathPoint3 *pnt ); + +/* + * Print a 3-D point and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ); + +#endif + +/* + * Copy a quaternion + */ +static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ); + +/* + * Construct a quaternion from x, y, z, and w elements + */ +static inline void vmathQMakeFromElems( VmathQuat *result, float x, float y, float z, float w ); + +/* + * Construct a quaternion from a 3-D vector and a scalar + */ +static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float w ); + +/* + * Copy elements from a 4-D vector into a quaternion + */ +static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ); + +/* + * Convert a rotation matrix to a unit-length quaternion + */ +static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *rotMat ); + +/* + * Set all elements of a quaternion to the same scalar value + */ +static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ); + +/* + * Set vector float data in a quaternion + */ +static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ); + +/* + * Get vector float data from a quaternion + */ +static inline vec_float4 vmathQGet128( const VmathQuat *quat ); + +/* + * Set the x, y, and z elements of a quaternion + * NOTE: + * This function does not change the w element. + */ +static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ); + +/* + * Get the x, y, and z elements of a quaternion + */ +static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ); + +/* + * Set the x element of a quaternion + */ +static inline void vmathQSetX( VmathQuat *result, float x ); + +/* + * Set the y element of a quaternion + */ +static inline void vmathQSetY( VmathQuat *result, float y ); + +/* + * Set the z element of a quaternion + */ +static inline void vmathQSetZ( VmathQuat *result, float z ); + +/* + * Set the w element of a quaternion + */ +static inline void vmathQSetW( VmathQuat *result, float w ); + +/* + * Get the x element of a quaternion + */ +static inline float vmathQGetX( const VmathQuat *quat ); + +/* + * Get the y element of a quaternion + */ +static inline float vmathQGetY( const VmathQuat *quat ); + +/* + * Get the z element of a quaternion + */ +static inline float vmathQGetZ( const VmathQuat *quat ); + +/* + * Get the w element of a quaternion + */ +static inline float vmathQGetW( const VmathQuat *quat ); + +/* + * Set an x, y, z, or w element of a quaternion by index + */ +static inline void vmathQSetElem( VmathQuat *result, int idx, float value ); + +/* + * Get an x, y, z, or w element of a quaternion by index + */ +static inline float vmathQGetElem( const VmathQuat *quat, int idx ); + +/* + * Add two quaternions + */ +static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Subtract a quaternion from another quaternion + */ +static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Multiply two quaternions + */ +static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Multiply a quaternion by a scalar + */ +static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ); + +/* + * Divide a quaternion by a scalar + */ +static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ); + +/* + * Negate all elements of a quaternion + */ +static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ); + +/* + * Construct an identity quaternion + */ +static inline void vmathQMakeIdentity( VmathQuat *result ); + +/* + * Construct a quaternion to rotate between two unit-length 3-D vectors + * NOTE: + * The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. + */ +static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); + +/* + * Construct a quaternion to rotate around a unit-length 3-D vector + */ +static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a quaternion to rotate around the x axis + */ +static inline void vmathQMakeRotationX( VmathQuat *result, float radians ); + +/* + * Construct a quaternion to rotate around the y axis + */ +static inline void vmathQMakeRotationY( VmathQuat *result, float radians ); + +/* + * Construct a quaternion to rotate around the z axis + */ +static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ); + +/* + * Compute the conjugate of a quaternion + */ +static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ); + +/* + * Use a unit-length quaternion to rotate a 3-D vector + */ +static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *unitQuat, const VmathVector3 *vec ); + +/* + * Compute the dot product of two quaternions + */ +static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Compute the norm of a quaternion + */ +static inline float vmathQNorm( const VmathQuat *quat ); + +/* + * Compute the length of a quaternion + */ +static inline float vmathQLength( const VmathQuat *quat ); + +/* + * Normalize a quaternion + * NOTE: + * The result is unpredictable when all elements of quat are at or near zero. + */ +static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ); + +/* + * Linear interpolation between two quaternions + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Spherical linear interpolation between two quaternions + * NOTE: + * Interpolates along the shortest path between orientations. + * Does not clamp t between 0 and 1. + */ +static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ); + +/* + * Spherical quadrangle interpolation + */ +static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ); + +/* + * Conditionally select between two quaternions + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a quaternion + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathQPrint( const VmathQuat *quat ); + +/* + * Print a quaternion and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathQPrints( const VmathQuat *quat, const char *name ); + +#endif + +/* + * Copy a 3x3 matrix + */ +static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Construct a 3x3 matrix containing the specified columns + */ +static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2 ); + +/* + * Construct a 3x3 rotation matrix from a unit-length quaternion + */ +static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); + +/* + * Set all elements of a 3x3 matrix to the same scalar value + */ +static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ); + +/* + * Set column 0 of a 3x3 matrix + */ +static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *col0 ); + +/* + * Set column 1 of a 3x3 matrix + */ +static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *col1 ); + +/* + * Set column 2 of a 3x3 matrix + */ +static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *col2 ); + +/* + * Get column 0 of a 3x3 matrix + */ +static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Get column 1 of a 3x3 matrix + */ +static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Get column 2 of a 3x3 matrix + */ +static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Set the column of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ); + +/* + * Set the row of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ); + +/* + * Get the column of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ); + +/* + * Get the row of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ); + +/* + * Set the element of a 3x3 matrix referred to by column and row indices + */ +static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ); + +/* + * Get the element of a 3x3 matrix referred to by column and row indices + */ +static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ); + +/* + * Add two 3x3 matrices + */ +static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Subtract a 3x3 matrix from another 3x3 matrix + */ +static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Negate all elements of a 3x3 matrix + */ +static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Multiply a 3x3 matrix by a scalar + */ +static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ); + +/* + * Multiply a 3x3 matrix by a 3-D vector + */ +static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ); + +/* + * Multiply two 3x3 matrices + */ +static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Construct an identity 3x3 matrix + */ +static inline void vmathM3MakeIdentity( VmathMatrix3 *result ); + +/* + * Construct a 3x3 matrix to rotate around the x axis + */ +static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the y axis + */ +static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the z axis + */ +static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the x, y, and z axes + */ +static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 3x3 matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 3x3 matrix to perform scaling + */ +static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ); + +/* + * Append (post-multiply) a scale transformation to a 3x3 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 3x3 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ); + +/* + * Multiply two 3x3 matrices per element + */ +static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Compute the absolute value of a 3x3 matrix per element + */ +static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Transpose of a 3x3 matrix + */ +static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Compute the inverse of a 3x3 matrix + * NOTE: + * Result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Determinant of a 3x3 matrix + */ +static inline float vmathM3Determinant( const VmathMatrix3 *mat ); + +/* + * Conditionally select between two 3x3 matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3x3 matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM3Print( const VmathMatrix3 *mat ); + +/* + * Print a 3x3 matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ); + +#endif + +/* + * Copy a 4x4 matrix + */ +static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Construct a 4x4 matrix containing the specified columns + */ +static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *col0, const VmathVector4 *col1, const VmathVector4 *col2, const VmathVector4 *col3 ); + +/* + * Construct a 4x4 matrix from a 3x4 transformation matrix + */ +static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ); + +/* + * Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector + */ +static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ); + +/* + * Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector + */ +static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); + +/* + * Set all elements of a 4x4 matrix to the same scalar value + */ +static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ); + +/* + * Set the upper-left 3x3 submatrix + * NOTE: + * This function does not change the bottom row elements. + */ +static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ); + +/* + * Get the upper-left 3x3 submatrix of a 4x4 matrix + */ +static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ); + +/* + * Set translation component + * NOTE: + * This function does not change the bottom row elements. + */ +static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); + +/* + * Get the translation component of a 4x4 matrix + */ +static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ); + +/* + * Set column 0 of a 4x4 matrix + */ +static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *col0 ); + +/* + * Set column 1 of a 4x4 matrix + */ +static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *col1 ); + +/* + * Set column 2 of a 4x4 matrix + */ +static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *col2 ); + +/* + * Set column 3 of a 4x4 matrix + */ +static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *col3 ); + +/* + * Get column 0 of a 4x4 matrix + */ +static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 1 of a 4x4 matrix + */ +static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 2 of a 4x4 matrix + */ +static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 3 of a 4x4 matrix + */ +static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Set the column of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ); + +/* + * Set the row of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ); + +/* + * Get the column of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ); + +/* + * Get the row of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ); + +/* + * Set the element of a 4x4 matrix referred to by column and row indices + */ +static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ); + +/* + * Get the element of a 4x4 matrix referred to by column and row indices + */ +static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ); + +/* + * Add two 4x4 matrices + */ +static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Subtract a 4x4 matrix from another 4x4 matrix + */ +static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Negate all elements of a 4x4 matrix + */ +static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Multiply a 4x4 matrix by a scalar + */ +static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ); + +/* + * Multiply a 4x4 matrix by a 4-D vector + */ +static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ); + +/* + * Multiply a 4x4 matrix by a 3-D vector + */ +static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ); + +/* + * Multiply a 4x4 matrix by a 3-D point + */ +static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ); + +/* + * Multiply two 4x4 matrices + */ +static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Multiply a 4x4 matrix by a 3x4 transformation matrix + */ +static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm ); + +/* + * Construct an identity 4x4 matrix + */ +static inline void vmathM4MakeIdentity( VmathMatrix4 *result ); + +/* + * Construct a 4x4 matrix to rotate around the x axis + */ +static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the y axis + */ +static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the z axis + */ +static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the x, y, and z axes + */ +static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 4x4 matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 4x4 matrix to perform scaling + */ +static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ); + +/* + * Construct a 4x4 matrix to perform translation + */ +static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); + +/* + * Construct viewing matrix based on eye position, position looked at, and up direction + */ +static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ); + +/* + * Construct a perspective projection matrix + */ +static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ); + +/* + * Construct a perspective projection matrix based on frustum + */ +static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); + +/* + * Construct an orthographic projection matrix + */ +static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); + +/* + * Append (post-multiply) a scale transformation to a 4x4 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 4x4 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ); + +/* + * Multiply two 4x4 matrices per element + */ +static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Compute the absolute value of a 4x4 matrix per element + */ +static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Transpose of a 4x4 matrix + */ +static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix + * NOTE: + * Result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. + */ +static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Determinant of a 4x4 matrix + */ +static inline float vmathM4Determinant( const VmathMatrix4 *mat ); + +/* + * Conditionally select between two 4x4 matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 4x4 matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM4Print( const VmathMatrix4 *mat ); + +/* + * Print a 4x4 matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ); + +#endif + +/* + * Copy a 3x4 transformation matrix + */ +static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Construct a 3x4 transformation matrix containing the specified columns + */ +static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2, const VmathVector3 *col3 ); + +/* + * Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector + */ +static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ); + +/* + * Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector + */ +static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); + +/* + * Set all elements of a 3x4 transformation matrix to the same scalar value + */ +static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ); + +/* + * Set the upper-left 3x3 submatrix + */ +static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *mat3 ); + +/* + * Get the upper-left 3x3 submatrix of a 3x4 transformation matrix + */ +static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ); + +/* + * Set translation component + */ +static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); + +/* + * Get the translation component of a 3x4 transformation matrix + */ +static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Set column 0 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *col0 ); + +/* + * Set column 1 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *col1 ); + +/* + * Set column 2 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *col2 ); + +/* + * Set column 3 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *col3 ); + +/* + * Get column 0 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 1 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 2 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 3 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Set the column of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ); + +/* + * Set the row of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ); + +/* + * Get the column of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ); + +/* + * Get the row of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ); + +/* + * Set the element of a 3x4 transformation matrix referred to by column and row indices + */ +static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ); + +/* + * Get the element of a 3x4 transformation matrix referred to by column and row indices + */ +static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ); + +/* + * Multiply a 3x4 transformation matrix by a 3-D vector + */ +static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ); + +/* + * Multiply a 3x4 transformation matrix by a 3-D point + */ +static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ); + +/* + * Multiply two 3x4 transformation matrices + */ +static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); + +/* + * Construct an identity 3x4 transformation matrix + */ +static inline void vmathT3MakeIdentity( VmathTransform3 *result ); + +/* + * Construct a 3x4 transformation matrix to rotate around the x axis + */ +static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the y axis + */ +static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the z axis + */ +static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the x, y, and z axes + */ +static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 3x4 transformation matrix to perform scaling + */ +static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ); + +/* + * Construct a 3x4 transformation matrix to perform translation + */ +static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); + +/* + * Append (post-multiply) a scale transformation to a 3x4 transformation matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ); + +/* + * Multiply two 3x4 transformation matrices per element + */ +static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); + +/* + * Compute the absolute value of a 3x4 transformation matrix per element + */ +static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Inverse of a 3x4 transformation matrix + * NOTE: + * Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. + */ +static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. + */ +static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Conditionally select between two 3x4 transformation matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + * However, the transfer of select1 to a VMX register may use more processing time than a branch. + */ +static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3x4 transformation matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathT3Print( const VmathTransform3 *tfrm ); + +/* + * Print a 3x4 transformation matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ); + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#include "vec_aos.h" +#include "quat_aos.h" +#include "mat_aos.h" + +#endif diff --git a/common/vectormath/ppu/cpp/boolInVec.h b/common/vectormath/ppu/cpp/boolInVec.h index 8d116af2..d5882ec5 100644 --- a/common/vectormath/ppu/cpp/boolInVec.h +++ b/common/vectormath/ppu/cpp/boolInVec.h @@ -1,261 +1,261 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _BOOLINVEC_H -#define _BOOLINVEC_H - -#include -#include -#include -#undef bool - -namespace Vectormath { - -class floatInVec; - -//-------------------------------------------------------------------------------------------------- -// boolInVec class -// - -class boolInVec -{ - private: - vec_uint4 mData; - - inline boolInVec(vec_uint4 vec); - public: - inline boolInVec() {} - - // matches standard type conversions - // - inline boolInVec(floatInVec vec); - - // explicit cast from bool - // - explicit inline boolInVec(bool scalar); - -#ifdef _VECTORMATH_NO_SCALAR_CAST - // explicit cast to bool - // - inline bool getAsBool() const; -#else - // implicit cast to bool - // - inline operator bool() const; -#endif - - // get vector data - // bool value is splatted across all word slots of vector as 0 (false) or -1 (true) - // - inline vec_uint4 get128() const; - - // operators - // - inline const boolInVec operator ! () const; - inline boolInVec& operator = (boolInVec vec); - inline boolInVec& operator &= (boolInVec vec); - inline boolInVec& operator ^= (boolInVec vec); - inline boolInVec& operator |= (boolInVec vec); - - // friend functions - // - friend inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); -}; - -//-------------------------------------------------------------------------------------------------- -// boolInVec functions -// - -// operators -// -inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); - -// select between vec0 and vec1 using boolInVec. -// false selects vec0, true selects vec1 -// -inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); - -} // namespace Vectormath - -//-------------------------------------------------------------------------------------------------- -// boolInVec implementation -// - -#include "floatInVec.h" - -namespace Vectormath { - -inline -boolInVec::boolInVec(vec_uint4 vec) -{ - mData = vec; -} - -inline -boolInVec::boolInVec(floatInVec vec) -{ - *this = (vec != floatInVec(0.0f)); -} - -inline -boolInVec::boolInVec(bool scalar) -{ -#ifdef __GNUC__ - if (__builtin_constant_p(scalar)) - { - const unsigned int mask = -(int)scalar; - mData = (vec_uint4){mask, mask, mask, mask}; - } - else -#endif - { - unsigned int mask = -(int)scalar; - vec_uint4 vec = vec_ld(0, &mask); - mData = vec_splat(vec_perm(vec, vec, vec_lvsl(0, &mask)), 0); - } -} - -#ifdef _VECTORMATH_NO_SCALAR_CAST -inline -bool -boolInVec::getAsBool() const -#else -inline -boolInVec::operator bool() const -#endif -{ - return vec_all_gt(mData, ((vec_uint4){0,0,0,0})); -} - -inline -vec_uint4 -boolInVec::get128() const -{ - return mData; -} - -inline -const boolInVec -boolInVec::operator ! () const -{ - return boolInVec(vec_nor(mData, mData)); -} - -inline -boolInVec& -boolInVec::operator = (boolInVec vec) -{ - mData = vec.mData; - return *this; -} - -inline -boolInVec& -boolInVec::operator &= (boolInVec vec) -{ - *this = *this & vec; - return *this; -} - -inline -boolInVec& -boolInVec::operator ^= (boolInVec vec) -{ - *this = *this ^ vec; - return *this; -} - -inline -boolInVec& -boolInVec::operator |= (boolInVec vec) -{ - *this = *this | vec; - return *this; -} - -inline -const boolInVec -operator == (boolInVec vec0, boolInVec vec1) -{ - return boolInVec((vec_uint4)vec_cmpeq(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator != (boolInVec vec0, boolInVec vec1) -{ - return !(vec0 == vec1); -} - -inline -const boolInVec -operator & (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(vec_and(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator | (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(vec_or(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator ^ (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(vec_xor(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1) -{ - return boolInVec(vec_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); -} - -} // namespace Vectormath - -#endif // boolInVec_h +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BOOLINVEC_H +#define _BOOLINVEC_H + +#include +#include +#include +#undef bool + +namespace Vectormath { + +class floatInVec; + +//-------------------------------------------------------------------------------------------------- +// boolInVec class +// + +class boolInVec +{ + private: + vec_uint4 mData; + + inline boolInVec(vec_uint4 vec); + public: + inline boolInVec() {} + + // matches standard type conversions + // + inline boolInVec(floatInVec vec); + + // explicit cast from bool + // + explicit inline boolInVec(bool scalar); + +#ifdef _VECTORMATH_NO_SCALAR_CAST + // explicit cast to bool + // + inline bool getAsBool() const; +#else + // implicit cast to bool + // + inline operator bool() const; +#endif + + // get vector data + // bool value is splatted across all word slots of vector as 0 (false) or -1 (true) + // + inline vec_uint4 get128() const; + + // operators + // + inline const boolInVec operator ! () const; + inline boolInVec& operator = (boolInVec vec); + inline boolInVec& operator &= (boolInVec vec); + inline boolInVec& operator ^= (boolInVec vec); + inline boolInVec& operator |= (boolInVec vec); + + // friend functions + // + friend inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); +}; + +//-------------------------------------------------------------------------------------------------- +// boolInVec functions +// + +// operators +// +inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); + +// select between vec0 and vec1 using boolInVec. +// false selects vec0, true selects vec1 +// +inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); + +} // namespace Vectormath + +//-------------------------------------------------------------------------------------------------- +// boolInVec implementation +// + +#include "floatInVec.h" + +namespace Vectormath { + +inline +boolInVec::boolInVec(vec_uint4 vec) +{ + mData = vec; +} + +inline +boolInVec::boolInVec(floatInVec vec) +{ + *this = (vec != floatInVec(0.0f)); +} + +inline +boolInVec::boolInVec(bool scalar) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(scalar)) + { + const unsigned int mask = -(int)scalar; + mData = (vec_uint4){mask, mask, mask, mask}; + } + else +#endif + { + unsigned int mask = -(int)scalar; + vec_uint4 vec = vec_ld(0, &mask); + mData = vec_splat(vec_perm(vec, vec, vec_lvsl(0, &mask)), 0); + } +} + +#ifdef _VECTORMATH_NO_SCALAR_CAST +inline +bool +boolInVec::getAsBool() const +#else +inline +boolInVec::operator bool() const +#endif +{ + return vec_all_gt(mData, ((vec_uint4){0,0,0,0})); +} + +inline +vec_uint4 +boolInVec::get128() const +{ + return mData; +} + +inline +const boolInVec +boolInVec::operator ! () const +{ + return boolInVec(vec_nor(mData, mData)); +} + +inline +boolInVec& +boolInVec::operator = (boolInVec vec) +{ + mData = vec.mData; + return *this; +} + +inline +boolInVec& +boolInVec::operator &= (boolInVec vec) +{ + *this = *this & vec; + return *this; +} + +inline +boolInVec& +boolInVec::operator ^= (boolInVec vec) +{ + *this = *this ^ vec; + return *this; +} + +inline +boolInVec& +boolInVec::operator |= (boolInVec vec) +{ + *this = *this | vec; + return *this; +} + +inline +const boolInVec +operator == (boolInVec vec0, boolInVec vec1) +{ + return boolInVec((vec_uint4)vec_cmpeq(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator != (boolInVec vec0, boolInVec vec1) +{ + return !(vec0 == vec1); +} + +inline +const boolInVec +operator & (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(vec_and(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator | (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(vec_or(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator ^ (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(vec_xor(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1) +{ + return boolInVec(vec_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); +} + +} // namespace Vectormath + +#endif // boolInVec_h diff --git a/common/vectormath/ppu/cpp/floatInVec.h b/common/vectormath/ppu/cpp/floatInVec.h index 369ec2ec..31415b21 100644 --- a/common/vectormath/ppu/cpp/floatInVec.h +++ b/common/vectormath/ppu/cpp/floatInVec.h @@ -1,361 +1,361 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _FLOATINVEC_H -#define _FLOATINVEC_H - -#include -#include -#include -#include -#include -#undef bool - -namespace Vectormath { - -class boolInVec; - -//-------------------------------------------------------------------------------------------------- -// floatInVec class -// - -class floatInVec -{ - private: - vec_float4 mData; - - inline floatInVec(vec_float4 vec); - public: - inline floatInVec() {} - - // matches standard type conversions - // - inline floatInVec(boolInVec vec); - - // construct from a slot of vec_float4 - // - inline floatInVec(vec_float4 vec, int slot); - - // explicit cast from float - // - explicit inline floatInVec(float scalar); - -#ifdef _VECTORMATH_NO_SCALAR_CAST - // explicit cast to float - // - inline float getAsFloat() const; -#else - // implicit cast to float - // - inline operator float() const; -#endif - - // get vector data - // float value is splatted across all word slots of vector - // - inline vec_float4 get128() const; - - // operators - // - inline const floatInVec operator ++ (int); - inline const floatInVec operator -- (int); - inline floatInVec& operator ++ (); - inline floatInVec& operator -- (); - inline const floatInVec operator - () const; - inline floatInVec& operator = (floatInVec vec); - inline floatInVec& operator *= (floatInVec vec); - inline floatInVec& operator /= (floatInVec vec); - inline floatInVec& operator += (floatInVec vec); - inline floatInVec& operator -= (floatInVec vec); - - // friend functions - // - friend inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); -}; - -//-------------------------------------------------------------------------------------------------- -// floatInVec functions -// - -// operators -// -inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); - -// select between vec0 and vec1 using boolInVec. -// false selects vec0, true selects vec1 -// -inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); - -} // namespace Vectormath - -//-------------------------------------------------------------------------------------------------- -// floatInVec implementation -// - -#include "boolInVec.h" - -namespace Vectormath { - -inline -floatInVec::floatInVec(vec_float4 vec) -{ - mData = vec; -} - -inline -floatInVec::floatInVec(boolInVec vec) -{ - mData = vec_ctf(vec_sub((vec_uint4){0,0,0,0}, vec.get128()), 0); -} - -inline -floatInVec::floatInVec(vec_float4 vec, int slot) -{ -#ifdef __GNUC__ - if (__builtin_constant_p(slot)) - { - mData = vec_splat(vec, slot); - } - else -#endif - { - const vec_uchar16 shiftpattern = vec_lvsl(0, (float *)(size_t)(slot << 2)); - mData = vec_splat(vec_perm(vec, vec, shiftpattern), 0); - } -} - -inline -floatInVec::floatInVec(float scalar) -{ -#ifdef __GNUC__ - if (__builtin_constant_p(scalar)) - { - mData = (vec_float4){scalar, scalar, scalar, scalar}; - } - else -#endif - { - vec_float4 vec = vec_ld(0, &scalar); - mData = vec_splat(vec_perm(vec, vec, vec_lvsl(0, &scalar)), 0); - } -} - -#ifdef _VECTORMATH_NO_SCALAR_CAST -inline -float -floatInVec::getAsFloat() const -#else -inline -floatInVec::operator float() const -#endif -{ - return *((float *)&mData); -} - -inline -vec_float4 -floatInVec::get128() const -{ - return mData; -} - -inline -const floatInVec -floatInVec::operator ++ (int) -{ - vec_float4 olddata = mData; - operator ++(); - return floatInVec(olddata); -} - -inline -const floatInVec -floatInVec::operator -- (int) -{ - vec_float4 olddata = mData; - operator --(); - return floatInVec(olddata); -} - -inline -floatInVec& -floatInVec::operator ++ () -{ - *this += floatInVec((vec_float4){1.0f,1.0f,1.0f,1.0f}); - return *this; -} - -inline -floatInVec& -floatInVec::operator -- () -{ - *this -= floatInVec((vec_float4){1.0f,1.0f,1.0f,1.0f}); - return *this; -} - -inline -const floatInVec -floatInVec::operator - () const -{ - return floatInVec((vec_float4)vec_xor((vec_uint4)mData, (vec_uint4){0x80000000,0x80000000,0x80000000,0x80000000})); -} - -inline -floatInVec& -floatInVec::operator = (floatInVec vec) -{ - mData = vec.mData; - return *this; -} - -inline -floatInVec& -floatInVec::operator *= (floatInVec vec) -{ - *this = *this * vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator /= (floatInVec vec) -{ - *this = *this / vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator += (floatInVec vec) -{ - *this = *this + vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator -= (floatInVec vec) -{ - *this = *this - vec; - return *this; -} - -inline -const floatInVec -operator * (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(vec_madd(vec0.get128(), vec1.get128(), (vec_float4){0,0,0,0})); -} - -inline -const floatInVec -operator / (floatInVec num, floatInVec den) -{ - return floatInVec(divf4(num.get128(), den.get128())); -} - -inline -const floatInVec -operator + (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(vec_add(vec0.get128(), vec1.get128())); -} - -inline -const floatInVec -operator - (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(vec_sub(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator < (floatInVec vec0, floatInVec vec1) -{ - return boolInVec((vec_uint4)vec_cmpgt(vec1.get128(), vec0.get128())); -} - -inline -const boolInVec -operator <= (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 > vec1); -} - -inline -const boolInVec -operator > (floatInVec vec0, floatInVec vec1) -{ - return boolInVec((vec_uint4)vec_cmpgt(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator >= (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 < vec1); -} - -inline -const boolInVec -operator == (floatInVec vec0, floatInVec vec1) -{ - return boolInVec((vec_uint4)vec_cmpeq(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator != (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 == vec1); -} - -inline -const floatInVec -select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1) -{ - return floatInVec(vec_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); -} - -} // namespace Vectormath - -#endif // floatInVec_h +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FLOATINVEC_H +#define _FLOATINVEC_H + +#include +#include +#include +#include +#include +#undef bool + +namespace Vectormath { + +class boolInVec; + +//-------------------------------------------------------------------------------------------------- +// floatInVec class +// + +class floatInVec +{ + private: + vec_float4 mData; + + inline floatInVec(vec_float4 vec); + public: + inline floatInVec() {} + + // matches standard type conversions + // + inline floatInVec(boolInVec vec); + + // construct from a slot of vec_float4 + // + inline floatInVec(vec_float4 vec, int slot); + + // explicit cast from float + // + explicit inline floatInVec(float scalar); + +#ifdef _VECTORMATH_NO_SCALAR_CAST + // explicit cast to float + // + inline float getAsFloat() const; +#else + // implicit cast to float + // + inline operator float() const; +#endif + + // get vector data + // float value is splatted across all word slots of vector + // + inline vec_float4 get128() const; + + // operators + // + inline const floatInVec operator ++ (int); + inline const floatInVec operator -- (int); + inline floatInVec& operator ++ (); + inline floatInVec& operator -- (); + inline const floatInVec operator - () const; + inline floatInVec& operator = (floatInVec vec); + inline floatInVec& operator *= (floatInVec vec); + inline floatInVec& operator /= (floatInVec vec); + inline floatInVec& operator += (floatInVec vec); + inline floatInVec& operator -= (floatInVec vec); + + // friend functions + // + friend inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); +}; + +//-------------------------------------------------------------------------------------------------- +// floatInVec functions +// + +// operators +// +inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); + +// select between vec0 and vec1 using boolInVec. +// false selects vec0, true selects vec1 +// +inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); + +} // namespace Vectormath + +//-------------------------------------------------------------------------------------------------- +// floatInVec implementation +// + +#include "boolInVec.h" + +namespace Vectormath { + +inline +floatInVec::floatInVec(vec_float4 vec) +{ + mData = vec; +} + +inline +floatInVec::floatInVec(boolInVec vec) +{ + mData = vec_ctf(vec_sub((vec_uint4){0,0,0,0}, vec.get128()), 0); +} + +inline +floatInVec::floatInVec(vec_float4 vec, int slot) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(slot)) + { + mData = vec_splat(vec, slot); + } + else +#endif + { + const vec_uchar16 shiftpattern = vec_lvsl(0, (float *)(size_t)(slot << 2)); + mData = vec_splat(vec_perm(vec, vec, shiftpattern), 0); + } +} + +inline +floatInVec::floatInVec(float scalar) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(scalar)) + { + mData = (vec_float4){scalar, scalar, scalar, scalar}; + } + else +#endif + { + vec_float4 vec = vec_ld(0, &scalar); + mData = vec_splat(vec_perm(vec, vec, vec_lvsl(0, &scalar)), 0); + } +} + +#ifdef _VECTORMATH_NO_SCALAR_CAST +inline +float +floatInVec::getAsFloat() const +#else +inline +floatInVec::operator float() const +#endif +{ + return *((float *)&mData); +} + +inline +vec_float4 +floatInVec::get128() const +{ + return mData; +} + +inline +const floatInVec +floatInVec::operator ++ (int) +{ + vec_float4 olddata = mData; + operator ++(); + return floatInVec(olddata); +} + +inline +const floatInVec +floatInVec::operator -- (int) +{ + vec_float4 olddata = mData; + operator --(); + return floatInVec(olddata); +} + +inline +floatInVec& +floatInVec::operator ++ () +{ + *this += floatInVec((vec_float4){1.0f,1.0f,1.0f,1.0f}); + return *this; +} + +inline +floatInVec& +floatInVec::operator -- () +{ + *this -= floatInVec((vec_float4){1.0f,1.0f,1.0f,1.0f}); + return *this; +} + +inline +const floatInVec +floatInVec::operator - () const +{ + return floatInVec((vec_float4)vec_xor((vec_uint4)mData, (vec_uint4){0x80000000,0x80000000,0x80000000,0x80000000})); +} + +inline +floatInVec& +floatInVec::operator = (floatInVec vec) +{ + mData = vec.mData; + return *this; +} + +inline +floatInVec& +floatInVec::operator *= (floatInVec vec) +{ + *this = *this * vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator /= (floatInVec vec) +{ + *this = *this / vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator += (floatInVec vec) +{ + *this = *this + vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator -= (floatInVec vec) +{ + *this = *this - vec; + return *this; +} + +inline +const floatInVec +operator * (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(vec_madd(vec0.get128(), vec1.get128(), (vec_float4){0,0,0,0})); +} + +inline +const floatInVec +operator / (floatInVec num, floatInVec den) +{ + return floatInVec(divf4(num.get128(), den.get128())); +} + +inline +const floatInVec +operator + (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(vec_add(vec0.get128(), vec1.get128())); +} + +inline +const floatInVec +operator - (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(vec_sub(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator < (floatInVec vec0, floatInVec vec1) +{ + return boolInVec((vec_uint4)vec_cmpgt(vec1.get128(), vec0.get128())); +} + +inline +const boolInVec +operator <= (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 > vec1); +} + +inline +const boolInVec +operator > (floatInVec vec0, floatInVec vec1) +{ + return boolInVec((vec_uint4)vec_cmpgt(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator >= (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 < vec1); +} + +inline +const boolInVec +operator == (floatInVec vec0, floatInVec vec1) +{ + return boolInVec((vec_uint4)vec_cmpeq(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator != (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 == vec1); +} + +inline +const floatInVec +select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1) +{ + return floatInVec(vec_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); +} + +} // namespace Vectormath + +#endif // floatInVec_h diff --git a/common/vectormath/ppu/cpp/mat_aos.h b/common/vectormath/ppu/cpp/mat_aos.h index 783e9c58..8607985e 100644 --- a/common/vectormath/ppu/cpp/mat_aos.h +++ b/common/vectormath/ppu/cpp/mat_aos.h @@ -1,2188 +1,2201 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_MAT_AOS_CPP_H -#define _VECTORMATH_MAT_AOS_CPP_H - -namespace Vectormath { -namespace Aos { - -//----------------------------------------------------------------------------- -// Constants -// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - -#define _VECTORMATH_PERM_ZBWX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XCYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_C, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B }) -#define _VECTORMATH_PERM_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W, _VECTORMATH_PERM_C, _VECTORMATH_PERM_D }) -#define _VECTORMATH_PERM_XZBX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_CXXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_YAXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W, _VECTORMATH_PERM_Z }) -#define _VECTORMATH_PERM_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_D }) -#define _VECTORMATH_PERM_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y }) -#define _VECTORMATH_PERM_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_ZAYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_BZXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PERM_XZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A }) -#define _VECTORMATH_PERM_ZXXB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_B }) -#define _VECTORMATH_PERM_YXXC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_C }) -#define _VECTORMATH_PERM_BBYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_B, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) -#define _VECTORMATH_PI_OVER_2 1.570796327f - -//----------------------------------------------------------------------------- -// Definitions - -inline Matrix3::Matrix3( const Matrix3 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; -} - -inline Matrix3::Matrix3( float scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); -} - -inline Matrix3::Matrix3( floatInVec scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); -} - -inline Matrix3::Matrix3( Quat unitQuat ) -{ - vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - vec_uint4 select_x = _VECTORMATH_MASK_0xF000; - vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; - xyzw_2 = vec_add( unitQuat.get128(), unitQuat.get128() ); - wwww = vec_splat( unitQuat.get128(), 3 ); - yzxw = vec_perm( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_PERM_YZXW ); - zxyw = vec_perm( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_PERM_ZXYW ); - yzxw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_YZXW ); - zxyw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_ZXYW ); - tmp0 = vec_madd( yzxw_2, wwww, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - tmp1 = vec_nmsub( yzxw, yzxw_2, ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); - tmp2 = vec_madd( yzxw, xyzw_2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - tmp0 = vec_madd( zxyw, xyzw_2, tmp0 ); - tmp1 = vec_nmsub( zxyw, zxyw_2, tmp1 ); - tmp2 = vec_nmsub( zxyw_2, wwww, tmp2 ); - tmp3 = vec_sel( tmp0, tmp1, select_x ); - tmp4 = vec_sel( tmp1, tmp2, select_x ); - tmp5 = vec_sel( tmp2, tmp0, select_x ); - mCol0 = Vector3( vec_sel( tmp3, tmp2, select_z ) ); - mCol1 = Vector3( vec_sel( tmp4, tmp0, select_z ) ); - mCol2 = Vector3( vec_sel( tmp5, tmp1, select_z ) ); -} - -inline Matrix3::Matrix3( Vector3 _col0, Vector3 _col1, Vector3 _col2 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; -} - -inline Matrix3 & Matrix3::setCol0( Vector3 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Matrix3 & Matrix3::setCol1( Vector3 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Matrix3 & Matrix3::setCol2( Vector3 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Matrix3 & Matrix3::setCol( int col, Vector3 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Matrix3 & Matrix3::setRow( int row, Vector3 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - return *this; -} - -inline Matrix3 & Matrix3::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline Matrix3 & Matrix3::setElem( int col, int row, floatInVec val ) -{ - Vector3 tmpV3_0; - tmpV3_0 = this->getCol( col ); - tmpV3_0.setElem( row, val ); - this->setCol( col, tmpV3_0 ); - return *this; -} - -inline const floatInVec Matrix3::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector3 Matrix3::getCol0( ) const -{ - return mCol0; -} - -inline const Vector3 Matrix3::getCol1( ) const -{ - return mCol1; -} - -inline const Vector3 Matrix3::getCol2( ) const -{ - return mCol2; -} - -inline const Vector3 Matrix3::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector3 Matrix3::getRow( int row ) const -{ - return Vector3( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ) ); -} - -inline Vector3 & Matrix3::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector3 Matrix3::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Matrix3 & Matrix3::operator =( const Matrix3 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - return *this; -} - -inline const Matrix3 transpose( const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, res0, res1, res2; - tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); - tmp1 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); - res0 = vec_mergeh( tmp0, mat.getCol1().get128() ); - res1 = vec_perm( tmp0, mat.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); - res2 = vec_perm( tmp1, mat.getCol1().get128(), _VECTORMATH_PERM_XCYX ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 inverse( const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp2 = _vmathVfCross( mat.getCol0().get128(), mat.getCol1().get128() ); - tmp0 = _vmathVfCross( mat.getCol1().get128(), mat.getCol2().get128() ); - tmp1 = _vmathVfCross( mat.getCol2().get128(), mat.getCol0().get128() ); - dot = _vmathVfDot3( tmp2, mat.getCol2().get128() ); - dot = vec_splat( dot, 0 ); - invdet = recipf4( dot ); - tmp3 = vec_mergeh( tmp0, tmp2 ); - tmp4 = vec_mergel( tmp0, tmp2 ); - inv0 = vec_mergeh( tmp3, tmp1 ); - inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); - inv0 = vec_madd( inv0, invdet, zero ); - inv1 = vec_madd( inv1, invdet, zero ); - inv2 = vec_madd( inv2, invdet, zero ); - return Matrix3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ) - ); -} - -inline const floatInVec determinant( const Matrix3 & mat ) -{ - return dot( mat.getCol2(), cross( mat.getCol0(), mat.getCol1() ) ); -} - -inline const Matrix3 Matrix3::operator +( const Matrix3 & mat ) const -{ - return Matrix3( - ( mCol0 + mat.mCol0 ), - ( mCol1 + mat.mCol1 ), - ( mCol2 + mat.mCol2 ) - ); -} - -inline const Matrix3 Matrix3::operator -( const Matrix3 & mat ) const -{ - return Matrix3( - ( mCol0 - mat.mCol0 ), - ( mCol1 - mat.mCol1 ), - ( mCol2 - mat.mCol2 ) - ); -} - -inline Matrix3 & Matrix3::operator +=( const Matrix3 & mat ) -{ - *this = *this + mat; - return *this; -} - -inline Matrix3 & Matrix3::operator -=( const Matrix3 & mat ) -{ - *this = *this - mat; - return *this; -} - -inline const Matrix3 Matrix3::operator -( ) const -{ - return Matrix3( - ( -mCol0 ), - ( -mCol1 ), - ( -mCol2 ) - ); -} - -inline const Matrix3 absPerElem( const Matrix3 & mat ) -{ - return Matrix3( - absPerElem( mat.getCol0() ), - absPerElem( mat.getCol1() ), - absPerElem( mat.getCol2() ) - ); -} - -inline const Matrix3 Matrix3::operator *( float scalar ) const -{ - return *this * floatInVec(scalar); -} - -inline const Matrix3 Matrix3::operator *( floatInVec scalar ) const -{ - return Matrix3( - ( mCol0 * scalar ), - ( mCol1 * scalar ), - ( mCol2 * scalar ) - ); -} - -inline Matrix3 & Matrix3::operator *=( float scalar ) -{ - return *this *= floatInVec(scalar); -} - -inline Matrix3 & Matrix3::operator *=( floatInVec scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Matrix3 operator *( float scalar, const Matrix3 & mat ) -{ - return floatInVec(scalar) * mat; -} - -inline const Matrix3 operator *( floatInVec scalar, const Matrix3 & mat ) -{ - return mat * scalar; -} - -inline const Vector3 Matrix3::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec.get128(), 0 ); - yyyy = vec_splat( vec.get128(), 1 ); - zzzz = vec_splat( vec.get128(), 2 ); - res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( mCol1.get128(), yyyy, res ); - res = vec_madd( mCol2.get128(), zzzz, res ); - return Vector3( res ); -} - -inline const Matrix3 Matrix3::operator *( const Matrix3 & mat ) const -{ - return Matrix3( - ( *this * mat.mCol0 ), - ( *this * mat.mCol1 ), - ( *this * mat.mCol2 ) - ); -} - -inline Matrix3 & Matrix3::operator *=( const Matrix3 & mat ) -{ - *this = *this * mat; - return *this; -} - -inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ) -{ - return Matrix3( - mulPerElem( mat0.getCol0(), mat1.getCol0() ), - mulPerElem( mat0.getCol1(), mat1.getCol1() ), - mulPerElem( mat0.getCol2(), mat1.getCol2() ) - ); -} - -inline const Matrix3 Matrix3::identity( ) -{ - return Matrix3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ) - ); -} - -inline const Matrix3 Matrix3::rotationX( float radians ) -{ - return rotationX( floatInVec(radians) ); -} - -inline const Matrix3 Matrix3::rotationX( floatInVec radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - return Matrix3( - Vector3::xAxis( ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 Matrix3::rotationY( float radians ) -{ - return rotationY( floatInVec(radians) ); -} - -inline const Matrix3 Matrix3::rotationY( floatInVec radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - return Matrix3( - Vector3( res0 ), - Vector3::yAxis( ), - Vector3( res2 ) - ); -} - -inline const Matrix3 Matrix3::rotationZ( float radians ) -{ - return rotationZ( floatInVec(radians) ); -} - -inline const Matrix3 Matrix3::rotationZ( floatInVec radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3::zAxis( ) - ); -} - -inline const Matrix3 Matrix3::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - angles = Vector4( radiansXYZ, 0.0f ).get128(); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - return Matrix3( - Vector3( vec_madd( Z0, Y0, zero ) ), - Vector3( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), - Vector3( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ) - ); -} - -inline const Matrix3 Matrix3::rotation( float radians, Vector3 unitVec ) -{ - return rotation( floatInVec(radians), unitVec ); -} - -inline const Matrix3 Matrix3::rotation( floatInVec radians, Vector3 unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - axis = unitVec.get128(); - sincosf4( radians.get128(), &s, &c ); - xxxx = vec_splat( axis, 0 ); - yyyy = vec_splat( axis, 1 ); - zzzz = vec_splat( axis, 2 ); - oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); - axisS = vec_madd( axis, s, zero ); - negAxisS = negatef4( axisS ); - tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); - tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); - tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); - tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); - tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); - tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); - return Matrix3( - Vector3( vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ) ), - Vector3( vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ) ), - Vector3( vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ) ) - ); -} - -inline const Matrix3 Matrix3::rotation( Quat unitQuat ) -{ - return Matrix3( unitQuat ); -} - -inline const Matrix3 Matrix3::scale( Vector3 scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - return Matrix3( - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ) - ); -} - -inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ) -{ - return Matrix3( - ( mat.getCol0() * scaleVec.getX( ) ), - ( mat.getCol1() * scaleVec.getY( ) ), - ( mat.getCol2() * scaleVec.getZ( ) ) - ); -} - -inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ) -{ - return Matrix3( - mulPerElem( mat.getCol0(), scaleVec ), - mulPerElem( mat.getCol1(), scaleVec ), - mulPerElem( mat.getCol2(), scaleVec ) - ); -} - -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ) -{ - return Matrix3( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ) - ); -} - -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, boolInVec select1 ) -{ - return Matrix3( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Matrix3 & mat ) -{ - print( mat.getRow( 0 ) ); - print( mat.getRow( 1 ) ); - print( mat.getRow( 2 ) ); -} - -inline void print( const Matrix3 & mat, const char * name ) -{ - printf("%s:\n", name); - print( mat ); -} - -#endif - -inline Matrix4::Matrix4( const Matrix4 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - mCol3 = mat.mCol3; -} - -inline Matrix4::Matrix4( float scalar ) -{ - mCol0 = Vector4( scalar ); - mCol1 = Vector4( scalar ); - mCol2 = Vector4( scalar ); - mCol3 = Vector4( scalar ); -} - -inline Matrix4::Matrix4( floatInVec scalar ) -{ - mCol0 = Vector4( scalar ); - mCol1 = Vector4( scalar ); - mCol2 = Vector4( scalar ); - mCol3 = Vector4( scalar ); -} - -inline Matrix4::Matrix4( const Transform3 & mat ) -{ - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( mat.getCol3(), 1.0f ); -} - -inline Matrix4::Matrix4( Vector4 _col0, Vector4 _col1, Vector4 _col2, Vector4 _col3 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; - mCol3 = _col3; -} - -inline Matrix4::Matrix4( const Matrix3 & mat, Vector3 translateVec ) -{ - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( translateVec, 1.0f ); -} - -inline Matrix4::Matrix4( Quat unitQuat, Vector3 translateVec ) -{ - Matrix3 mat; - mat = Matrix3( unitQuat ); - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( translateVec, 1.0f ); -} - -inline Matrix4 & Matrix4::setCol0( Vector4 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Matrix4 & Matrix4::setCol1( Vector4 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Matrix4 & Matrix4::setCol2( Vector4 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Matrix4 & Matrix4::setCol3( Vector4 _col3 ) -{ - mCol3 = _col3; - return *this; -} - -inline Matrix4 & Matrix4::setCol( int col, Vector4 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Matrix4 & Matrix4::setRow( int row, Vector4 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - mCol3.setElem( row, vec.getElem( 3 ) ); - return *this; -} - -inline Matrix4 & Matrix4::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline Matrix4 & Matrix4::setElem( int col, int row, floatInVec val ) -{ - Vector4 tmpV3_0; - tmpV3_0 = this->getCol( col ); - tmpV3_0.setElem( row, val ); - this->setCol( col, tmpV3_0 ); - return *this; -} - -inline const floatInVec Matrix4::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector4 Matrix4::getCol0( ) const -{ - return mCol0; -} - -inline const Vector4 Matrix4::getCol1( ) const -{ - return mCol1; -} - -inline const Vector4 Matrix4::getCol2( ) const -{ - return mCol2; -} - -inline const Vector4 Matrix4::getCol3( ) const -{ - return mCol3; -} - -inline const Vector4 Matrix4::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector4 Matrix4::getRow( int row ) const -{ - return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); -} - -inline Vector4 & Matrix4::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector4 Matrix4::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Matrix4 & Matrix4::operator =( const Matrix4 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - mCol3 = mat.mCol3; - return *this; -} - -inline const Matrix4 transpose( const Matrix4 & mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; - tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); - tmp1 = vec_mergeh( mat.getCol1().get128(), mat.getCol3().get128() ); - tmp2 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); - tmp3 = vec_mergel( mat.getCol1().get128(), mat.getCol3().get128() ); - res0 = vec_mergeh( tmp0, tmp1 ); - res1 = vec_mergel( tmp0, tmp1 ); - res2 = vec_mergeh( tmp2, tmp3 ); - res3 = vec_mergel( tmp2, tmp3 ); - return Matrix4( - Vector4( res0 ), - Vector4( res1 ), - Vector4( res2 ), - Vector4( res3 ) - ); -} - -inline const Matrix4 inverse( const Matrix4 & mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vector float in0, in1, in2, in3; - vector float tmp0, tmp1, tmp2, tmp3; - vector float cof0, cof1, cof2, cof3; - vector float t0, t1, t2, t3; - vector float t01, t02, t03, t12, t23; - vector float t1r, t2r; - vector float t01r, t02r, t03r, t12r, t23r; - vector float t1r3, t1r3r; - vector float det, det0, det1, det2, det3, invdet; - vector float vzero = (vector float){0.0}; - in0 = mat.getCol0().get128(); - in1 = mat.getCol1().get128(); - in2 = mat.getCol2().get128(); - in3 = mat.getCol3().get128(); - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ - tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ - tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ - tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ - t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ - t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ - t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ - t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ - t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ - cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ - cof1 = vec_nmsub(t0, t23, vzero); /* -(AGP ECL IOH MKD) */ - t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ - cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ - cof1 = vec_madd(t0, t23r, cof1); /* AOH EKD IGP MCL + cof1 */ - cof1 = vec_sld(cof1, cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ - t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ - t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ - cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - cof3 = vec_madd(t0, t12, vzero); /* ANG EJC IFO MBK */ - t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ - cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - cof3 = vec_nmsub(t0, t12r, cof3); /* cof3 - AFO EBK ING MJC */ - cof3 = vec_sld(cof3, cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ - t1r = vec_sld(t1, t1, 8); /* B F J N */ - t2r = vec_sld(t2, t2, 8); /* K O C G */ - t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ - t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ - cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - cof2 = vec_madd(t0, t1r3, vzero); /* AFP EBL INH MJD */ - t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ - cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - cof2 = vec_nmsub(t0, t1r3r, cof2); /* cof2 - ANH EJD IFP MBL */ - cof2 = vec_sld(cof2, cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ - t01 = vec_madd(t0, t1, vzero); /* AJ EN IB MF */ - t01 = vec_perm(t01, t01, _VECTORMATH_PERM_YXWZ); /* EN AJ MF IB */ - cof2 = vec_nmsub(t3, t01, cof2); /* cof2 - LEN PAJ DMF HIB */ - cof3 = vec_madd(t2r, t01, cof3); /* KEN OAJ CMF GIB + cof3 */ - t01r = vec_sld(t01, t01, 8); /* MF IB EN AJ */ - cof2 = vec_madd(t3, t01r, cof2); /* LMF PIB DEN HAJ + cof2 */ - cof3 = vec_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ - t03 = vec_madd(t0, t3, vzero); /* AL EP ID MH */ - t03 = vec_perm(t03, t03, _VECTORMATH_PERM_YXWZ); /* EP AL MH ID */ - cof1 = vec_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ - cof2 = vec_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ - t03r = vec_sld(t03, t03, 8); /* MH ID EP AL */ - cof1 = vec_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ - cof2 = vec_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ - t02 = vec_madd(t0, t2r, vzero); /* AK EO IC MG */ - t02 = vec_perm(t02, t02, _VECTORMATH_PERM_YXWZ); /* E0 AK MG IC */ - cof1 = vec_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ - cof3 = vec_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ - t02r = vec_sld(t02, t02, 8); /* MG IC EO AK */ - cof1 = vec_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ - cof3 = vec_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ - /* Compute the determinant of the matrix - * - * det = sum_across(t0 * cof0); - * - * We perform a sum across the entire vector so that - * we don't have to splat the result when multiplying the - * cofactors by the inverse of the determinant. - */ - det = vec_madd(t0, cof0, vzero); - det0 = vec_splat(det, 0); - det1 = vec_splat(det, 1); - det2 = vec_splat(det, 2); - det3 = vec_splat(det, 3); - det = vec_add(det0, det1); - det2 = vec_add(det2, det3); - det = vec_add(det, det2); - /* Compute the reciprocal of the determinant. - */ - invdet = recipf4(det); - /* Multiply the cofactors by the reciprocal of the determinant. - */ - return Matrix4( - Vector4( vec_madd(cof0, invdet, vzero) ), - Vector4( vec_madd(cof1, invdet, vzero) ), - Vector4( vec_madd(cof2, invdet, vzero) ), - Vector4( vec_madd(cof3, invdet, vzero) ) - ); -} - -inline const Matrix4 affineInverse( const Matrix4 & mat ) -{ - Transform3 affineMat; - affineMat.setCol0( mat.getCol0().getXYZ( ) ); - affineMat.setCol1( mat.getCol1().getXYZ( ) ); - affineMat.setCol2( mat.getCol2().getXYZ( ) ); - affineMat.setCol3( mat.getCol3().getXYZ( ) ); - return Matrix4( inverse( affineMat ) ); -} - -inline const Matrix4 orthoInverse( const Matrix4 & mat ) -{ - Transform3 affineMat; - affineMat.setCol0( mat.getCol0().getXYZ( ) ); - affineMat.setCol1( mat.getCol1().getXYZ( ) ); - affineMat.setCol2( mat.getCol2().getXYZ( ) ); - affineMat.setCol3( mat.getCol3().getXYZ( ) ); - return Matrix4( orthoInverse( affineMat ) ); -} - -inline const floatInVec determinant( const Matrix4 & mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vector float in0, in1, in2, in3; - vector float tmp0, tmp1, tmp2, tmp3; - vector float cof0; - vector float t0, t1, t2, t3; - vector float t12, t23; - vector float t1r, t2r; - vector float t12r, t23r; - vector float t1r3, t1r3r; - vector float vzero = (vector float){0.0}; - in0 = mat.getCol0().get128(); - in1 = mat.getCol1().get128(); - in2 = mat.getCol2().get128(); - in3 = mat.getCol3().get128(); - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ - tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ - tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ - tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ - t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ - t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ - t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ - t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ - t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ - cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ - t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ - cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ - t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ - t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ - cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ - cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - t1r = vec_sld(t1, t1, 8); /* B F J N */ - t2r = vec_sld(t2, t2, 8); /* K O C G */ - t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ - t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ - cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ - cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - return floatInVec( _vmathVfDot4(t0,cof0), 0 ); -} - -inline const Matrix4 Matrix4::operator +( const Matrix4 & mat ) const -{ - return Matrix4( - ( mCol0 + mat.mCol0 ), - ( mCol1 + mat.mCol1 ), - ( mCol2 + mat.mCol2 ), - ( mCol3 + mat.mCol3 ) - ); -} - -inline const Matrix4 Matrix4::operator -( const Matrix4 & mat ) const -{ - return Matrix4( - ( mCol0 - mat.mCol0 ), - ( mCol1 - mat.mCol1 ), - ( mCol2 - mat.mCol2 ), - ( mCol3 - mat.mCol3 ) - ); -} - -inline Matrix4 & Matrix4::operator +=( const Matrix4 & mat ) -{ - *this = *this + mat; - return *this; -} - -inline Matrix4 & Matrix4::operator -=( const Matrix4 & mat ) -{ - *this = *this - mat; - return *this; -} - -inline const Matrix4 Matrix4::operator -( ) const -{ - return Matrix4( - ( -mCol0 ), - ( -mCol1 ), - ( -mCol2 ), - ( -mCol3 ) - ); -} - -inline const Matrix4 absPerElem( const Matrix4 & mat ) -{ - return Matrix4( - absPerElem( mat.getCol0() ), - absPerElem( mat.getCol1() ), - absPerElem( mat.getCol2() ), - absPerElem( mat.getCol3() ) - ); -} - -inline const Matrix4 Matrix4::operator *( float scalar ) const -{ - return *this * floatInVec(scalar); -} - -inline const Matrix4 Matrix4::operator *( floatInVec scalar ) const -{ - return Matrix4( - ( mCol0 * scalar ), - ( mCol1 * scalar ), - ( mCol2 * scalar ), - ( mCol3 * scalar ) - ); -} - -inline Matrix4 & Matrix4::operator *=( float scalar ) -{ - return *this *= floatInVec(scalar); -} - -inline Matrix4 & Matrix4::operator *=( floatInVec scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Matrix4 operator *( float scalar, const Matrix4 & mat ) -{ - return floatInVec(scalar) * mat; -} - -inline const Matrix4 operator *( floatInVec scalar, const Matrix4 & mat ) -{ - return mat * scalar; -} - -inline const Vector4 Matrix4::operator *( Vector4 vec ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz, wwww; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( vec.get128(), 0 ); - yyyy = vec_splat( vec.get128(), 1 ); - zzzz = vec_splat( vec.get128(), 2 ); - wwww = vec_splat( vec.get128(), 3 ); - tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); - tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); - tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = vec_madd( mCol3.get128(), wwww, tmp1 ); - res = vec_add( tmp0, tmp1 ); - return Vector4( res ); -} - -inline const Vector4 Matrix4::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec.get128(), 0 ); - yyyy = vec_splat( vec.get128(), 1 ); - zzzz = vec_splat( vec.get128(), 2 ); - res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( mCol1.get128(), yyyy, res ); - res = vec_madd( mCol2.get128(), zzzz, res ); - return Vector4( res ); -} - -inline const Vector4 Matrix4::operator *( Point3 pnt ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( pnt.get128(), 0 ); - yyyy = vec_splat( pnt.get128(), 1 ); - zzzz = vec_splat( pnt.get128(), 2 ); - tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); - tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); - tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = vec_add( mCol3.get128(), tmp1 ); - res = vec_add( tmp0, tmp1 ); - return Vector4( res ); -} - -inline const Matrix4 Matrix4::operator *( const Matrix4 & mat ) const -{ - return Matrix4( - ( *this * mat.mCol0 ), - ( *this * mat.mCol1 ), - ( *this * mat.mCol2 ), - ( *this * mat.mCol3 ) - ); -} - -inline Matrix4 & Matrix4::operator *=( const Matrix4 & mat ) -{ - *this = *this * mat; - return *this; -} - -inline const Matrix4 Matrix4::operator *( const Transform3 & tfrm ) const -{ - return Matrix4( - ( *this * tfrm.getCol0() ), - ( *this * tfrm.getCol1() ), - ( *this * tfrm.getCol2() ), - ( *this * Point3( tfrm.getCol3() ) ) - ); -} - -inline Matrix4 & Matrix4::operator *=( const Transform3 & tfrm ) -{ - *this = *this * tfrm; - return *this; -} - -inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ) -{ - return Matrix4( - mulPerElem( mat0.getCol0(), mat1.getCol0() ), - mulPerElem( mat0.getCol1(), mat1.getCol1() ), - mulPerElem( mat0.getCol2(), mat1.getCol2() ), - mulPerElem( mat0.getCol3(), mat1.getCol3() ) - ); -} - -inline const Matrix4 Matrix4::identity( ) -{ - return Matrix4( - Vector4::xAxis( ), - Vector4::yAxis( ), - Vector4::zAxis( ), - Vector4::wAxis( ) - ); -} - -inline Matrix4 & Matrix4::setUpper3x3( const Matrix3 & mat3 ) -{ - mCol0.setXYZ( mat3.getCol0() ); - mCol1.setXYZ( mat3.getCol1() ); - mCol2.setXYZ( mat3.getCol2() ); - return *this; -} - -inline const Matrix3 Matrix4::getUpper3x3( ) const -{ - return Matrix3( - mCol0.getXYZ( ), - mCol1.getXYZ( ), - mCol2.getXYZ( ) - ); -} - -inline Matrix4 & Matrix4::setTranslation( Vector3 translateVec ) -{ - mCol3.setXYZ( translateVec ); - return *this; -} - -inline const Vector3 Matrix4::getTranslation( ) const -{ - return mCol3.getXYZ( ); -} - -inline const Matrix4 Matrix4::rotationX( float radians ) -{ - return rotationX( floatInVec(radians) ); -} - -inline const Matrix4 Matrix4::rotationX( floatInVec radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - return Matrix4( - Vector4::xAxis( ), - Vector4( res1 ), - Vector4( res2 ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationY( float radians ) -{ - return rotationY( floatInVec(radians) ); -} - -inline const Matrix4 Matrix4::rotationY( floatInVec radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - return Matrix4( - Vector4( res0 ), - Vector4::yAxis( ), - Vector4( res2 ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationZ( float radians ) -{ - return rotationZ( floatInVec(radians) ); -} - -inline const Matrix4 Matrix4::rotationZ( floatInVec radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - return Matrix4( - Vector4( res0 ), - Vector4( res1 ), - Vector4::zAxis( ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - angles = Vector4( radiansXYZ, 0.0f ).get128(); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - return Matrix4( - Vector4( vec_madd( Z0, Y0, zero ) ), - Vector4( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), - Vector4( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotation( float radians, Vector3 unitVec ) -{ - return rotation( floatInVec(radians), unitVec ); -} - -inline const Matrix4 Matrix4::rotation( floatInVec radians, Vector3 unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - axis = unitVec.get128(); - sincosf4( radians.get128(), &s, &c ); - xxxx = vec_splat( axis, 0 ); - yyyy = vec_splat( axis, 1 ); - zzzz = vec_splat( axis, 2 ); - oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); - axisS = vec_madd( axis, s, zero ); - negAxisS = negatef4( axisS ); - tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); - tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); - tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); - tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); - tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); - tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); - zeroW = (vec_float4)_VECTORMATH_MASK_0x000F; - axis = vec_andc( axis, zeroW ); - tmp0 = vec_andc( tmp0, zeroW ); - tmp1 = vec_andc( tmp1, zeroW ); - tmp2 = vec_andc( tmp2, zeroW ); - return Matrix4( - Vector4( vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ) ), - Vector4( vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ) ), - Vector4( vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotation( Quat unitQuat ) -{ - return Matrix4( Transform3::rotation( unitQuat ) ); -} - -inline const Matrix4 Matrix4::scale( Vector3 scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - return Matrix4( - Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), - Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), - Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ) -{ - return Matrix4( - ( mat.getCol0() * scaleVec.getX( ) ), - ( mat.getCol1() * scaleVec.getY( ) ), - ( mat.getCol2() * scaleVec.getZ( ) ), - mat.getCol3() - ); -} - -inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ) -{ - Vector4 scale4; - scale4 = Vector4( scaleVec, 1.0f ); - return Matrix4( - mulPerElem( mat.getCol0(), scale4 ), - mulPerElem( mat.getCol1(), scale4 ), - mulPerElem( mat.getCol2(), scale4 ), - mulPerElem( mat.getCol3(), scale4 ) - ); -} - -inline const Matrix4 Matrix4::translation( Vector3 translateVec ) -{ - return Matrix4( - Vector4::xAxis( ), - Vector4::yAxis( ), - Vector4::zAxis( ), - Vector4( translateVec, 1.0f ) - ); -} - -inline const Matrix4 Matrix4::lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ) -{ - Matrix4 m4EyeFrame; - Vector3 v3X, v3Y, v3Z; - v3Y = normalize( upVec ); - v3Z = normalize( ( eyePos - lookAtPos ) ); - v3X = normalize( cross( v3Y, v3Z ) ); - v3Y = cross( v3Z, v3X ); - m4EyeFrame = Matrix4( Vector4( v3X ), Vector4( v3Y ), Vector4( v3Z ), Vector4( eyePos ) ); - return orthoInverse( m4EyeFrame ); -} - -inline const Matrix4 Matrix4::perspective( float fovyRadians, float aspect, float zNear, float zFar ) -{ - float f, rangeInv; - vec_float4 zero, col0, col1, col2, col3; - union { vec_float4 v; float s[4]; } tmp; - f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); - rangeInv = 1.0f / ( zNear - zFar ); - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp.v = zero; - tmp.s[0] = f / aspect; - col0 = tmp.v; - tmp.v = zero; - tmp.s[1] = f; - col1 = tmp.v; - tmp.v = zero; - tmp.s[2] = ( zNear + zFar ) * rangeInv; - tmp.s[3] = -1.0f; - col2 = tmp.v; - tmp.v = zero; - tmp.s[2] = zNear * zFar * rangeInv * 2.0f; - col3 = tmp.v; - return Matrix4( - Vector4( col0 ), - Vector4( col1 ), - Vector4( col2 ), - Vector4( col3 ) - ); -} - -inline const Matrix4 Matrix4::frustum( float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff; - vec_float4 diagonal, column, near2; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - union { vec_float4 v; float s[4]; } l, f, r, n, b, t; - l.s[0] = left; - f.s[0] = zFar; - r.s[0] = right; - n.s[0] = zNear; - b.s[0] = bottom; - t.s[0] = top; - lbf = vec_mergeh( l.v, f.v ); - rtn = vec_mergeh( r.v, n.v ); - lbf = vec_mergeh( lbf, b.v ); - rtn = vec_mergeh( rtn, t.v ); - diff = vec_sub( rtn, lbf ); - sum = vec_add( rtn, lbf ); - inv_diff = recipf4( diff ); - near2 = vec_splat( n.v, 0 ); - near2 = vec_add( near2, near2 ); - diagonal = vec_madd( near2, inv_diff, zero ); - column = vec_madd( sum, inv_diff, zero ); - return Matrix4( - Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ) ), - Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ) ), - Vector4( vec_sel( column, ((vec_float4){-1.0f,-1.0f,-1.0f,-1.0f}), _VECTORMATH_MASK_0x000F ) ), - Vector4( vec_sel( zero, vec_madd( diagonal, vec_splat( f.v, 0 ), zero ), _VECTORMATH_MASK_0x00F0 ) ) - ); -} - -inline const Matrix4 Matrix4::orthographic( float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff, neg_inv_diff; - vec_float4 diagonal, column; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - union { vec_float4 v; float s[4]; } l, f, r, n, b, t; - l.s[0] = left; - f.s[0] = zFar; - r.s[0] = right; - n.s[0] = zNear; - b.s[0] = bottom; - t.s[0] = top; - lbf = vec_mergeh( l.v, f.v ); - rtn = vec_mergeh( r.v, n.v ); - lbf = vec_mergeh( lbf, b.v ); - rtn = vec_mergeh( rtn, t.v ); - diff = vec_sub( rtn, lbf ); - sum = vec_add( rtn, lbf ); - inv_diff = recipf4( diff ); - neg_inv_diff = negatef4( inv_diff ); - diagonal = vec_add( inv_diff, inv_diff ); - column = vec_madd( sum, vec_sel( neg_inv_diff, inv_diff, _VECTORMATH_MASK_0x00F0 ), zero ); - return Matrix4( - Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ) ), - Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ) ), - Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x00F0 ) ), - Vector4( vec_sel( column, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F ) ) - ); -} - -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ) -{ - return Matrix4( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ), - select( mat0.getCol3(), mat1.getCol3(), select1 ) - ); -} - -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, boolInVec select1 ) -{ - return Matrix4( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ), - select( mat0.getCol3(), mat1.getCol3(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Matrix4 & mat ) -{ - print( mat.getRow( 0 ) ); - print( mat.getRow( 1 ) ); - print( mat.getRow( 2 ) ); - print( mat.getRow( 3 ) ); -} - -inline void print( const Matrix4 & mat, const char * name ) -{ - printf("%s:\n", name); - print( mat ); -} - -#endif - -inline Transform3::Transform3( const Transform3 & tfrm ) -{ - mCol0 = tfrm.mCol0; - mCol1 = tfrm.mCol1; - mCol2 = tfrm.mCol2; - mCol3 = tfrm.mCol3; -} - -inline Transform3::Transform3( float scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); - mCol3 = Vector3( scalar ); -} - -inline Transform3::Transform3( floatInVec scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); - mCol3 = Vector3( scalar ); -} - -inline Transform3::Transform3( Vector3 _col0, Vector3 _col1, Vector3 _col2, Vector3 _col3 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; - mCol3 = _col3; -} - -inline Transform3::Transform3( const Matrix3 & tfrm, Vector3 translateVec ) -{ - this->setUpper3x3( tfrm ); - this->setTranslation( translateVec ); -} - -inline Transform3::Transform3( Quat unitQuat, Vector3 translateVec ) -{ - this->setUpper3x3( Matrix3( unitQuat ) ); - this->setTranslation( translateVec ); -} - -inline Transform3 & Transform3::setCol0( Vector3 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Transform3 & Transform3::setCol1( Vector3 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Transform3 & Transform3::setCol2( Vector3 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Transform3 & Transform3::setCol3( Vector3 _col3 ) -{ - mCol3 = _col3; - return *this; -} - -inline Transform3 & Transform3::setCol( int col, Vector3 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Transform3 & Transform3::setRow( int row, Vector4 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - mCol3.setElem( row, vec.getElem( 3 ) ); - return *this; -} - -inline Transform3 & Transform3::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline Transform3 & Transform3::setElem( int col, int row, floatInVec val ) -{ - Vector3 tmpV3_0; - tmpV3_0 = this->getCol( col ); - tmpV3_0.setElem( row, val ); - this->setCol( col, tmpV3_0 ); - return *this; -} - -inline const floatInVec Transform3::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector3 Transform3::getCol0( ) const -{ - return mCol0; -} - -inline const Vector3 Transform3::getCol1( ) const -{ - return mCol1; -} - -inline const Vector3 Transform3::getCol2( ) const -{ - return mCol2; -} - -inline const Vector3 Transform3::getCol3( ) const -{ - return mCol3; -} - -inline const Vector3 Transform3::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector4 Transform3::getRow( int row ) const -{ - return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); -} - -inline Vector3 & Transform3::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector3 Transform3::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Transform3 & Transform3::operator =( const Transform3 & tfrm ) -{ - mCol0 = tfrm.mCol0; - mCol1 = tfrm.mCol1; - mCol2 = tfrm.mCol2; - mCol3 = tfrm.mCol3; - return *this; -} - -inline const Transform3 inverse( const Transform3 & tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - tmp2 = _vmathVfCross( tfrm.getCol0().get128(), tfrm.getCol1().get128() ); - tmp0 = _vmathVfCross( tfrm.getCol1().get128(), tfrm.getCol2().get128() ); - tmp1 = _vmathVfCross( tfrm.getCol2().get128(), tfrm.getCol0().get128() ); - inv3 = negatef4( tfrm.getCol3().get128() ); - dot = _vmathVfDot3( tmp2, tfrm.getCol2().get128() ); - dot = vec_splat( dot, 0 ); - invdet = recipf4( dot ); - tmp3 = vec_mergeh( tmp0, tmp2 ); - tmp4 = vec_mergel( tmp0, tmp2 ); - inv0 = vec_mergeh( tmp3, tmp1 ); - xxxx = vec_splat( inv3, 0 ); - inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( inv3, 1 ); - zzzz = vec_splat( inv3, 2 ); - inv3 = vec_madd( inv0, xxxx, zero ); - inv3 = vec_madd( inv1, yyyy, inv3 ); - inv3 = vec_madd( inv2, zzzz, inv3 ); - inv0 = vec_madd( inv0, invdet, zero ); - inv1 = vec_madd( inv1, invdet, zero ); - inv2 = vec_madd( inv2, invdet, zero ); - inv3 = vec_madd( inv3, invdet, zero ); - return Transform3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ), - Vector3( inv3 ) - ); -} - -inline const Transform3 orthoInverse( const Transform3 & tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1; - vec_float4 xxxx, yyyy, zzzz; - tmp0 = vec_mergeh( tfrm.getCol0().get128(), tfrm.getCol2().get128() ); - tmp1 = vec_mergel( tfrm.getCol0().get128(), tfrm.getCol2().get128() ); - inv3 = negatef4( tfrm.getCol3().get128() ); - inv0 = vec_mergeh( tmp0, tfrm.getCol1().get128() ); - xxxx = vec_splat( inv3, 0 ); - inv1 = vec_perm( tmp0, tfrm.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); - inv2 = vec_perm( tmp1, tfrm.getCol1().get128(), _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( inv3, 1 ); - zzzz = vec_splat( inv3, 2 ); - inv3 = vec_madd( inv0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - inv3 = vec_madd( inv1, yyyy, inv3 ); - inv3 = vec_madd( inv2, zzzz, inv3 ); - return Transform3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ), - Vector3( inv3 ) - ); -} - -inline const Transform3 absPerElem( const Transform3 & tfrm ) -{ - return Transform3( - absPerElem( tfrm.getCol0() ), - absPerElem( tfrm.getCol1() ), - absPerElem( tfrm.getCol2() ), - absPerElem( tfrm.getCol3() ) - ); -} - -inline const Vector3 Transform3::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - xxxx = vec_splat( vec.get128(), 0 ); - yyyy = vec_splat( vec.get128(), 1 ); - zzzz = vec_splat( vec.get128(), 2 ); - res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( mCol1.get128(), yyyy, res ); - res = vec_madd( mCol2.get128(), zzzz, res ); - return Vector3( res ); -} - -inline const Point3 Transform3::operator *( Point3 pnt ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - xxxx = vec_splat( pnt.get128(), 0 ); - yyyy = vec_splat( pnt.get128(), 1 ); - zzzz = vec_splat( pnt.get128(), 2 ); - tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); - tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); - tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = vec_add( mCol3.get128(), tmp1 ); - res = vec_add( tmp0, tmp1 ); - return Point3( res ); -} - -inline const Transform3 Transform3::operator *( const Transform3 & tfrm ) const -{ - return Transform3( - ( *this * tfrm.mCol0 ), - ( *this * tfrm.mCol1 ), - ( *this * tfrm.mCol2 ), - Vector3( ( *this * Point3( tfrm.mCol3 ) ) ) - ); -} - -inline Transform3 & Transform3::operator *=( const Transform3 & tfrm ) -{ - *this = *this * tfrm; - return *this; -} - -inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ) -{ - return Transform3( - mulPerElem( tfrm0.getCol0(), tfrm1.getCol0() ), - mulPerElem( tfrm0.getCol1(), tfrm1.getCol1() ), - mulPerElem( tfrm0.getCol2(), tfrm1.getCol2() ), - mulPerElem( tfrm0.getCol3(), tfrm1.getCol3() ) - ); -} - -inline const Transform3 Transform3::identity( ) -{ - return Transform3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ), - Vector3( 0.0f ) - ); -} - -inline Transform3 & Transform3::setUpper3x3( const Matrix3 & tfrm ) -{ - mCol0 = tfrm.getCol0(); - mCol1 = tfrm.getCol1(); - mCol2 = tfrm.getCol2(); - return *this; -} - -inline const Matrix3 Transform3::getUpper3x3( ) const -{ - return Matrix3( mCol0, mCol1, mCol2 ); -} - -inline Transform3 & Transform3::setTranslation( Vector3 translateVec ) -{ - mCol3 = translateVec; - return *this; -} - -inline const Vector3 Transform3::getTranslation( ) const -{ - return mCol3; -} - -inline const Transform3 Transform3::rotationX( float radians ) -{ - return rotationX( floatInVec(radians) ); -} - -inline const Transform3 Transform3::rotationX( floatInVec radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = _VECTORMATH_MASK_0x0F00; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res1 = vec_sel( zero, c, select_y ); - res1 = vec_sel( res1, s, select_z ); - res2 = vec_sel( zero, negatef4(s), select_y ); - res2 = vec_sel( res2, c, select_z ); - return Transform3( - Vector3::xAxis( ), - Vector3( res1 ), - Vector3( res2 ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationY( float radians ) -{ - return rotationY( floatInVec(radians) ); -} - -inline const Transform3 Transform3::rotationY( floatInVec radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_z = _VECTORMATH_MASK_0x00F0; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, negatef4(s), select_z ); - res2 = vec_sel( zero, s, select_x ); - res2 = vec_sel( res2, c, select_z ); - return Transform3( - Vector3( res0 ), - Vector3::yAxis( ), - Vector3( res2 ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationZ( float radians ) -{ - return rotationZ( floatInVec(radians) ); -} - -inline const Transform3 Transform3::rotationZ( floatInVec radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = _VECTORMATH_MASK_0xF000; - select_y = _VECTORMATH_MASK_0x0F00; - zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - sincosf4( radians.get128(), &s, &c ); - res0 = vec_sel( zero, c, select_x ); - res0 = vec_sel( res0, s, select_y ); - res1 = vec_sel( zero, negatef4(s), select_x ); - res1 = vec_sel( res1, c, select_y ); - return Transform3( - Vector3( res0 ), - Vector3( res1 ), - Vector3::zAxis( ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - angles = Vector4( radiansXYZ, 0.0f ).get128(); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = vec_mergel( c, s ); - Z1 = vec_mergel( negS, c ); - Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); - Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); - Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); - X0 = vec_splat( s, 0 ); - X1 = vec_splat( c, 0 ); - tmp = vec_madd( Z0, Y1, zero ); - return Transform3( - Vector3( vec_madd( Z0, Y0, zero ) ), - Vector3( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), - Vector3( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotation( float radians, Vector3 unitVec ) -{ - return rotation( floatInVec(radians), unitVec ); -} - -inline const Transform3 Transform3::rotation( floatInVec radians, Vector3 unitVec ) -{ - return Transform3( Matrix3::rotation( radians, unitVec ), Vector3( 0.0f ) ); -} - -inline const Transform3 Transform3::rotation( Quat unitQuat ) -{ - return Transform3( Matrix3( unitQuat ), Vector3( 0.0f ) ); -} - -inline const Transform3 Transform3::scale( Vector3 scaleVec ) -{ - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - return Transform3( - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), - Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ) -{ - return Transform3( - ( tfrm.getCol0() * scaleVec.getX( ) ), - ( tfrm.getCol1() * scaleVec.getY( ) ), - ( tfrm.getCol2() * scaleVec.getZ( ) ), - tfrm.getCol3() - ); -} - -inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ) -{ - return Transform3( - mulPerElem( tfrm.getCol0(), scaleVec ), - mulPerElem( tfrm.getCol1(), scaleVec ), - mulPerElem( tfrm.getCol2(), scaleVec ), - mulPerElem( tfrm.getCol3(), scaleVec ) - ); -} - -inline const Transform3 Transform3::translation( Vector3 translateVec ) -{ - return Transform3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ), - translateVec - ); -} - -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ) -{ - return Transform3( - select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), - select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), - select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), - select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) - ); -} - -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, boolInVec select1 ) -{ - return Transform3( - select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), - select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), - select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), - select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Transform3 & tfrm ) -{ - print( tfrm.getRow( 0 ) ); - print( tfrm.getRow( 1 ) ); - print( tfrm.getRow( 2 ) ); -} - -inline void print( const Transform3 & tfrm, const char * name ) -{ - printf("%s:\n", name); - print( tfrm ); -} - -#endif - -inline Quat::Quat( const Matrix3 & tfrm ) -{ - vec_float4 res; - vec_float4 col0, col1, col2; - vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; - vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; - vec_float4 radicand, invSqrt, scale; - vec_float4 res0, res1, res2, res3; - vec_float4 xx, yy, zz; - vec_uint4 select_x = _VECTORMATH_MASK_0xF000; - vec_uint4 select_y = _VECTORMATH_MASK_0x0F00; - vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; - vec_uint4 select_w = _VECTORMATH_MASK_0x000F; - vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); - - col0 = tfrm.getCol0().get128(); - col1 = tfrm.getCol1().get128(); - col2 = tfrm.getCol2().get128(); - - /* four cases: */ - /* trace > 0 */ - /* else */ - /* xx largest diagonal element */ - /* yy largest diagonal element */ - /* zz largest diagonal element */ - - /* compute quaternion for each case */ - - xx_yy = vec_sel( col0, col1, select_y ); - xx_yy_zz_xx = vec_perm( xx_yy, col2, _VECTORMATH_PERM_XYCX ); - yy_zz_xx_yy = vec_perm( xx_yy, col2, _VECTORMATH_PERM_YCXY ); - zz_xx_yy_zz = vec_perm( xx_yy, col2, _VECTORMATH_PERM_CXYC ); - - diagSum = vec_add( vec_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - diagDiff = vec_sub( vec_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - radicand = vec_add( vec_sel( diagDiff, diagSum, select_w ), ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); - invSqrt = rsqrtf4( radicand ); - - zy_xz_yx = vec_sel( col0, col1, select_z ); - zy_xz_yx = vec_perm( zy_xz_yx, col2, _VECTORMATH_PERM_ZAYX ); - yz_zx_xy = vec_sel( col0, col1, select_x ); - yz_zx_xy = vec_perm( yz_zx_xy, col2, _VECTORMATH_PERM_BZXX ); - - sum = vec_add( zy_xz_yx, yz_zx_xy ); - diff = vec_sub( zy_xz_yx, yz_zx_xy ); - - scale = vec_madd( invSqrt, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), zero ); - res0 = vec_perm( sum, diff, _VECTORMATH_PERM_XZYA ); - res1 = vec_perm( sum, diff, _VECTORMATH_PERM_ZXXB ); - res2 = vec_perm( sum, diff, _VECTORMATH_PERM_YXXC ); - res3 = diff; - res0 = vec_sel( res0, radicand, select_x ); - res1 = vec_sel( res1, radicand, select_y ); - res2 = vec_sel( res2, radicand, select_z ); - res3 = vec_sel( res3, radicand, select_w ); - res0 = vec_madd( res0, vec_splat( scale, 0 ), zero ); - res1 = vec_madd( res1, vec_splat( scale, 1 ), zero ); - res2 = vec_madd( res2, vec_splat( scale, 2 ), zero ); - res3 = vec_madd( res3, vec_splat( scale, 3 ), zero ); - - /* determine case and select answer */ - - xx = vec_splat( col0, 0 ); - yy = vec_splat( col1, 1 ); - zz = vec_splat( col2, 2 ); - res = vec_sel( res0, res1, vec_cmpgt( yy, xx ) ); - res = vec_sel( res, res2, vec_and( vec_cmpgt( zz, xx ), vec_cmpgt( zz, yy ) ) ); - res = vec_sel( res, res3, vec_cmpgt( vec_splat( diagSum, 0 ), zero ) ); - mVec128 = res; -} - -inline const Matrix3 outer( Vector3 tfrm0, Vector3 tfrm1 ) -{ - return Matrix3( - ( tfrm0 * tfrm1.getX( ) ), - ( tfrm0 * tfrm1.getY( ) ), - ( tfrm0 * tfrm1.getZ( ) ) - ); -} - -inline const Matrix4 outer( Vector4 tfrm0, Vector4 tfrm1 ) -{ - return Matrix4( - ( tfrm0 * tfrm1.getX( ) ), - ( tfrm0 * tfrm1.getY( ) ), - ( tfrm0 * tfrm1.getZ( ) ), - ( tfrm0 * tfrm1.getW( ) ) - ); -} - -inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; - vec_float4 xxxx, yyyy, zzzz; - tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); - tmp1 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); - xxxx = vec_splat( vec.get128(), 0 ); - mcol0 = vec_mergeh( tmp0, mat.getCol1().get128() ); - mcol1 = vec_perm( tmp0, mat.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); - mcol2 = vec_perm( tmp1, mat.getCol1().get128(), _VECTORMATH_PERM_XCYX ); - yyyy = vec_splat( vec.get128(), 1 ); - res = vec_madd( mcol0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - zzzz = vec_splat( vec.get128(), 2 ); - res = vec_madd( mcol1, yyyy, res ); - res = vec_madd( mcol2, zzzz, res ); - return Vector3( res ); -} - -inline const Matrix3 crossMatrix( Vector3 vec ) -{ - vec_float4 neg, res0, res1, res2; - neg = negatef4( vec.get128() ); - res0 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_XZBX ); - res1 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_CXXX ); - res2 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_YAXX ); - res0 = vec_andc( res0, (vec_float4)_VECTORMATH_MASK_0xF000 ); - res1 = vec_andc( res1, (vec_float4)_VECTORMATH_MASK_0x0F00 ); - res2 = vec_andc( res2, (vec_float4)_VECTORMATH_MASK_0x00F0 ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ) -{ - return Matrix3( cross( vec, mat.getCol0() ), cross( vec, mat.getCol1() ), cross( vec, mat.getCol2() ) ); -} - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_MAT_AOS_CPP_H +#define _VECTORMATH_MAT_AOS_CPP_H + +namespace Vectormath { +namespace Aos { + +//----------------------------------------------------------------------------- +// Constants +// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + +#define _VECTORMATH_PERM_ZBWX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XCYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_C, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B }) +#define _VECTORMATH_PERM_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W, _VECTORMATH_PERM_C, _VECTORMATH_PERM_D }) +#define _VECTORMATH_PERM_XZBX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_B, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_CXXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_YAXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W, _VECTORMATH_PERM_Z }) +#define _VECTORMATH_PERM_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_B, _VECTORMATH_PERM_W, _VECTORMATH_PERM_D }) +#define _VECTORMATH_PERM_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y }) +#define _VECTORMATH_PERM_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_C, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_ZAYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_BZXX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PERM_XZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A }) +#define _VECTORMATH_PERM_ZXXB ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_B }) +#define _VECTORMATH_PERM_YXXC ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X, _VECTORMATH_PERM_X, _VECTORMATH_PERM_C }) +#define _VECTORMATH_PERM_BBYX ((vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_B, _VECTORMATH_PERM_B, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_X }) +#define _VECTORMATH_PI_OVER_2 1.570796327f + +//----------------------------------------------------------------------------- +// Definitions + +inline Matrix3::Matrix3( const Matrix3 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; +} + +inline Matrix3::Matrix3( float scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); +} + +inline Matrix3::Matrix3( floatInVec scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); +} + +inline Matrix3::Matrix3( Quat unitQuat ) +{ + vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + vec_uint4 select_x = _VECTORMATH_MASK_0xF000; + vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; + xyzw_2 = vec_add( unitQuat.get128(), unitQuat.get128() ); + wwww = vec_splat( unitQuat.get128(), 3 ); + yzxw = vec_perm( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_PERM_YZXW ); + zxyw = vec_perm( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_PERM_ZXYW ); + yzxw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_YZXW ); + zxyw_2 = vec_perm( xyzw_2, xyzw_2, _VECTORMATH_PERM_ZXYW ); + tmp0 = vec_madd( yzxw_2, wwww, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + tmp1 = vec_nmsub( yzxw, yzxw_2, ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); + tmp2 = vec_madd( yzxw, xyzw_2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + tmp0 = vec_madd( zxyw, xyzw_2, tmp0 ); + tmp1 = vec_nmsub( zxyw, zxyw_2, tmp1 ); + tmp2 = vec_nmsub( zxyw_2, wwww, tmp2 ); + tmp3 = vec_sel( tmp0, tmp1, select_x ); + tmp4 = vec_sel( tmp1, tmp2, select_x ); + tmp5 = vec_sel( tmp2, tmp0, select_x ); + mCol0 = Vector3( vec_sel( tmp3, tmp2, select_z ) ); + mCol1 = Vector3( vec_sel( tmp4, tmp0, select_z ) ); + mCol2 = Vector3( vec_sel( tmp5, tmp1, select_z ) ); +} + +inline Matrix3::Matrix3( Vector3 _col0, Vector3 _col1, Vector3 _col2 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; +} + +inline Matrix3 & Matrix3::setCol0( Vector3 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Matrix3 & Matrix3::setCol1( Vector3 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Matrix3 & Matrix3::setCol2( Vector3 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Matrix3 & Matrix3::setCol( int col, Vector3 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Matrix3 & Matrix3::setRow( int row, Vector3 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + return *this; +} + +inline Matrix3 & Matrix3::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline Matrix3 & Matrix3::setElem( int col, int row, floatInVec val ) +{ + Vector3 tmpV3_0; + tmpV3_0 = this->getCol( col ); + tmpV3_0.setElem( row, val ); + this->setCol( col, tmpV3_0 ); + return *this; +} + +inline const floatInVec Matrix3::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector3 Matrix3::getCol0( ) const +{ + return mCol0; +} + +inline const Vector3 Matrix3::getCol1( ) const +{ + return mCol1; +} + +inline const Vector3 Matrix3::getCol2( ) const +{ + return mCol2; +} + +inline const Vector3 Matrix3::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector3 Matrix3::getRow( int row ) const +{ + return Vector3( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ) ); +} + +inline Vector3 & Matrix3::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector3 Matrix3::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Matrix3 & Matrix3::operator =( const Matrix3 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + return *this; +} + +inline const Matrix3 transpose( const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, res0, res1, res2; + tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); + tmp1 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); + res0 = vec_mergeh( tmp0, mat.getCol1().get128() ); + res1 = vec_perm( tmp0, mat.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); + res2 = vec_perm( tmp1, mat.getCol1().get128(), _VECTORMATH_PERM_XCYX ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 inverse( const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp2 = _vmathVfCross( mat.getCol0().get128(), mat.getCol1().get128() ); + tmp0 = _vmathVfCross( mat.getCol1().get128(), mat.getCol2().get128() ); + tmp1 = _vmathVfCross( mat.getCol2().get128(), mat.getCol0().get128() ); + dot = _vmathVfDot3( tmp2, mat.getCol2().get128() ); + dot = vec_splat( dot, 0 ); + invdet = recipf4( dot ); + tmp3 = vec_mergeh( tmp0, tmp2 ); + tmp4 = vec_mergel( tmp0, tmp2 ); + inv0 = vec_mergeh( tmp3, tmp1 ); + inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); + inv0 = vec_madd( inv0, invdet, zero ); + inv1 = vec_madd( inv1, invdet, zero ); + inv2 = vec_madd( inv2, invdet, zero ); + return Matrix3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ) + ); +} + +inline const floatInVec determinant( const Matrix3 & mat ) +{ + return dot( mat.getCol2(), cross( mat.getCol0(), mat.getCol1() ) ); +} + +inline const Matrix3 Matrix3::operator +( const Matrix3 & mat ) const +{ + return Matrix3( + ( mCol0 + mat.mCol0 ), + ( mCol1 + mat.mCol1 ), + ( mCol2 + mat.mCol2 ) + ); +} + +inline const Matrix3 Matrix3::operator -( const Matrix3 & mat ) const +{ + return Matrix3( + ( mCol0 - mat.mCol0 ), + ( mCol1 - mat.mCol1 ), + ( mCol2 - mat.mCol2 ) + ); +} + +inline Matrix3 & Matrix3::operator +=( const Matrix3 & mat ) +{ + *this = *this + mat; + return *this; +} + +inline Matrix3 & Matrix3::operator -=( const Matrix3 & mat ) +{ + *this = *this - mat; + return *this; +} + +inline const Matrix3 Matrix3::operator -( ) const +{ + return Matrix3( + ( -mCol0 ), + ( -mCol1 ), + ( -mCol2 ) + ); +} + +inline const Matrix3 absPerElem( const Matrix3 & mat ) +{ + return Matrix3( + absPerElem( mat.getCol0() ), + absPerElem( mat.getCol1() ), + absPerElem( mat.getCol2() ) + ); +} + +inline const Matrix3 Matrix3::operator *( float scalar ) const +{ + return *this * floatInVec(scalar); +} + +inline const Matrix3 Matrix3::operator *( floatInVec scalar ) const +{ + return Matrix3( + ( mCol0 * scalar ), + ( mCol1 * scalar ), + ( mCol2 * scalar ) + ); +} + +inline Matrix3 & Matrix3::operator *=( float scalar ) +{ + return *this *= floatInVec(scalar); +} + +inline Matrix3 & Matrix3::operator *=( floatInVec scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Matrix3 operator *( float scalar, const Matrix3 & mat ) +{ + return floatInVec(scalar) * mat; +} + +inline const Matrix3 operator *( floatInVec scalar, const Matrix3 & mat ) +{ + return mat * scalar; +} + +inline const Vector3 Matrix3::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec.get128(), 0 ); + yyyy = vec_splat( vec.get128(), 1 ); + zzzz = vec_splat( vec.get128(), 2 ); + res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( mCol1.get128(), yyyy, res ); + res = vec_madd( mCol2.get128(), zzzz, res ); + return Vector3( res ); +} + +inline const Matrix3 Matrix3::operator *( const Matrix3 & mat ) const +{ + return Matrix3( + ( *this * mat.mCol0 ), + ( *this * mat.mCol1 ), + ( *this * mat.mCol2 ) + ); +} + +inline Matrix3 & Matrix3::operator *=( const Matrix3 & mat ) +{ + *this = *this * mat; + return *this; +} + +inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ) +{ + return Matrix3( + mulPerElem( mat0.getCol0(), mat1.getCol0() ), + mulPerElem( mat0.getCol1(), mat1.getCol1() ), + mulPerElem( mat0.getCol2(), mat1.getCol2() ) + ); +} + +inline const Matrix3 Matrix3::identity( ) +{ + return Matrix3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ) + ); +} + +inline const Matrix3 Matrix3::rotationX( float radians ) +{ + return rotationX( floatInVec(radians) ); +} + +inline const Matrix3 Matrix3::rotationX( floatInVec radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + return Matrix3( + Vector3::xAxis( ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 Matrix3::rotationY( float radians ) +{ + return rotationY( floatInVec(radians) ); +} + +inline const Matrix3 Matrix3::rotationY( floatInVec radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + return Matrix3( + Vector3( res0 ), + Vector3::yAxis( ), + Vector3( res2 ) + ); +} + +inline const Matrix3 Matrix3::rotationZ( float radians ) +{ + return rotationZ( floatInVec(radians) ); +} + +inline const Matrix3 Matrix3::rotationZ( floatInVec radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3::zAxis( ) + ); +} + +inline const Matrix3 Matrix3::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + angles = Vector4( radiansXYZ, 0.0f ).get128(); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + return Matrix3( + Vector3( vec_madd( Z0, Y0, zero ) ), + Vector3( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), + Vector3( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ) + ); +} + +inline const Matrix3 Matrix3::rotation( float radians, Vector3 unitVec ) +{ + return rotation( floatInVec(radians), unitVec ); +} + +inline const Matrix3 Matrix3::rotation( floatInVec radians, Vector3 unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + axis = unitVec.get128(); + sincosf4( radians.get128(), &s, &c ); + xxxx = vec_splat( axis, 0 ); + yyyy = vec_splat( axis, 1 ); + zzzz = vec_splat( axis, 2 ); + oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); + axisS = vec_madd( axis, s, zero ); + negAxisS = negatef4( axisS ); + tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); + tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); + tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); + tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); + tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); + tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); + return Matrix3( + Vector3( vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ) ), + Vector3( vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ) ), + Vector3( vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ) ) + ); +} + +inline const Matrix3 Matrix3::rotation( Quat unitQuat ) +{ + return Matrix3( unitQuat ); +} + +inline const Matrix3 Matrix3::scale( Vector3 scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + return Matrix3( + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ) + ); +} + +inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ) +{ + return Matrix3( + ( mat.getCol0() * scaleVec.getX( ) ), + ( mat.getCol1() * scaleVec.getY( ) ), + ( mat.getCol2() * scaleVec.getZ( ) ) + ); +} + +inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ) +{ + return Matrix3( + mulPerElem( mat.getCol0(), scaleVec ), + mulPerElem( mat.getCol1(), scaleVec ), + mulPerElem( mat.getCol2(), scaleVec ) + ); +} + +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ) +{ + return Matrix3( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ) + ); +} + +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, boolInVec select1 ) +{ + return Matrix3( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Matrix3 & mat ) +{ + print( mat.getRow( 0 ) ); + print( mat.getRow( 1 ) ); + print( mat.getRow( 2 ) ); +} + +inline void print( const Matrix3 & mat, const char * name ) +{ + printf("%s:\n", name); + print( mat ); +} + +#endif + +inline Matrix4::Matrix4( const Matrix4 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + mCol3 = mat.mCol3; +} + +inline Matrix4::Matrix4( float scalar ) +{ + mCol0 = Vector4( scalar ); + mCol1 = Vector4( scalar ); + mCol2 = Vector4( scalar ); + mCol3 = Vector4( scalar ); +} + +inline Matrix4::Matrix4( floatInVec scalar ) +{ + mCol0 = Vector4( scalar ); + mCol1 = Vector4( scalar ); + mCol2 = Vector4( scalar ); + mCol3 = Vector4( scalar ); +} + +inline Matrix4::Matrix4( const Transform3 & mat ) +{ + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( mat.getCol3(), 1.0f ); +} + +inline Matrix4::Matrix4( Vector4 _col0, Vector4 _col1, Vector4 _col2, Vector4 _col3 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; + mCol3 = _col3; +} + +inline Matrix4::Matrix4( const Matrix3 & mat, Vector3 translateVec ) +{ + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( translateVec, 1.0f ); +} + +inline Matrix4::Matrix4( Quat unitQuat, Vector3 translateVec ) +{ + Matrix3 mat; + mat = Matrix3( unitQuat ); + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( translateVec, 1.0f ); +} + +inline Matrix4 & Matrix4::setCol0( Vector4 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Matrix4 & Matrix4::setCol1( Vector4 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Matrix4 & Matrix4::setCol2( Vector4 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Matrix4 & Matrix4::setCol3( Vector4 _col3 ) +{ + mCol3 = _col3; + return *this; +} + +inline Matrix4 & Matrix4::setCol( int col, Vector4 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Matrix4 & Matrix4::setRow( int row, Vector4 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + mCol3.setElem( row, vec.getElem( 3 ) ); + return *this; +} + +inline Matrix4 & Matrix4::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline Matrix4 & Matrix4::setElem( int col, int row, floatInVec val ) +{ + Vector4 tmpV3_0; + tmpV3_0 = this->getCol( col ); + tmpV3_0.setElem( row, val ); + this->setCol( col, tmpV3_0 ); + return *this; +} + +inline const floatInVec Matrix4::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector4 Matrix4::getCol0( ) const +{ + return mCol0; +} + +inline const Vector4 Matrix4::getCol1( ) const +{ + return mCol1; +} + +inline const Vector4 Matrix4::getCol2( ) const +{ + return mCol2; +} + +inline const Vector4 Matrix4::getCol3( ) const +{ + return mCol3; +} + +inline const Vector4 Matrix4::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector4 Matrix4::getRow( int row ) const +{ + return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); +} + +inline Vector4 & Matrix4::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector4 Matrix4::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Matrix4 & Matrix4::operator =( const Matrix4 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + mCol3 = mat.mCol3; + return *this; +} + +inline const Matrix4 transpose( const Matrix4 & mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; + tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); + tmp1 = vec_mergeh( mat.getCol1().get128(), mat.getCol3().get128() ); + tmp2 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); + tmp3 = vec_mergel( mat.getCol1().get128(), mat.getCol3().get128() ); + res0 = vec_mergeh( tmp0, tmp1 ); + res1 = vec_mergel( tmp0, tmp1 ); + res2 = vec_mergeh( tmp2, tmp3 ); + res3 = vec_mergel( tmp2, tmp3 ); + return Matrix4( + Vector4( res0 ), + Vector4( res1 ), + Vector4( res2 ), + Vector4( res3 ) + ); +} + +inline const Matrix4 inverse( const Matrix4 & mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vector float in0, in1, in2, in3; + vector float tmp0, tmp1, tmp2, tmp3; + vector float cof0, cof1, cof2, cof3; + vector float t0, t1, t2, t3; + vector float t01, t02, t03, t12, t23; + vector float t1r, t2r; + vector float t01r, t02r, t03r, t12r, t23r; + vector float t1r3, t1r3r; + vector float det, det0, det1, det2, det3, invdet; + vector float vzero = (vector float){0.0}; + in0 = mat.getCol0().get128(); + in1 = mat.getCol1().get128(); + in2 = mat.getCol2().get128(); + in3 = mat.getCol3().get128(); + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ + tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ + tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ + tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ + t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ + t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ + t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ + t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ + t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ + cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ + cof1 = vec_nmsub(t0, t23, vzero); /* -(AGP ECL IOH MKD) */ + t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ + cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ + cof1 = vec_madd(t0, t23r, cof1); /* AOH EKD IGP MCL + cof1 */ + cof1 = vec_sld(cof1, cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ + t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ + t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ + cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + cof3 = vec_madd(t0, t12, vzero); /* ANG EJC IFO MBK */ + t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ + cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + cof3 = vec_nmsub(t0, t12r, cof3); /* cof3 - AFO EBK ING MJC */ + cof3 = vec_sld(cof3, cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ + t1r = vec_sld(t1, t1, 8); /* B F J N */ + t2r = vec_sld(t2, t2, 8); /* K O C G */ + t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ + t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ + cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + cof2 = vec_madd(t0, t1r3, vzero); /* AFP EBL INH MJD */ + t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ + cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + cof2 = vec_nmsub(t0, t1r3r, cof2); /* cof2 - ANH EJD IFP MBL */ + cof2 = vec_sld(cof2, cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ + t01 = vec_madd(t0, t1, vzero); /* AJ EN IB MF */ + t01 = vec_perm(t01, t01, _VECTORMATH_PERM_YXWZ); /* EN AJ MF IB */ + cof2 = vec_nmsub(t3, t01, cof2); /* cof2 - LEN PAJ DMF HIB */ + cof3 = vec_madd(t2r, t01, cof3); /* KEN OAJ CMF GIB + cof3 */ + t01r = vec_sld(t01, t01, 8); /* MF IB EN AJ */ + cof2 = vec_madd(t3, t01r, cof2); /* LMF PIB DEN HAJ + cof2 */ + cof3 = vec_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ + t03 = vec_madd(t0, t3, vzero); /* AL EP ID MH */ + t03 = vec_perm(t03, t03, _VECTORMATH_PERM_YXWZ); /* EP AL MH ID */ + cof1 = vec_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ + cof2 = vec_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ + t03r = vec_sld(t03, t03, 8); /* MH ID EP AL */ + cof1 = vec_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ + cof2 = vec_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ + t02 = vec_madd(t0, t2r, vzero); /* AK EO IC MG */ + t02 = vec_perm(t02, t02, _VECTORMATH_PERM_YXWZ); /* E0 AK MG IC */ + cof1 = vec_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ + cof3 = vec_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ + t02r = vec_sld(t02, t02, 8); /* MG IC EO AK */ + cof1 = vec_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ + cof3 = vec_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ + /* Compute the determinant of the matrix + * + * det = sum_across(t0 * cof0); + * + * We perform a sum across the entire vector so that + * we don't have to splat the result when multiplying the + * cofactors by the inverse of the determinant. + */ + det = vec_madd(t0, cof0, vzero); + det0 = vec_splat(det, 0); + det1 = vec_splat(det, 1); + det2 = vec_splat(det, 2); + det3 = vec_splat(det, 3); + det = vec_add(det0, det1); + det2 = vec_add(det2, det3); + det = vec_add(det, det2); + /* Compute the reciprocal of the determinant. + */ + invdet = recipf4(det); + /* Multiply the cofactors by the reciprocal of the determinant. + */ + return Matrix4( + Vector4( vec_madd(cof0, invdet, vzero) ), + Vector4( vec_madd(cof1, invdet, vzero) ), + Vector4( vec_madd(cof2, invdet, vzero) ), + Vector4( vec_madd(cof3, invdet, vzero) ) + ); +} + +inline const Matrix4 affineInverse( const Matrix4 & mat ) +{ + Transform3 affineMat; + affineMat.setCol0( mat.getCol0().getXYZ( ) ); + affineMat.setCol1( mat.getCol1().getXYZ( ) ); + affineMat.setCol2( mat.getCol2().getXYZ( ) ); + affineMat.setCol3( mat.getCol3().getXYZ( ) ); + return Matrix4( inverse( affineMat ) ); +} + +inline const Matrix4 orthoInverse( const Matrix4 & mat ) +{ + Transform3 affineMat; + affineMat.setCol0( mat.getCol0().getXYZ( ) ); + affineMat.setCol1( mat.getCol1().getXYZ( ) ); + affineMat.setCol2( mat.getCol2().getXYZ( ) ); + affineMat.setCol3( mat.getCol3().getXYZ( ) ); + return Matrix4( orthoInverse( affineMat ) ); +} + +inline const floatInVec determinant( const Matrix4 & mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vector float in0, in1, in2, in3; + vector float tmp0, tmp1, tmp2, tmp3; + vector float cof0; + vector float t0, t1, t2, t3; + vector float t12, t23; + vector float t1r, t2r; + vector float t12r, t23r; + vector float t1r3, t1r3r; + vector float vzero = (vector float){0.0}; + in0 = mat.getCol0().get128(); + in1 = mat.getCol1().get128(); + in2 = mat.getCol2().get128(); + in3 = mat.getCol3().get128(); + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = vec_perm(in0, in1, _VECTORMATH_PERM_XAZC); /* A E C G */ + tmp1 = vec_perm(in2, in3, _VECTORMATH_PERM_XAZC); /* I M K O */ + tmp2 = vec_perm(in0, in1, _VECTORMATH_PERM_YBWD); /* B F D H */ + tmp3 = vec_perm(in2, in3, _VECTORMATH_PERM_YBWD); /* J N L P */ + t0 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_XYAB); /* A E I M */ + t1 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_XYAB); /* J N B F */ + t2 = vec_perm(tmp0, tmp1, _VECTORMATH_PERM_ZWCD); /* C G K O */ + t3 = vec_perm(tmp3, tmp2, _VECTORMATH_PERM_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = vec_madd(t2, t3, vzero); /* CL GP KD OH */ + t23 = vec_perm(t23, t23, _VECTORMATH_PERM_YXWZ); /* GP CL OH KD */ + cof0 = vec_nmsub(t1, t23, vzero); /* -(JGP NCL FOH BKD) */ + t23r = vec_sld(t23, t23, 8); /* OH KD GP CL */ + cof0 = vec_madd(t1, t23r, cof0); /* JOH NKD BGP FCL + cof0 */ + t12 = vec_madd(t1, t2, vzero); /* JC NG BK FO */ + t12 = vec_perm(t12, t12, _VECTORMATH_PERM_YXWZ); /* NG JC FO BK */ + cof0 = vec_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + t12r = vec_sld(t12, t12, 8); /* FO BK NG JC */ + cof0 = vec_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + t1r = vec_sld(t1, t1, 8); /* B F J N */ + t2r = vec_sld(t2, t2, 8); /* K O C G */ + t1r3 = vec_madd(t1r, t3, vzero); /* BL FP JD NH */ + t1r3 = vec_perm(t1r3, t1r3, _VECTORMATH_PERM_YXWZ); /* FP BL NH JD */ + cof0 = vec_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + t1r3r = vec_sld(t1r3, t1r3, 8); /* NH JD FP BL */ + cof0 = vec_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + return floatInVec( _vmathVfDot4(t0,cof0), 0 ); +} + +inline const Matrix4 Matrix4::operator +( const Matrix4 & mat ) const +{ + return Matrix4( + ( mCol0 + mat.mCol0 ), + ( mCol1 + mat.mCol1 ), + ( mCol2 + mat.mCol2 ), + ( mCol3 + mat.mCol3 ) + ); +} + +inline const Matrix4 Matrix4::operator -( const Matrix4 & mat ) const +{ + return Matrix4( + ( mCol0 - mat.mCol0 ), + ( mCol1 - mat.mCol1 ), + ( mCol2 - mat.mCol2 ), + ( mCol3 - mat.mCol3 ) + ); +} + +inline Matrix4 & Matrix4::operator +=( const Matrix4 & mat ) +{ + *this = *this + mat; + return *this; +} + +inline Matrix4 & Matrix4::operator -=( const Matrix4 & mat ) +{ + *this = *this - mat; + return *this; +} + +inline const Matrix4 Matrix4::operator -( ) const +{ + return Matrix4( + ( -mCol0 ), + ( -mCol1 ), + ( -mCol2 ), + ( -mCol3 ) + ); +} + +inline const Matrix4 absPerElem( const Matrix4 & mat ) +{ + return Matrix4( + absPerElem( mat.getCol0() ), + absPerElem( mat.getCol1() ), + absPerElem( mat.getCol2() ), + absPerElem( mat.getCol3() ) + ); +} + +inline const Matrix4 Matrix4::operator *( float scalar ) const +{ + return *this * floatInVec(scalar); +} + +inline const Matrix4 Matrix4::operator *( floatInVec scalar ) const +{ + return Matrix4( + ( mCol0 * scalar ), + ( mCol1 * scalar ), + ( mCol2 * scalar ), + ( mCol3 * scalar ) + ); +} + +inline Matrix4 & Matrix4::operator *=( float scalar ) +{ + return *this *= floatInVec(scalar); +} + +inline Matrix4 & Matrix4::operator *=( floatInVec scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Matrix4 operator *( float scalar, const Matrix4 & mat ) +{ + return floatInVec(scalar) * mat; +} + +inline const Matrix4 operator *( floatInVec scalar, const Matrix4 & mat ) +{ + return mat * scalar; +} + +inline const Vector4 Matrix4::operator *( Vector4 vec ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz, wwww; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( vec.get128(), 0 ); + yyyy = vec_splat( vec.get128(), 1 ); + zzzz = vec_splat( vec.get128(), 2 ); + wwww = vec_splat( vec.get128(), 3 ); + tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); + tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); + tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = vec_madd( mCol3.get128(), wwww, tmp1 ); + res = vec_add( tmp0, tmp1 ); + return Vector4( res ); +} + +inline const Vector4 Matrix4::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec.get128(), 0 ); + yyyy = vec_splat( vec.get128(), 1 ); + zzzz = vec_splat( vec.get128(), 2 ); + res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( mCol1.get128(), yyyy, res ); + res = vec_madd( mCol2.get128(), zzzz, res ); + return Vector4( res ); +} + +inline const Vector4 Matrix4::operator *( Point3 pnt ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( pnt.get128(), 0 ); + yyyy = vec_splat( pnt.get128(), 1 ); + zzzz = vec_splat( pnt.get128(), 2 ); + tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); + tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); + tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = vec_add( mCol3.get128(), tmp1 ); + res = vec_add( tmp0, tmp1 ); + return Vector4( res ); +} + +inline const Matrix4 Matrix4::operator *( const Matrix4 & mat ) const +{ + return Matrix4( + ( *this * mat.mCol0 ), + ( *this * mat.mCol1 ), + ( *this * mat.mCol2 ), + ( *this * mat.mCol3 ) + ); +} + +inline Matrix4 & Matrix4::operator *=( const Matrix4 & mat ) +{ + *this = *this * mat; + return *this; +} + +inline const Matrix4 Matrix4::operator *( const Transform3 & tfrm ) const +{ + return Matrix4( + ( *this * tfrm.getCol0() ), + ( *this * tfrm.getCol1() ), + ( *this * tfrm.getCol2() ), + ( *this * Point3( tfrm.getCol3() ) ) + ); +} + +inline Matrix4 & Matrix4::operator *=( const Transform3 & tfrm ) +{ + *this = *this * tfrm; + return *this; +} + +inline bool Matrix4::operator == (const Matrix4& mat) const +{ + return (vec_all_gt(vec_cmpeq(mCol0.get128(), mat.mCol0.get128()),((vec_uint4){0,0,0,0})) && + vec_all_gt(vec_cmpeq(mCol1.get128(), mat.mCol1.get128()),((vec_uint4){0,0,0,0})) && + vec_all_gt(vec_cmpeq(mCol2.get128(), mat.mCol2.get128()),((vec_uint4){0,0,0,0})) && + vec_all_gt(vec_cmpeq(mCol3.get128(), mat.mCol3.get128()),((vec_uint4){0,0,0,0}))); +} + +inline bool Matrix4::operator != (const Matrix4& mat) const +{ + return !(*this == mat); +} + +inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ) +{ + return Matrix4( + mulPerElem( mat0.getCol0(), mat1.getCol0() ), + mulPerElem( mat0.getCol1(), mat1.getCol1() ), + mulPerElem( mat0.getCol2(), mat1.getCol2() ), + mulPerElem( mat0.getCol3(), mat1.getCol3() ) + ); +} + +inline const Matrix4 Matrix4::identity( ) +{ + return Matrix4( + Vector4::xAxis( ), + Vector4::yAxis( ), + Vector4::zAxis( ), + Vector4::wAxis( ) + ); +} + +inline Matrix4 & Matrix4::setUpper3x3( const Matrix3 & mat3 ) +{ + mCol0.setXYZ( mat3.getCol0() ); + mCol1.setXYZ( mat3.getCol1() ); + mCol2.setXYZ( mat3.getCol2() ); + return *this; +} + +inline const Matrix3 Matrix4::getUpper3x3( ) const +{ + return Matrix3( + mCol0.getXYZ( ), + mCol1.getXYZ( ), + mCol2.getXYZ( ) + ); +} + +inline Matrix4 & Matrix4::setTranslation( Vector3 translateVec ) +{ + mCol3.setXYZ( translateVec ); + return *this; +} + +inline const Vector3 Matrix4::getTranslation( ) const +{ + return mCol3.getXYZ( ); +} + +inline const Matrix4 Matrix4::rotationX( float radians ) +{ + return rotationX( floatInVec(radians) ); +} + +inline const Matrix4 Matrix4::rotationX( floatInVec radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + return Matrix4( + Vector4::xAxis( ), + Vector4( res1 ), + Vector4( res2 ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationY( float radians ) +{ + return rotationY( floatInVec(radians) ); +} + +inline const Matrix4 Matrix4::rotationY( floatInVec radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + return Matrix4( + Vector4( res0 ), + Vector4::yAxis( ), + Vector4( res2 ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationZ( float radians ) +{ + return rotationZ( floatInVec(radians) ); +} + +inline const Matrix4 Matrix4::rotationZ( floatInVec radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + return Matrix4( + Vector4( res0 ), + Vector4( res1 ), + Vector4::zAxis( ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + angles = Vector4( radiansXYZ, 0.0f ).get128(); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + return Matrix4( + Vector4( vec_madd( Z0, Y0, zero ) ), + Vector4( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), + Vector4( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotation( float radians, Vector3 unitVec ) +{ + return rotation( floatInVec(radians), unitVec ); +} + +inline const Matrix4 Matrix4::rotation( floatInVec radians, Vector3 unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + axis = unitVec.get128(); + sincosf4( radians.get128(), &s, &c ); + xxxx = vec_splat( axis, 0 ); + yyyy = vec_splat( axis, 1 ); + zzzz = vec_splat( axis, 2 ); + oneMinusC = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), c ); + axisS = vec_madd( axis, s, zero ); + negAxisS = negatef4( axisS ); + tmp0 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_XZBX ); + tmp1 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_CXXX ); + tmp2 = vec_perm( axisS, negAxisS, _VECTORMATH_PERM_YAXX ); + tmp0 = vec_sel( tmp0, c, _VECTORMATH_MASK_0xF000 ); + tmp1 = vec_sel( tmp1, c, _VECTORMATH_MASK_0x0F00 ); + tmp2 = vec_sel( tmp2, c, _VECTORMATH_MASK_0x00F0 ); + zeroW = (vec_float4)_VECTORMATH_MASK_0x000F; + axis = vec_andc( axis, zeroW ); + tmp0 = vec_andc( tmp0, zeroW ); + tmp1 = vec_andc( tmp1, zeroW ); + tmp2 = vec_andc( tmp2, zeroW ); + return Matrix4( + Vector4( vec_madd( vec_madd( axis, xxxx, zero ), oneMinusC, tmp0 ) ), + Vector4( vec_madd( vec_madd( axis, yyyy, zero ), oneMinusC, tmp1 ) ), + Vector4( vec_madd( vec_madd( axis, zzzz, zero ), oneMinusC, tmp2 ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotation( Quat unitQuat ) +{ + return Matrix4( Transform3::rotation( unitQuat ) ); +} + +inline const Matrix4 Matrix4::scale( Vector3 scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + return Matrix4( + Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), + Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), + Vector4( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ) +{ + return Matrix4( + ( mat.getCol0() * scaleVec.getX( ) ), + ( mat.getCol1() * scaleVec.getY( ) ), + ( mat.getCol2() * scaleVec.getZ( ) ), + mat.getCol3() + ); +} + +inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ) +{ + Vector4 scale4; + scale4 = Vector4( scaleVec, 1.0f ); + return Matrix4( + mulPerElem( mat.getCol0(), scale4 ), + mulPerElem( mat.getCol1(), scale4 ), + mulPerElem( mat.getCol2(), scale4 ), + mulPerElem( mat.getCol3(), scale4 ) + ); +} + +inline const Matrix4 Matrix4::translation( Vector3 translateVec ) +{ + return Matrix4( + Vector4::xAxis( ), + Vector4::yAxis( ), + Vector4::zAxis( ), + Vector4( translateVec, 1.0f ) + ); +} + +inline const Matrix4 Matrix4::lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ) +{ + Matrix4 m4EyeFrame; + Vector3 v3X, v3Y, v3Z; + v3Y = normalize( upVec ); + v3Z = normalize( ( eyePos - lookAtPos ) ); + v3X = normalize( cross( v3Y, v3Z ) ); + v3Y = cross( v3Z, v3X ); + m4EyeFrame = Matrix4( Vector4( v3X ), Vector4( v3Y ), Vector4( v3Z ), Vector4( eyePos ) ); + return orthoInverse( m4EyeFrame ); +} + +inline const Matrix4 Matrix4::perspective( float fovyRadians, float aspect, float zNear, float zFar ) +{ + float f, rangeInv; + vec_float4 zero, col0, col1, col2, col3; + union { vec_float4 v; float s[4]; } tmp; + f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); + rangeInv = 1.0f / ( zNear - zFar ); + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp.v = zero; + tmp.s[0] = f / aspect; + col0 = tmp.v; + tmp.v = zero; + tmp.s[1] = f; + col1 = tmp.v; + tmp.v = zero; + tmp.s[2] = ( zNear + zFar ) * rangeInv; + tmp.s[3] = -1.0f; + col2 = tmp.v; + tmp.v = zero; + tmp.s[2] = zNear * zFar * rangeInv * 2.0f; + col3 = tmp.v; + return Matrix4( + Vector4( col0 ), + Vector4( col1 ), + Vector4( col2 ), + Vector4( col3 ) + ); +} + +inline const Matrix4 Matrix4::frustum( float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff; + vec_float4 diagonal, column, near2; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + union { vec_float4 v; float s[4]; } l, f, r, n, b, t; + l.s[0] = left; + f.s[0] = zFar; + r.s[0] = right; + n.s[0] = zNear; + b.s[0] = bottom; + t.s[0] = top; + lbf = vec_mergeh( l.v, f.v ); + rtn = vec_mergeh( r.v, n.v ); + lbf = vec_mergeh( lbf, b.v ); + rtn = vec_mergeh( rtn, t.v ); + diff = vec_sub( rtn, lbf ); + sum = vec_add( rtn, lbf ); + inv_diff = recipf4( diff ); + near2 = vec_splat( n.v, 0 ); + near2 = vec_add( near2, near2 ); + diagonal = vec_madd( near2, inv_diff, zero ); + column = vec_madd( sum, inv_diff, zero ); + return Matrix4( + Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ) ), + Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ) ), + Vector4( vec_sel( column, ((vec_float4){-1.0f,-1.0f,-1.0f,-1.0f}), _VECTORMATH_MASK_0x000F ) ), + Vector4( vec_sel( zero, vec_madd( diagonal, vec_splat( f.v, 0 ), zero ), _VECTORMATH_MASK_0x00F0 ) ) + ); +} + +inline const Matrix4 Matrix4::orthographic( float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff, neg_inv_diff; + vec_float4 diagonal, column; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + union { vec_float4 v; float s[4]; } l, f, r, n, b, t; + l.s[0] = left; + f.s[0] = zFar; + r.s[0] = right; + n.s[0] = zNear; + b.s[0] = bottom; + t.s[0] = top; + lbf = vec_mergeh( l.v, f.v ); + rtn = vec_mergeh( r.v, n.v ); + lbf = vec_mergeh( lbf, b.v ); + rtn = vec_mergeh( rtn, t.v ); + diff = vec_sub( rtn, lbf ); + sum = vec_add( rtn, lbf ); + inv_diff = recipf4( diff ); + neg_inv_diff = negatef4( inv_diff ); + diagonal = vec_add( inv_diff, inv_diff ); + column = vec_madd( sum, vec_sel( neg_inv_diff, inv_diff, _VECTORMATH_MASK_0x00F0 ), zero ); + return Matrix4( + Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0xF000 ) ), + Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x0F00 ) ), + Vector4( vec_sel( zero, diagonal, _VECTORMATH_MASK_0x00F0 ) ), + Vector4( vec_sel( column, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F ) ) + ); +} + +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ) +{ + return Matrix4( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ), + select( mat0.getCol3(), mat1.getCol3(), select1 ) + ); +} + +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, boolInVec select1 ) +{ + return Matrix4( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ), + select( mat0.getCol3(), mat1.getCol3(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Matrix4 & mat ) +{ + print( mat.getRow( 0 ) ); + print( mat.getRow( 1 ) ); + print( mat.getRow( 2 ) ); + print( mat.getRow( 3 ) ); +} + +inline void print( const Matrix4 & mat, const char * name ) +{ + printf("%s:\n", name); + print( mat ); +} + +#endif + +inline Transform3::Transform3( const Transform3 & tfrm ) +{ + mCol0 = tfrm.mCol0; + mCol1 = tfrm.mCol1; + mCol2 = tfrm.mCol2; + mCol3 = tfrm.mCol3; +} + +inline Transform3::Transform3( float scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); + mCol3 = Vector3( scalar ); +} + +inline Transform3::Transform3( floatInVec scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); + mCol3 = Vector3( scalar ); +} + +inline Transform3::Transform3( Vector3 _col0, Vector3 _col1, Vector3 _col2, Vector3 _col3 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; + mCol3 = _col3; +} + +inline Transform3::Transform3( const Matrix3 & tfrm, Vector3 translateVec ) +{ + this->setUpper3x3( tfrm ); + this->setTranslation( translateVec ); +} + +inline Transform3::Transform3( Quat unitQuat, Vector3 translateVec ) +{ + this->setUpper3x3( Matrix3( unitQuat ) ); + this->setTranslation( translateVec ); +} + +inline Transform3 & Transform3::setCol0( Vector3 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Transform3 & Transform3::setCol1( Vector3 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Transform3 & Transform3::setCol2( Vector3 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Transform3 & Transform3::setCol3( Vector3 _col3 ) +{ + mCol3 = _col3; + return *this; +} + +inline Transform3 & Transform3::setCol( int col, Vector3 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Transform3 & Transform3::setRow( int row, Vector4 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + mCol3.setElem( row, vec.getElem( 3 ) ); + return *this; +} + +inline Transform3 & Transform3::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline Transform3 & Transform3::setElem( int col, int row, floatInVec val ) +{ + Vector3 tmpV3_0; + tmpV3_0 = this->getCol( col ); + tmpV3_0.setElem( row, val ); + this->setCol( col, tmpV3_0 ); + return *this; +} + +inline const floatInVec Transform3::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector3 Transform3::getCol0( ) const +{ + return mCol0; +} + +inline const Vector3 Transform3::getCol1( ) const +{ + return mCol1; +} + +inline const Vector3 Transform3::getCol2( ) const +{ + return mCol2; +} + +inline const Vector3 Transform3::getCol3( ) const +{ + return mCol3; +} + +inline const Vector3 Transform3::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector4 Transform3::getRow( int row ) const +{ + return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); +} + +inline Vector3 & Transform3::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector3 Transform3::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Transform3 & Transform3::operator =( const Transform3 & tfrm ) +{ + mCol0 = tfrm.mCol0; + mCol1 = tfrm.mCol1; + mCol2 = tfrm.mCol2; + mCol3 = tfrm.mCol3; + return *this; +} + +inline const Transform3 inverse( const Transform3 & tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + tmp2 = _vmathVfCross( tfrm.getCol0().get128(), tfrm.getCol1().get128() ); + tmp0 = _vmathVfCross( tfrm.getCol1().get128(), tfrm.getCol2().get128() ); + tmp1 = _vmathVfCross( tfrm.getCol2().get128(), tfrm.getCol0().get128() ); + inv3 = negatef4( tfrm.getCol3().get128() ); + dot = _vmathVfDot3( tmp2, tfrm.getCol2().get128() ); + dot = vec_splat( dot, 0 ); + invdet = recipf4( dot ); + tmp3 = vec_mergeh( tmp0, tmp2 ); + tmp4 = vec_mergel( tmp0, tmp2 ); + inv0 = vec_mergeh( tmp3, tmp1 ); + xxxx = vec_splat( inv3, 0 ); + inv1 = vec_perm( tmp3, tmp1, _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp4, tmp1, _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( inv3, 1 ); + zzzz = vec_splat( inv3, 2 ); + inv3 = vec_madd( inv0, xxxx, zero ); + inv3 = vec_madd( inv1, yyyy, inv3 ); + inv3 = vec_madd( inv2, zzzz, inv3 ); + inv0 = vec_madd( inv0, invdet, zero ); + inv1 = vec_madd( inv1, invdet, zero ); + inv2 = vec_madd( inv2, invdet, zero ); + inv3 = vec_madd( inv3, invdet, zero ); + return Transform3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ), + Vector3( inv3 ) + ); +} + +inline const Transform3 orthoInverse( const Transform3 & tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1; + vec_float4 xxxx, yyyy, zzzz; + tmp0 = vec_mergeh( tfrm.getCol0().get128(), tfrm.getCol2().get128() ); + tmp1 = vec_mergel( tfrm.getCol0().get128(), tfrm.getCol2().get128() ); + inv3 = negatef4( tfrm.getCol3().get128() ); + inv0 = vec_mergeh( tmp0, tfrm.getCol1().get128() ); + xxxx = vec_splat( inv3, 0 ); + inv1 = vec_perm( tmp0, tfrm.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); + inv2 = vec_perm( tmp1, tfrm.getCol1().get128(), _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( inv3, 1 ); + zzzz = vec_splat( inv3, 2 ); + inv3 = vec_madd( inv0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + inv3 = vec_madd( inv1, yyyy, inv3 ); + inv3 = vec_madd( inv2, zzzz, inv3 ); + return Transform3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ), + Vector3( inv3 ) + ); +} + +inline const Transform3 absPerElem( const Transform3 & tfrm ) +{ + return Transform3( + absPerElem( tfrm.getCol0() ), + absPerElem( tfrm.getCol1() ), + absPerElem( tfrm.getCol2() ), + absPerElem( tfrm.getCol3() ) + ); +} + +inline const Vector3 Transform3::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + xxxx = vec_splat( vec.get128(), 0 ); + yyyy = vec_splat( vec.get128(), 1 ); + zzzz = vec_splat( vec.get128(), 2 ); + res = vec_madd( mCol0.get128(), xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( mCol1.get128(), yyyy, res ); + res = vec_madd( mCol2.get128(), zzzz, res ); + return Vector3( res ); +} + +inline const Point3 Transform3::operator *( Point3 pnt ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + xxxx = vec_splat( pnt.get128(), 0 ); + yyyy = vec_splat( pnt.get128(), 1 ); + zzzz = vec_splat( pnt.get128(), 2 ); + tmp0 = vec_madd( mCol0.get128(), xxxx, zero ); + tmp1 = vec_madd( mCol1.get128(), yyyy, zero ); + tmp0 = vec_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = vec_add( mCol3.get128(), tmp1 ); + res = vec_add( tmp0, tmp1 ); + return Point3( res ); +} + +inline const Transform3 Transform3::operator *( const Transform3 & tfrm ) const +{ + return Transform3( + ( *this * tfrm.mCol0 ), + ( *this * tfrm.mCol1 ), + ( *this * tfrm.mCol2 ), + Vector3( ( *this * Point3( tfrm.mCol3 ) ) ) + ); +} + +inline Transform3 & Transform3::operator *=( const Transform3 & tfrm ) +{ + *this = *this * tfrm; + return *this; +} + +inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ) +{ + return Transform3( + mulPerElem( tfrm0.getCol0(), tfrm1.getCol0() ), + mulPerElem( tfrm0.getCol1(), tfrm1.getCol1() ), + mulPerElem( tfrm0.getCol2(), tfrm1.getCol2() ), + mulPerElem( tfrm0.getCol3(), tfrm1.getCol3() ) + ); +} + +inline const Transform3 Transform3::identity( ) +{ + return Transform3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ), + Vector3( 0.0f ) + ); +} + +inline Transform3 & Transform3::setUpper3x3( const Matrix3 & tfrm ) +{ + mCol0 = tfrm.getCol0(); + mCol1 = tfrm.getCol1(); + mCol2 = tfrm.getCol2(); + return *this; +} + +inline const Matrix3 Transform3::getUpper3x3( ) const +{ + return Matrix3( mCol0, mCol1, mCol2 ); +} + +inline Transform3 & Transform3::setTranslation( Vector3 translateVec ) +{ + mCol3 = translateVec; + return *this; +} + +inline const Vector3 Transform3::getTranslation( ) const +{ + return mCol3; +} + +inline const Transform3 Transform3::rotationX( float radians ) +{ + return rotationX( floatInVec(radians) ); +} + +inline const Transform3 Transform3::rotationX( floatInVec radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = _VECTORMATH_MASK_0x0F00; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res1 = vec_sel( zero, c, select_y ); + res1 = vec_sel( res1, s, select_z ); + res2 = vec_sel( zero, negatef4(s), select_y ); + res2 = vec_sel( res2, c, select_z ); + return Transform3( + Vector3::xAxis( ), + Vector3( res1 ), + Vector3( res2 ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationY( float radians ) +{ + return rotationY( floatInVec(radians) ); +} + +inline const Transform3 Transform3::rotationY( floatInVec radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_z = _VECTORMATH_MASK_0x00F0; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, negatef4(s), select_z ); + res2 = vec_sel( zero, s, select_x ); + res2 = vec_sel( res2, c, select_z ); + return Transform3( + Vector3( res0 ), + Vector3::yAxis( ), + Vector3( res2 ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationZ( float radians ) +{ + return rotationZ( floatInVec(radians) ); +} + +inline const Transform3 Transform3::rotationZ( floatInVec radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = _VECTORMATH_MASK_0xF000; + select_y = _VECTORMATH_MASK_0x0F00; + zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + sincosf4( radians.get128(), &s, &c ); + res0 = vec_sel( zero, c, select_x ); + res0 = vec_sel( res0, s, select_y ); + res1 = vec_sel( zero, negatef4(s), select_x ); + res1 = vec_sel( res1, c, select_y ); + return Transform3( + Vector3( res0 ), + Vector3( res1 ), + Vector3::zAxis( ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + angles = Vector4( radiansXYZ, 0.0f ).get128(); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = vec_mergel( c, s ); + Z1 = vec_mergel( negS, c ); + Z1 = vec_andc( Z1, (vec_float4)_VECTORMATH_MASK_0x000F ); + Y0 = vec_perm( negS, c, _VECTORMATH_PERM_BBYX ); + Y1 = vec_perm( c, s, _VECTORMATH_PERM_BBYX ); + X0 = vec_splat( s, 0 ); + X1 = vec_splat( c, 0 ); + tmp = vec_madd( Z0, Y1, zero ); + return Transform3( + Vector3( vec_madd( Z0, Y0, zero ) ), + Vector3( vec_madd( Z1, X1, vec_madd( tmp, X0, zero ) ) ), + Vector3( vec_nmsub( Z1, X0, vec_madd( tmp, X1, zero ) ) ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotation( float radians, Vector3 unitVec ) +{ + return rotation( floatInVec(radians), unitVec ); +} + +inline const Transform3 Transform3::rotation( floatInVec radians, Vector3 unitVec ) +{ + return Transform3( Matrix3::rotation( radians, unitVec ), Vector3( 0.0f ) ); +} + +inline const Transform3 Transform3::rotation( Quat unitQuat ) +{ + return Transform3( Matrix3( unitQuat ), Vector3( 0.0f ) ); +} + +inline const Transform3 Transform3::scale( Vector3 scaleVec ) +{ + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + return Transform3( + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0xF000 ) ), + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x0F00 ) ), + Vector3( vec_sel( zero, scaleVec.get128(), _VECTORMATH_MASK_0x00F0 ) ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ) +{ + return Transform3( + ( tfrm.getCol0() * scaleVec.getX( ) ), + ( tfrm.getCol1() * scaleVec.getY( ) ), + ( tfrm.getCol2() * scaleVec.getZ( ) ), + tfrm.getCol3() + ); +} + +inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ) +{ + return Transform3( + mulPerElem( tfrm.getCol0(), scaleVec ), + mulPerElem( tfrm.getCol1(), scaleVec ), + mulPerElem( tfrm.getCol2(), scaleVec ), + mulPerElem( tfrm.getCol3(), scaleVec ) + ); +} + +inline const Transform3 Transform3::translation( Vector3 translateVec ) +{ + return Transform3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ), + translateVec + ); +} + +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ) +{ + return Transform3( + select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), + select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), + select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), + select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) + ); +} + +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, boolInVec select1 ) +{ + return Transform3( + select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), + select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), + select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), + select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Transform3 & tfrm ) +{ + print( tfrm.getRow( 0 ) ); + print( tfrm.getRow( 1 ) ); + print( tfrm.getRow( 2 ) ); +} + +inline void print( const Transform3 & tfrm, const char * name ) +{ + printf("%s:\n", name); + print( tfrm ); +} + +#endif + +inline Quat::Quat( const Matrix3 & tfrm ) +{ + vec_float4 res; + vec_float4 col0, col1, col2; + vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; + vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; + vec_float4 radicand, invSqrt, scale; + vec_float4 res0, res1, res2, res3; + vec_float4 xx, yy, zz; + vec_uint4 select_x = _VECTORMATH_MASK_0xF000; + vec_uint4 select_y = _VECTORMATH_MASK_0x0F00; + vec_uint4 select_z = _VECTORMATH_MASK_0x00F0; + vec_uint4 select_w = _VECTORMATH_MASK_0x000F; + vec_float4 zero = ((vec_float4){0.0f,0.0f,0.0f,0.0f}); + + col0 = tfrm.getCol0().get128(); + col1 = tfrm.getCol1().get128(); + col2 = tfrm.getCol2().get128(); + + /* four cases: */ + /* trace > 0 */ + /* else */ + /* xx largest diagonal element */ + /* yy largest diagonal element */ + /* zz largest diagonal element */ + + /* compute quaternion for each case */ + + xx_yy = vec_sel( col0, col1, select_y ); + xx_yy_zz_xx = vec_perm( xx_yy, col2, _VECTORMATH_PERM_XYCX ); + yy_zz_xx_yy = vec_perm( xx_yy, col2, _VECTORMATH_PERM_YCXY ); + zz_xx_yy_zz = vec_perm( xx_yy, col2, _VECTORMATH_PERM_CXYC ); + + diagSum = vec_add( vec_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + diagDiff = vec_sub( vec_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + radicand = vec_add( vec_sel( diagDiff, diagSum, select_w ), ((vec_float4){1.0f,1.0f,1.0f,1.0f}) ); + invSqrt = rsqrtf4( radicand ); + + zy_xz_yx = vec_sel( col0, col1, select_z ); + zy_xz_yx = vec_perm( zy_xz_yx, col2, _VECTORMATH_PERM_ZAYX ); + yz_zx_xy = vec_sel( col0, col1, select_x ); + yz_zx_xy = vec_perm( yz_zx_xy, col2, _VECTORMATH_PERM_BZXX ); + + sum = vec_add( zy_xz_yx, yz_zx_xy ); + diff = vec_sub( zy_xz_yx, yz_zx_xy ); + + scale = vec_madd( invSqrt, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), zero ); + res0 = vec_perm( sum, diff, _VECTORMATH_PERM_XZYA ); + res1 = vec_perm( sum, diff, _VECTORMATH_PERM_ZXXB ); + res2 = vec_perm( sum, diff, _VECTORMATH_PERM_YXXC ); + res3 = diff; + res0 = vec_sel( res0, radicand, select_x ); + res1 = vec_sel( res1, radicand, select_y ); + res2 = vec_sel( res2, radicand, select_z ); + res3 = vec_sel( res3, radicand, select_w ); + res0 = vec_madd( res0, vec_splat( scale, 0 ), zero ); + res1 = vec_madd( res1, vec_splat( scale, 1 ), zero ); + res2 = vec_madd( res2, vec_splat( scale, 2 ), zero ); + res3 = vec_madd( res3, vec_splat( scale, 3 ), zero ); + + /* determine case and select answer */ + + xx = vec_splat( col0, 0 ); + yy = vec_splat( col1, 1 ); + zz = vec_splat( col2, 2 ); + res = vec_sel( res0, res1, vec_cmpgt( yy, xx ) ); + res = vec_sel( res, res2, vec_and( vec_cmpgt( zz, xx ), vec_cmpgt( zz, yy ) ) ); + res = vec_sel( res, res3, vec_cmpgt( vec_splat( diagSum, 0 ), zero ) ); + mVec128 = res; +} + +inline const Matrix3 outer( Vector3 tfrm0, Vector3 tfrm1 ) +{ + return Matrix3( + ( tfrm0 * tfrm1.getX( ) ), + ( tfrm0 * tfrm1.getY( ) ), + ( tfrm0 * tfrm1.getZ( ) ) + ); +} + +inline const Matrix4 outer( Vector4 tfrm0, Vector4 tfrm1 ) +{ + return Matrix4( + ( tfrm0 * tfrm1.getX( ) ), + ( tfrm0 * tfrm1.getY( ) ), + ( tfrm0 * tfrm1.getZ( ) ), + ( tfrm0 * tfrm1.getW( ) ) + ); +} + +inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; + vec_float4 xxxx, yyyy, zzzz; + tmp0 = vec_mergeh( mat.getCol0().get128(), mat.getCol2().get128() ); + tmp1 = vec_mergel( mat.getCol0().get128(), mat.getCol2().get128() ); + xxxx = vec_splat( vec.get128(), 0 ); + mcol0 = vec_mergeh( tmp0, mat.getCol1().get128() ); + mcol1 = vec_perm( tmp0, mat.getCol1().get128(), _VECTORMATH_PERM_ZBWX ); + mcol2 = vec_perm( tmp1, mat.getCol1().get128(), _VECTORMATH_PERM_XCYX ); + yyyy = vec_splat( vec.get128(), 1 ); + res = vec_madd( mcol0, xxxx, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + zzzz = vec_splat( vec.get128(), 2 ); + res = vec_madd( mcol1, yyyy, res ); + res = vec_madd( mcol2, zzzz, res ); + return Vector3( res ); +} + +inline const Matrix3 crossMatrix( Vector3 vec ) +{ + vec_float4 neg, res0, res1, res2; + neg = negatef4( vec.get128() ); + res0 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_XZBX ); + res1 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_CXXX ); + res2 = vec_perm( vec.get128(), neg, _VECTORMATH_PERM_YAXX ); + res0 = vec_andc( res0, (vec_float4)_VECTORMATH_MASK_0xF000 ); + res1 = vec_andc( res1, (vec_float4)_VECTORMATH_MASK_0x0F00 ); + res2 = vec_andc( res2, (vec_float4)_VECTORMATH_MASK_0x00F0 ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ) +{ + return Matrix3( cross( vec, mat.getCol0() ), cross( vec, mat.getCol1() ), cross( vec, mat.getCol2() ) ); +} + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/ppu/cpp/quat_aos.h b/common/vectormath/ppu/cpp/quat_aos.h index a99b68bf..2f2f1e2b 100644 --- a/common/vectormath/ppu/cpp/quat_aos.h +++ b/common/vectormath/ppu/cpp/quat_aos.h @@ -1,536 +1,556 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_QUAT_AOS_CPP_H -#define _VECTORMATH_QUAT_AOS_CPP_H -//----------------------------------------------------------------------------- -// Definitions - -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -#endif - -namespace Vectormath { -namespace Aos { - -inline Quat::Quat( float _x, float _y, float _z, float _w ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & - __builtin_constant_p(_z) & __builtin_constant_p(_w)) { - mVec128 = (vec_float4){_x, _y, _z, _w}; - } else { - float *pf = (float *)&mVec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - pf[3] = _w; - } -} - -inline Quat::Quat( floatInVec _x, floatInVec _y, floatInVec _z, floatInVec _w ) -{ - vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); - vec_float4 yw = vec_mergeh( _y.get128(), _w.get128() ); - mVec128 = vec_mergeh( xz, yw ); -} - -inline Quat::Quat( Vector3 xyz, float _w ) -{ - mVec128 = xyz.get128(); - _vmathVfSetElement(mVec128, _w, 3); -} - -inline Quat::Quat( Vector3 xyz, floatInVec _w ) -{ - mVec128 = xyz.get128(); - mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); -} - -inline Quat::Quat( Vector4 vec ) -{ - mVec128 = vec.get128(); -} - -inline Quat::Quat( float scalar ) -{ - mVec128 = floatInVec(scalar).get128(); -} - -inline Quat::Quat( floatInVec scalar ) -{ - mVec128 = scalar.get128(); -} - -inline Quat::Quat( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Quat Quat::identity( ) -{ - return Quat( _VECTORMATH_UNIT_0001 ); -} - -inline const Quat lerp( float t, Quat quat0, Quat quat1 ) -{ - return lerp( floatInVec(t), quat0, quat1 ); -} - -inline const Quat lerp( floatInVec t, Quat quat0, Quat quat1 ) -{ - return ( quat0 + ( ( quat1 - quat0 ) * t ) ); -} - -inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ) -{ - return slerp( floatInVec(t), unitQuat0, unitQuat1 ); -} - -inline const Quat slerp( floatInVec t, Quat unitQuat0, Quat unitQuat1 ) -{ - Quat start; - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot4( unitQuat0.get128(), unitQuat1.get128() ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), cosAngle ); - cosAngle = vec_sel( cosAngle, negatef4( cosAngle ), selectMask ); - start = Quat( vec_sel( unitQuat0.get128(), negatef4( unitQuat0.get128() ), selectMask ) ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = t.get128(); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - return Quat( vec_madd( start.get128(), scale0, vec_madd( unitQuat1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); -} - -inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) -{ - return squad( floatInVec(t), unitQuat0, unitQuat1, unitQuat2, unitQuat3 ); -} - -inline const Quat squad( floatInVec t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) -{ - Quat tmp0, tmp1; - tmp0 = slerp( t, unitQuat0, unitQuat3 ); - tmp1 = slerp( t, unitQuat1, unitQuat2 ); - return slerp( ( ( floatInVec(2.0f) * t ) * ( floatInVec(1.0f) - t ) ), tmp0, tmp1 ); -} - -inline vec_float4 Quat::get128( ) const -{ - return mVec128; -} - -inline Quat & Quat::operator =( Quat quat ) -{ - mVec128 = quat.mVec128; - return *this; -} - -inline Quat & Quat::setXYZ( Vector3 vec ) -{ - mVec128 = vec_sel( vec.get128(), mVec128, _VECTORMATH_MASK_0x000F ); - return *this; -} - -inline const Vector3 Quat::getXYZ( ) const -{ - return Vector3( mVec128 ); -} - -inline Quat & Quat::setX( float _x ) -{ - _vmathVfSetElement(mVec128, _x, 0); - return *this; -} - -inline Quat & Quat::setX( floatInVec _x ) -{ - mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); - return *this; -} - -inline const floatInVec Quat::getX( ) const -{ - return floatInVec( mVec128, 0 ); -} - -inline Quat & Quat::setY( float _y ) -{ - _vmathVfSetElement(mVec128, _y, 1); - return *this; -} - -inline Quat & Quat::setY( floatInVec _y ) -{ - mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); - return *this; -} - -inline const floatInVec Quat::getY( ) const -{ - return floatInVec( mVec128, 1 ); -} - -inline Quat & Quat::setZ( float _z ) -{ - _vmathVfSetElement(mVec128, _z, 2); - return *this; -} - -inline Quat & Quat::setZ( floatInVec _z ) -{ - mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); - return *this; -} - -inline const floatInVec Quat::getZ( ) const -{ - return floatInVec( mVec128, 2 ); -} - -inline Quat & Quat::setW( float _w ) -{ - _vmathVfSetElement(mVec128, _w, 3); - return *this; -} - -inline Quat & Quat::setW( floatInVec _w ) -{ - mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); - return *this; -} - -inline const floatInVec Quat::getW( ) const -{ - return floatInVec( mVec128, 3 ); -} - -inline Quat & Quat::setElem( int idx, float value ) -{ - _vmathVfSetElement(mVec128, value, idx); - return *this; -} - -inline Quat & Quat::setElem( int idx, floatInVec value ) -{ - mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); - return *this; -} - -inline const floatInVec Quat::getElem( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline VecIdx Quat::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline const floatInVec Quat::operator []( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline const Quat Quat::operator +( Quat quat ) const -{ - return Quat( vec_add( mVec128, quat.mVec128 ) ); -} - -inline const Quat Quat::operator -( Quat quat ) const -{ - return Quat( vec_sub( mVec128, quat.mVec128 ) ); -} - -inline const Quat Quat::operator *( float scalar ) const -{ - return *this * floatInVec(scalar); -} - -inline const Quat Quat::operator *( floatInVec scalar ) const -{ - return Quat( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline Quat & Quat::operator +=( Quat quat ) -{ - *this = *this + quat; - return *this; -} - -inline Quat & Quat::operator -=( Quat quat ) -{ - *this = *this - quat; - return *this; -} - -inline Quat & Quat::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline Quat & Quat::operator *=( floatInVec scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Quat Quat::operator /( float scalar ) const -{ - return *this / floatInVec(scalar); -} - -inline const Quat Quat::operator /( floatInVec scalar ) const -{ - return Quat( divf4( mVec128, scalar.get128() ) ); -} - -inline Quat & Quat::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline Quat & Quat::operator /=( floatInVec scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Quat Quat::operator -( ) const -{ - return Quat( negatef4( mVec128 ) ); -} - -inline const Quat operator *( float scalar, Quat quat ) -{ - return floatInVec(scalar) * quat; -} - -inline const Quat operator *( floatInVec scalar, Quat quat ) -{ - return quat * scalar; -} - -inline const floatInVec dot( Quat quat0, Quat quat1 ) -{ - return floatInVec( _vmathVfDot4( quat0.get128(), quat1.get128() ), 0 ); -} - -inline const floatInVec norm( Quat quat ) -{ - return floatInVec( _vmathVfDot4( quat.get128(), quat.get128() ), 0 ); -} - -inline const floatInVec length( Quat quat ) -{ - return floatInVec( sqrtf4(_vmathVfDot4( quat.get128(), quat.get128() )), 0 ); -} - -inline const Quat normalize( Quat quat ) -{ - vec_float4 dot = _vmathVfDot4( quat.get128(), quat.get128() ); - return Quat( vec_madd( quat.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Quat Quat::rotation( Vector3 unitVec0, Vector3 unitVec1 ) -{ - Vector3 crossVec; - vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; - cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); - cosAngle = vec_splat( cosAngle, 0 ); - cosAngleX2Plus2 = vec_madd( cosAngle, ((vec_float4){2.0f,2.0f,2.0f,2.0f}), ((vec_float4){2.0f,2.0f,2.0f,2.0f}) ); - recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); - cosHalfAngleX2 = vec_madd( recipCosHalfAngleX2, cosAngleX2Plus2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - crossVec = cross( unitVec0, unitVec1 ); - res = vec_madd( crossVec.get128(), recipCosHalfAngleX2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_sel( res, vec_madd( cosHalfAngleX2, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), _VECTORMATH_MASK_0x000F ); - return Quat( res ); -} - -inline const Quat Quat::rotation( float radians, Vector3 unitVec ) -{ - return rotation( floatInVec(radians), unitVec ); -} - -inline const Quat Quat::rotation( floatInVec radians, Vector3 unitVec ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( vec_madd( unitVec.get128(), s, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), c, _VECTORMATH_MASK_0x000F ); - return Quat( res ); -} - -inline const Quat Quat::rotationX( float radians ) -{ - return rotationX( floatInVec(radians) ); -} - -inline const Quat Quat::rotationX( floatInVec radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0xF000 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - return Quat( res ); -} - -inline const Quat Quat::rotationY( float radians ) -{ - return rotationY( floatInVec(radians) ); -} - -inline const Quat Quat::rotationY( floatInVec radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x0F00 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - return Quat( res ); -} - -inline const Quat Quat::rotationZ( float radians ) -{ - return rotationZ( floatInVec(radians) ); -} - -inline const Quat Quat::rotationZ( floatInVec radians ) -{ - vec_float4 s, c, angle, res; - angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sincosf4( angle, &s, &c ); - res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x00F0 ); - res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); - return Quat( res ); -} - -inline const Quat Quat::operator *( Quat quat ) const -{ - vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; - vec_float4 product, l_wxyz, r_wxyz, xy, qw; - ldata = mVec128; - rdata = quat.mVec128; - tmp0 = vec_perm( ldata, ldata, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( rdata, rdata, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( ldata, ldata, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( rdata, rdata, _VECTORMATH_PERM_YZXW ); - qv = vec_madd( vec_splat( ldata, 3 ), rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qv = vec_madd( vec_splat( rdata, 3 ), ldata, qv ); - qv = vec_madd( tmp0, tmp1, qv ); - qv = vec_nmsub( tmp2, tmp3, qv ); - product = vec_madd( ldata, rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - l_wxyz = vec_sld( ldata, ldata, 12 ); - r_wxyz = vec_sld( rdata, rdata, 12 ); - qw = vec_nmsub( l_wxyz, r_wxyz, product ); - xy = vec_madd( l_wxyz, r_wxyz, product ); - qw = vec_sub( qw, vec_sld( xy, xy, 8 ) ); - return Quat( vec_sel( qv, qw, _VECTORMATH_MASK_0x000F ) ); -} - -inline Quat & Quat::operator *=( Quat quat ) -{ - *this = *this * quat; - return *this; -} - -inline const Vector3 rotate( Quat quat, Vector3 vec ) -{ - vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; - qdata = quat.get128(); - vdata = vec.get128(); - tmp0 = vec_perm( qdata, qdata, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( vdata, vdata, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( qdata, qdata, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( vdata, vdata, _VECTORMATH_PERM_YZXW ); - wwww = vec_splat( qdata, 3 ); - qv = vec_madd( wwww, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qv = vec_madd( tmp0, tmp1, qv ); - qv = vec_nmsub( tmp2, tmp3, qv ); - product = vec_madd( qdata, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - qw = vec_madd( vec_sld( qdata, qdata, 4 ), vec_sld( vdata, vdata, 4 ), product ); - qw = vec_add( vec_sld( product, product, 8 ), qw ); - tmp1 = vec_perm( qv, qv, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( qv, qv, _VECTORMATH_PERM_YZXW ); - res = vec_madd( vec_splat( qw, 0 ), qdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - res = vec_madd( wwww, qv, res ); - res = vec_madd( tmp0, tmp1, res ); - res = vec_nmsub( tmp2, tmp3, res ); - return Vector3( res ); -} - -inline const Quat conj( Quat quat ) -{ - return Quat( vec_xor( quat.get128(), ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ) ); -} - -inline const Quat select( Quat quat0, Quat quat1, bool select1 ) -{ - return select( quat0, quat1, boolInVec(select1) ); -} - -inline const Quat select( Quat quat0, Quat quat1, boolInVec select1 ) -{ - return Quat( vec_sel( quat0.get128(), quat1.get128(), select1.get128() ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Quat quat ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat.get128(); - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -inline void print( Quat quat, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat.get128(); - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_QUAT_AOS_CPP_H +#define _VECTORMATH_QUAT_AOS_CPP_H +//----------------------------------------------------------------------------- +// Definitions + +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +#endif + +namespace Vectormath { +namespace Aos { + +inline Quat::Quat( float _x, float _y, float _z, float _w ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & + __builtin_constant_p(_z) & __builtin_constant_p(_w)) { + mVec128 = (vec_float4){_x, _y, _z, _w}; + } else { + float *pf = (float *)&mVec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = _w; + } +} + +inline Quat::Quat( floatInVec _x, floatInVec _y, floatInVec _z, floatInVec _w ) +{ + vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); + vec_float4 yw = vec_mergeh( _y.get128(), _w.get128() ); + mVec128 = vec_mergeh( xz, yw ); +} + +inline Quat::Quat( Vector3 xyz, float _w ) +{ + mVec128 = xyz.get128(); + _vmathVfSetElement(mVec128, _w, 3); +} + +inline Quat::Quat( Vector3 xyz, floatInVec _w ) +{ + mVec128 = xyz.get128(); + mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); +} + +inline Quat::Quat( Vector4 vec ) +{ + mVec128 = vec.get128(); +} + +inline Quat::Quat( float scalar ) +{ + mVec128 = floatInVec(scalar).get128(); +} + +inline Quat::Quat( floatInVec scalar ) +{ + mVec128 = scalar.get128(); +} + +inline Quat::Quat( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Quat Quat::identity( ) +{ + return Quat( _VECTORMATH_UNIT_0001 ); +} + +inline const Quat lerp( float t, Quat quat0, Quat quat1 ) +{ + return lerp( floatInVec(t), quat0, quat1 ); +} + +inline const Quat lerp( floatInVec t, Quat quat0, Quat quat1 ) +{ + return ( quat0 + ( ( quat1 - quat0 ) * t ) ); +} + +inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ) +{ + return slerp( floatInVec(t), unitQuat0, unitQuat1 ); +} + +inline const Quat slerp( floatInVec t, Quat unitQuat0, Quat unitQuat1 ) +{ + Quat start; + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot4( unitQuat0.get128(), unitQuat1.get128() ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), cosAngle ); + cosAngle = vec_sel( cosAngle, negatef4( cosAngle ), selectMask ); + start = Quat( vec_sel( unitQuat0.get128(), negatef4( unitQuat0.get128() ), selectMask ) ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = t.get128(); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + return Quat( vec_madd( start.get128(), scale0, vec_madd( unitQuat1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); +} + +inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) +{ + return squad( floatInVec(t), unitQuat0, unitQuat1, unitQuat2, unitQuat3 ); +} + +inline const Quat squad( floatInVec t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) +{ + Quat tmp0, tmp1; + tmp0 = slerp( t, unitQuat0, unitQuat3 ); + tmp1 = slerp( t, unitQuat1, unitQuat2 ); + return slerp( ( ( floatInVec(2.0f) * t ) * ( floatInVec(1.0f) - t ) ), tmp0, tmp1 ); +} + +inline vec_float4 Quat::get128( ) const +{ + return mVec128; +} + +inline Quat & Quat::operator =( Quat quat ) +{ + mVec128 = quat.mVec128; + return *this; +} + +inline Quat & Quat::setXYZ( Vector3 vec ) +{ + mVec128 = vec_sel( vec.get128(), mVec128, _VECTORMATH_MASK_0x000F ); + return *this; +} + +inline const Vector3 Quat::getXYZ( ) const +{ + return Vector3( mVec128 ); +} + +inline Quat & Quat::setX( float _x ) +{ + _vmathVfSetElement(mVec128, _x, 0); + return *this; +} + +inline Quat & Quat::setX( floatInVec _x ) +{ + mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); + return *this; +} + +inline const floatInVec Quat::getX( ) const +{ + return floatInVec( mVec128, 0 ); +} + +inline Quat & Quat::setY( float _y ) +{ + _vmathVfSetElement(mVec128, _y, 1); + return *this; +} + +inline Quat & Quat::setY( floatInVec _y ) +{ + mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); + return *this; +} + +inline const floatInVec Quat::getY( ) const +{ + return floatInVec( mVec128, 1 ); +} + +inline Quat & Quat::setZ( float _z ) +{ + _vmathVfSetElement(mVec128, _z, 2); + return *this; +} + +inline Quat & Quat::setZ( floatInVec _z ) +{ + mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); + return *this; +} + +inline const floatInVec Quat::getZ( ) const +{ + return floatInVec( mVec128, 2 ); +} + +inline Quat & Quat::setW( float _w ) +{ + _vmathVfSetElement(mVec128, _w, 3); + return *this; +} + +inline Quat & Quat::setW( floatInVec _w ) +{ + mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); + return *this; +} + +inline const floatInVec Quat::getW( ) const +{ + return floatInVec( mVec128, 3 ); +} + +inline Quat & Quat::setElem( int idx, float value ) +{ + _vmathVfSetElement(mVec128, value, idx); + return *this; +} + +inline Quat & Quat::setElem( int idx, floatInVec value ) +{ + mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); + return *this; +} + +inline const floatInVec Quat::getElem( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline VecIdx Quat::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline const floatInVec Quat::operator []( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline const Quat Quat::operator +( Quat quat ) const +{ + return Quat( vec_add( mVec128, quat.mVec128 ) ); +} + +inline const Quat Quat::operator -( Quat quat ) const +{ + return Quat( vec_sub( mVec128, quat.mVec128 ) ); +} + +inline const Quat Quat::operator *( float scalar ) const +{ + return *this * floatInVec(scalar); +} + +inline const Quat Quat::operator *( floatInVec scalar ) const +{ + return Quat( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline Quat & Quat::operator +=( Quat quat ) +{ + *this = *this + quat; + return *this; +} + +inline Quat & Quat::operator -=( Quat quat ) +{ + *this = *this - quat; + return *this; +} + +inline Quat & Quat::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline Quat & Quat::operator *=( floatInVec scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Quat Quat::operator /( float scalar ) const +{ + return *this / floatInVec(scalar); +} + +inline const Quat Quat::operator /( floatInVec scalar ) const +{ + return Quat( divf4( mVec128, scalar.get128() ) ); +} + +inline Quat & Quat::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline Quat & Quat::operator /=( floatInVec scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline const Quat Quat::operator -( ) const +{ + return Quat( negatef4( mVec128 ) ); +} + +inline const Quat operator *( float scalar, Quat quat ) +{ + return floatInVec(scalar) * quat; +} + +inline const Quat operator *( floatInVec scalar, Quat quat ) +{ + return quat * scalar; +} + +inline const floatInVec dot( Quat quat0, Quat quat1 ) +{ + return floatInVec( _vmathVfDot4( quat0.get128(), quat1.get128() ), 0 ); +} + +inline const floatInVec norm( Quat quat ) +{ + return floatInVec( _vmathVfDot4( quat.get128(), quat.get128() ), 0 ); +} + +inline const floatInVec length( Quat quat ) +{ + return floatInVec( sqrtf4(_vmathVfDot4( quat.get128(), quat.get128() )), 0 ); +} + +inline const Quat normalize( Quat quat ) +{ + vec_float4 dot = _vmathVfDot4( quat.get128(), quat.get128() ); + return Quat( vec_madd( quat.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Quat Quat::rotation( Vector3 unitVec0, Vector3 unitVec1 ) +{ + Vector3 crossVec; + vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; + cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); + cosAngle = vec_splat( cosAngle, 0 ); + cosAngleX2Plus2 = vec_madd( cosAngle, ((vec_float4){2.0f,2.0f,2.0f,2.0f}), ((vec_float4){2.0f,2.0f,2.0f,2.0f}) ); + recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); + cosHalfAngleX2 = vec_madd( recipCosHalfAngleX2, cosAngleX2Plus2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + crossVec = cross( unitVec0, unitVec1 ); + res = vec_madd( crossVec.get128(), recipCosHalfAngleX2, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_sel( res, vec_madd( cosHalfAngleX2, ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), _VECTORMATH_MASK_0x000F ); + return Quat( res ); +} + +inline const Quat Quat::rotation( float radians, Vector3 unitVec ) +{ + return rotation( floatInVec(radians), unitVec ); +} + +inline const Quat Quat::rotation( floatInVec radians, Vector3 unitVec ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( vec_madd( unitVec.get128(), s, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ), c, _VECTORMATH_MASK_0x000F ); + return Quat( res ); +} + +inline const Quat Quat::rotationX( float radians ) +{ + return rotationX( floatInVec(radians) ); +} + +inline const Quat Quat::rotationX( floatInVec radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0xF000 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + return Quat( res ); +} + +inline const Quat Quat::rotationY( float radians ) +{ + return rotationY( floatInVec(radians) ); +} + +inline const Quat Quat::rotationY( floatInVec radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x0F00 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + return Quat( res ); +} + +inline const Quat Quat::rotationZ( float radians ) +{ + return rotationZ( floatInVec(radians) ); +} + +inline const Quat Quat::rotationZ( floatInVec radians ) +{ + vec_float4 s, c, angle, res; + angle = vec_madd( radians.get128(), ((vec_float4){0.5f,0.5f,0.5f,0.5f}), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sincosf4( angle, &s, &c ); + res = vec_sel( ((vec_float4){0.0f,0.0f,0.0f,0.0f}), s, _VECTORMATH_MASK_0x00F0 ); + res = vec_sel( res, c, _VECTORMATH_MASK_0x000F ); + return Quat( res ); +} + +inline const Quat Quat::operator *( Quat quat ) const +{ + vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; + vec_float4 product, l_wxyz, r_wxyz, xy, qw; + ldata = mVec128; + rdata = quat.mVec128; + tmp0 = vec_perm( ldata, ldata, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( rdata, rdata, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( ldata, ldata, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( rdata, rdata, _VECTORMATH_PERM_YZXW ); + qv = vec_madd( vec_splat( ldata, 3 ), rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qv = vec_madd( vec_splat( rdata, 3 ), ldata, qv ); + qv = vec_madd( tmp0, tmp1, qv ); + qv = vec_nmsub( tmp2, tmp3, qv ); + product = vec_madd( ldata, rdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + l_wxyz = vec_sld( ldata, ldata, 12 ); + r_wxyz = vec_sld( rdata, rdata, 12 ); + qw = vec_nmsub( l_wxyz, r_wxyz, product ); + xy = vec_madd( l_wxyz, r_wxyz, product ); + qw = vec_sub( qw, vec_sld( xy, xy, 8 ) ); + return Quat( vec_sel( qv, qw, _VECTORMATH_MASK_0x000F ) ); +} + +inline Quat & Quat::operator *=( Quat quat ) +{ + *this = *this * quat; + return *this; +} + +inline const Vector3 rotate( Quat quat, Vector3 vec ) +{ + vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; + qdata = quat.get128(); + vdata = vec.get128(); + tmp0 = vec_perm( qdata, qdata, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( vdata, vdata, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( qdata, qdata, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( vdata, vdata, _VECTORMATH_PERM_YZXW ); + wwww = vec_splat( qdata, 3 ); + qv = vec_madd( wwww, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qv = vec_madd( tmp0, tmp1, qv ); + qv = vec_nmsub( tmp2, tmp3, qv ); + product = vec_madd( qdata, vdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + qw = vec_madd( vec_sld( qdata, qdata, 4 ), vec_sld( vdata, vdata, 4 ), product ); + qw = vec_add( vec_sld( product, product, 8 ), qw ); + tmp1 = vec_perm( qv, qv, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( qv, qv, _VECTORMATH_PERM_YZXW ); + res = vec_madd( vec_splat( qw, 0 ), qdata, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + res = vec_madd( wwww, qv, res ); + res = vec_madd( tmp0, tmp1, res ); + res = vec_nmsub( tmp2, tmp3, res ); + return Vector3( res ); +} + +inline const Quat conj( Quat quat ) +{ + return Quat( vec_xor( quat.get128(), ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ) ); +} + +inline const Quat select( Quat quat0, Quat quat1, bool select1 ) +{ + return select( quat0, quat1, boolInVec(select1) ); +} + +inline const Quat select( Quat quat0, Quat quat1, boolInVec select1 ) +{ + return Quat( vec_sel( quat0.get128(), quat1.get128(), select1.get128() ) ); +} + +inline void loadXYZW( Quat & quat, const float * fptr ) +{ + vec_float4 vec0 = vec_ld(0, fptr); + vec_float4 vec1 = vec_ld(16, fptr); + quat = Quat( vec_perm(vec0, vec1, vec_lvsl(0, fptr)) ); +} + +inline void storeXYZW( Quat quat, float * fptr ) +{ + vec_float4 vsrc = quat.get128(); + vec_float4 x = vec_splat(vsrc, 0); + vec_float4 y = vec_splat(vsrc, 1); + vec_float4 z = vec_splat(vsrc, 2); + vec_float4 w = vec_splat(vsrc, 3); + vec_ste(x, 0, fptr); + vec_ste(y, 4, fptr); + vec_ste(z, 8, fptr); + vec_ste(w, 12, fptr); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Quat quat ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat.get128(); + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +inline void print( Quat quat, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat.get128(); + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/ppu/cpp/vec_aos.h b/common/vectormath/ppu/cpp/vec_aos.h index dc1f9849..921a156f 100644 --- a/common/vectormath/ppu/cpp/vec_aos.h +++ b/common/vectormath/ppu/cpp/vec_aos.h @@ -1,1492 +1,1652 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VEC_AOS_CPP_H -#define _VECTORMATH_VEC_AOS_CPP_H -//----------------------------------------------------------------------------- -// Constants -// for permutes words are labeled [x,y,z,w] [a,b,c,d] - -#define _VECTORMATH_PERM_X 0x00010203 -#define _VECTORMATH_PERM_Y 0x04050607 -#define _VECTORMATH_PERM_Z 0x08090a0b -#define _VECTORMATH_PERM_W 0x0c0d0e0f -#define _VECTORMATH_PERM_A 0x10111213 -#define _VECTORMATH_PERM_B 0x14151617 -#define _VECTORMATH_PERM_C 0x18191a1b -#define _VECTORMATH_PERM_D 0x1c1d1e1f -#define _VECTORMATH_PERM_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A } -#define _VECTORMATH_PERM_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B } -#define _VECTORMATH_PERM_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B, _VECTORMATH_PERM_C } -#define _VECTORMATH_PERM_XYAW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_W } -#define _VECTORMATH_PERM_XAZW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W } -#define _VECTORMATH_MASK_0xF000 (vec_uint4){ 0xffffffff, 0, 0, 0 } -#define _VECTORMATH_MASK_0x0F00 (vec_uint4){ 0, 0xffffffff, 0, 0 } -#define _VECTORMATH_MASK_0x00F0 (vec_uint4){ 0, 0, 0xffffffff, 0 } -#define _VECTORMATH_MASK_0x000F (vec_uint4){ 0, 0, 0, 0xffffffff } -#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } -#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } -#define _VECTORMATH_SLERP_TOL 0.999f - -//----------------------------------------------------------------------------- -// Definitions - -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); - return vec_madd( vec_sld( vec0, vec0, 8 ), vec_sld( vec1, vec1, 8 ), result ); -} - -static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); - return vec_add( vec_sld( result, result, 8 ), result ); -} - -static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, result; - tmp0 = vec_perm( vec0, vec0, _VECTORMATH_PERM_YZXW ); - tmp1 = vec_perm( vec1, vec1, _VECTORMATH_PERM_ZXYW ); - tmp2 = vec_perm( vec0, vec0, _VECTORMATH_PERM_ZXYW ); - tmp3 = vec_perm( vec1, vec1, _VECTORMATH_PERM_YZXW ); - result = vec_madd( tmp0, tmp1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); - result = vec_nmsub( tmp2, tmp3, result ); - return result; -} - -static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) -{ - vec_int4 bexp; - vec_uint4 mant, sign, hfloat; - vec_uint4 notZero, isInf; - const vec_uint4 hfloatInf = (vec_uint4){0x00007c00u,0x00007c00u,0x00007c00u,0x00007c00u}; - const vec_uint4 mergeMant = (vec_uint4){0x000003ffu,0x000003ffu,0x000003ffu,0x000003ffu}; - const vec_uint4 mergeSign = (vec_uint4){0x00008000u,0x00008000u,0x00008000u,0x00008000u}; - - sign = vec_sr((vec_uint4)v, (vec_uint4){16,16,16,16}); - mant = vec_sr((vec_uint4)v, (vec_uint4){13,13,13,13}); - bexp = vec_and(vec_sr((vec_int4)v, (vec_uint4){23,23,23,23}), (vec_int4){0xff,0xff,0xff,0xff}); - - notZero = (vec_uint4)vec_cmpgt(bexp, (vec_int4){112,112,112,112}); - isInf = (vec_uint4)vec_cmpgt(bexp, (vec_int4){142,142,142,142}); - - bexp = vec_add(bexp, (vec_int4){-112,-112,-112,-112}); - bexp = vec_sl(bexp, (vec_uint4){10,10,10,10}); - - hfloat = vec_sel((vec_uint4)bexp, mant, mergeMant); - hfloat = vec_sel((vec_uint4){0,0,0,0}, hfloat, notZero); - hfloat = vec_sel(hfloat, hfloatInf, isInf); - hfloat = vec_sel(hfloat, sign, mergeSign); - - return hfloat; -} - -static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) -{ - vec_uint4 hfloat_u, hfloat_v; - const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; - hfloat_u = _vmathVfToHalfFloatsUnpacked(u); - hfloat_v = _vmathVfToHalfFloatsUnpacked(v); - return (vec_ushort8)vec_perm(hfloat_u, hfloat_v, pack); -} - -#ifndef __GNUC__ -#define __builtin_constant_p(x) 0 -#endif - -static inline vec_float4 _vmathVfInsert(vec_float4 dst, vec_float4 src, int slot) -{ -#ifdef __GNUC__ - if (__builtin_constant_p(slot)) { - dst = vec_sld(dst, dst, slot<<2); - dst = vec_sld(dst, src, 4); - if (slot != 3) dst = vec_sld(dst, dst, (3-slot)<<2); - return dst; - } else -#endif - { - vec_uchar16 shiftpattern = vec_lvsr( 0, (float *)(size_t)(slot<<2) ); - vec_uint4 selectmask = (vec_uint4)vec_perm( (vec_uint4){0,0,0,0}, _VECTORMATH_MASK_0xF000, shiftpattern ); - return vec_sel( dst, src, selectmask ); - } -} - -#define _vmathVfGetElement(vec, slot) ((float *)&(vec))[slot] -#ifdef _VECTORMATH_SET_CONSTS_IN_MEM -#define _vmathVfSetElement(vec, scalar, slot) ((float *)&(vec))[slot] = scalar -#else -#define _vmathVfSetElement(vec, scalar, slot) \ -{ \ - if (__builtin_constant_p(scalar)) { \ - (vec) = _vmathVfInsert(vec, (vec_float4){scalar, scalar, scalar, scalar}, slot); \ - } else { \ - ((float *)&(vec))[slot] = scalar; \ - } \ -} -#endif - -static inline vec_float4 _vmathVfSplatScalar(float scalar) -{ - vec_float4 result; - if (__builtin_constant_p(scalar)) { - result = (vec_float4){scalar, scalar, scalar, scalar}; - } else { - result = vec_ld(0, &scalar); - result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); - } - return result; -} - -static inline vec_uint4 _vmathVuiSplatScalar(unsigned int scalar) -{ - vec_uint4 result; - if (__builtin_constant_p(scalar)) { - result = (vec_uint4){scalar, scalar, scalar, scalar}; - } else { - result = vec_ld(0, &scalar); - result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); - } - return result; -} - -#endif - -namespace Vectormath { -namespace Aos { - -#ifdef _VECTORMATH_NO_SCALAR_CAST -inline VecIdx::operator floatInVec() const -{ - return floatInVec(ref, i); -} - -inline float VecIdx::getAsFloat() const -#else -inline VecIdx::operator float() const -#endif -{ - return _vmathVfGetElement(ref, i); -} - -inline float VecIdx::operator =( float scalar ) -{ - _vmathVfSetElement(ref, scalar, i); - return scalar; -} - -inline floatInVec VecIdx::operator =( floatInVec scalar ) -{ - ref = _vmathVfInsert(ref, scalar.get128(), i); - return scalar; -} - -inline floatInVec VecIdx::operator =( const VecIdx& scalar ) -{ - return *this = floatInVec(scalar.ref, scalar.i); -} - -inline floatInVec VecIdx::operator *=( float scalar ) -{ - return *this *= floatInVec(scalar); -} - -inline floatInVec VecIdx::operator *=( floatInVec scalar ) -{ - return *this = floatInVec(ref, i) * scalar; -} - -inline floatInVec VecIdx::operator /=( float scalar ) -{ - return *this /= floatInVec(scalar); -} - -inline floatInVec VecIdx::operator /=( floatInVec scalar ) -{ - return *this = floatInVec(ref, i) / scalar; -} - -inline floatInVec VecIdx::operator +=( float scalar ) -{ - return *this += floatInVec(scalar); -} - -inline floatInVec VecIdx::operator +=( floatInVec scalar ) -{ - return *this = floatInVec(ref, i) + scalar; -} - -inline floatInVec VecIdx::operator -=( float scalar ) -{ - return *this -= floatInVec(scalar); -} - -inline floatInVec VecIdx::operator -=( floatInVec scalar ) -{ - return *this = floatInVec(ref, i) - scalar; -} - -inline Vector3::Vector3( float _x, float _y, float _z ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { - mVec128 = (vec_float4){_x, _y, _z, 0.0f}; - } else { - float *pf = (float *)&mVec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - } -} - -inline Vector3::Vector3( floatInVec _x, floatInVec _y, floatInVec _z ) -{ - vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); - mVec128 = vec_mergeh( xz, _y.get128() ); -} - -inline Vector3::Vector3( Point3 pnt ) -{ - mVec128 = pnt.get128(); -} - -inline Vector3::Vector3( float scalar ) -{ - mVec128 = floatInVec(scalar).get128(); -} - -inline Vector3::Vector3( floatInVec scalar ) -{ - mVec128 = scalar.get128(); -} - -inline Vector3::Vector3( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Vector3 Vector3::xAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_1000 ); -} - -inline const Vector3 Vector3::yAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_0100 ); -} - -inline const Vector3 Vector3::zAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_0010 ); -} - -inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ) -{ - return lerp( floatInVec(t), vec0, vec1 ); -} - -inline const Vector3 lerp( floatInVec t, Vector3 vec0, Vector3 vec1 ) -{ - return ( vec0 + ( ( vec1 - vec0 ) * t ) ); -} - -inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ) -{ - return slerp( floatInVec(t), unitVec0, unitVec1 ); -} - -inline const Vector3 slerp( floatInVec t, Vector3 unitVec0, Vector3 unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = t.get128(); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - return Vector3( vec_madd( unitVec0.get128(), scale0, vec_madd( unitVec1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); -} - -inline vec_float4 Vector3::get128( ) const -{ - return mVec128; -} - -inline void storeXYZ( Vector3 vec, vec_float4 * quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = _VECTORMATH_MASK_0x000F; - dstVec = vec_sel(vec.get128(), dstVec, mask); - *quad = dstVec; -} - -inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = vec_sld( xyzx, yzxy, 12 ); - xyz2 = vec_sld( yzxy, zxyz, 8 ); - xyz3 = vec_sld( zxyz, zxyz, 4 ); - vec0 = Vector3( xyzx ); - vec1 = Vector3( xyz1 ); - vec2 = Vector3( xyz2 ); - vec3 = Vector3( xyz3 ); -} - -inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = vec_perm( vec0.get128(), vec1.get128(), _VECTORMATH_PERM_XYZA ); - yzxy = vec_perm( vec1.get128(), vec2.get128(), _VECTORMATH_PERM_YZAB ); - zxyz = vec_perm( vec2.get128(), vec3.get128(), _VECTORMATH_PERM_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - storeXYZArray( vec0, vec1, vec2, vec3, xyz0 ); - storeXYZArray( vec4, vec5, vec6, vec7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -inline Vector3 & Vector3::operator =( Vector3 vec ) -{ - mVec128 = vec.mVec128; - return *this; -} - -inline Vector3 & Vector3::setX( float _x ) -{ - _vmathVfSetElement(mVec128, _x, 0); - return *this; -} - -inline Vector3 & Vector3::setX( floatInVec _x ) -{ - mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); - return *this; -} - -inline const floatInVec Vector3::getX( ) const -{ - return floatInVec( mVec128, 0 ); -} - -inline Vector3 & Vector3::setY( float _y ) -{ - _vmathVfSetElement(mVec128, _y, 1); - return *this; -} - -inline Vector3 & Vector3::setY( floatInVec _y ) -{ - mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); - return *this; -} - -inline const floatInVec Vector3::getY( ) const -{ - return floatInVec( mVec128, 1 ); -} - -inline Vector3 & Vector3::setZ( float _z ) -{ - _vmathVfSetElement(mVec128, _z, 2); - return *this; -} - -inline Vector3 & Vector3::setZ( floatInVec _z ) -{ - mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); - return *this; -} - -inline const floatInVec Vector3::getZ( ) const -{ - return floatInVec( mVec128, 2 ); -} - -inline Vector3 & Vector3::setElem( int idx, float value ) -{ - _vmathVfSetElement(mVec128, value, idx); - return *this; -} - -inline Vector3 & Vector3::setElem( int idx, floatInVec value ) -{ - mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); - return *this; -} - -inline const floatInVec Vector3::getElem( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline VecIdx Vector3::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline const floatInVec Vector3::operator []( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline const Vector3 Vector3::operator +( Vector3 vec ) const -{ - return Vector3( vec_add( mVec128, vec.mVec128 ) ); -} - -inline const Vector3 Vector3::operator -( Vector3 vec ) const -{ - return Vector3( vec_sub( mVec128, vec.mVec128 ) ); -} - -inline const Point3 Vector3::operator +( Point3 pnt ) const -{ - return Point3( vec_add( mVec128, pnt.get128() ) ); -} - -inline const Vector3 Vector3::operator *( float scalar ) const -{ - return *this * floatInVec(scalar); -} - -inline const Vector3 Vector3::operator *( floatInVec scalar ) const -{ - return Vector3( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline Vector3 & Vector3::operator +=( Vector3 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Vector3 & Vector3::operator -=( Vector3 vec ) -{ - *this = *this - vec; - return *this; -} - -inline Vector3 & Vector3::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline Vector3 & Vector3::operator *=( floatInVec scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Vector3 Vector3::operator /( float scalar ) const -{ - return *this / floatInVec(scalar); -} - -inline const Vector3 Vector3::operator /( floatInVec scalar ) const -{ - return Vector3( divf4( mVec128, scalar.get128() ) ); -} - -inline Vector3 & Vector3::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline Vector3 & Vector3::operator /=( floatInVec scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Vector3 Vector3::operator -( ) const -{ - return Vector3( negatef4( mVec128 ) ); -} - -inline const Vector3 operator *( float scalar, Vector3 vec ) -{ - return floatInVec(scalar) * vec; -} - -inline const Vector3 operator *( floatInVec scalar, Vector3 vec ) -{ - return vec * scalar; -} - -inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( vec_madd( vec0.get128(), vec1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( divf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 recipPerElem( Vector3 vec ) -{ - return Vector3( recipf4( vec.get128() ) ); -} - -inline const Vector3 sqrtPerElem( Vector3 vec ) -{ - return Vector3( sqrtf4( vec.get128() ) ); -} - -inline const Vector3 rsqrtPerElem( Vector3 vec ) -{ - return Vector3( rsqrtf4( vec.get128() ) ); -} - -inline const Vector3 absPerElem( Vector3 vec ) -{ - return Vector3( fabsf4( vec.get128() ) ); -} - -inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( copysignf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( fmaxf4( vec0.get128(), vec1.get128() ) ); -} - -inline const floatInVec maxElem( Vector3 vec ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = fmaxf4( vec_splat( vec.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( fminf4( vec0.get128(), vec1.get128() ) ); -} - -inline const floatInVec minElem( Vector3 vec ) -{ - vec_float4 result; - result = fminf4( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = fminf4( vec_splat( vec.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const floatInVec sum( Vector3 vec ) -{ - vec_float4 result; - result = vec_add( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = vec_add( vec_splat( vec.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const floatInVec dot( Vector3 vec0, Vector3 vec1 ) -{ - return floatInVec( _vmathVfDot3( vec0.get128(), vec1.get128() ), 0 ); -} - -inline const floatInVec lengthSqr( Vector3 vec ) -{ - return floatInVec( _vmathVfDot3( vec.get128(), vec.get128() ), 0 ); -} - -inline const floatInVec length( Vector3 vec ) -{ - return floatInVec( sqrtf4(_vmathVfDot3( vec.get128(), vec.get128() )), 0 ); -} - -inline const Vector3 normalize( Vector3 vec ) -{ - vec_float4 dot = _vmathVfDot3( vec.get128(), vec.get128() ); - dot = vec_splat( dot, 0 ); - return Vector3( vec_madd( vec.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( _vmathVfCross( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ) -{ - return select( vec0, vec1, boolInVec(select1) ); -} - -inline const Vector3 select( Vector3 vec0, Vector3 vec1, boolInVec select1 ) -{ - return Vector3( vec_sel( vec0.get128(), vec1.get128(), select1.get128() ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Vector3 vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -inline void print( Vector3 vec, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -inline Vector4::Vector4( float _x, float _y, float _z, float _w ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & - __builtin_constant_p(_z) & __builtin_constant_p(_w)) { - mVec128 = (vec_float4){_x, _y, _z, _w}; - } else { - float *pf = (float *)&mVec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - pf[3] = _w; - } -} - -inline Vector4::Vector4( floatInVec _x, floatInVec _y, floatInVec _z, floatInVec _w ) -{ - vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); - vec_float4 yw = vec_mergeh( _y.get128(), _w.get128() ); - mVec128 = vec_mergeh( xz, yw ); -} - -inline Vector4::Vector4( Vector3 xyz, float _w ) -{ - mVec128 = xyz.get128(); - _vmathVfSetElement(mVec128, _w, 3); -} - -inline Vector4::Vector4( Vector3 xyz, floatInVec _w ) -{ - mVec128 = xyz.get128(); - mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); -} - -inline Vector4::Vector4( Vector3 vec ) -{ - mVec128 = vec.get128(); - mVec128 = _vmathVfInsert(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), 3); -} - -inline Vector4::Vector4( Point3 pnt ) -{ - mVec128 = pnt.get128(); - mVec128 = _vmathVfInsert(mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), 3); -} - -inline Vector4::Vector4( Quat quat ) -{ - mVec128 = quat.get128(); -} - -inline Vector4::Vector4( float scalar ) -{ - mVec128 = floatInVec(scalar).get128(); -} - -inline Vector4::Vector4( floatInVec scalar ) -{ - mVec128 = scalar.get128(); -} - -inline Vector4::Vector4( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Vector4 Vector4::xAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_1000 ); -} - -inline const Vector4 Vector4::yAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0100 ); -} - -inline const Vector4 Vector4::zAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0010 ); -} - -inline const Vector4 Vector4::wAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0001 ); -} - -inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ) -{ - return lerp( floatInVec(t), vec0, vec1 ); -} - -inline const Vector4 lerp( floatInVec t, Vector4 vec0, Vector4 vec1 ) -{ - return ( vec0 + ( ( vec1 - vec0 ) * t ) ); -} - -inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ) -{ - return slerp( floatInVec(t), unitVec0, unitVec1 ); -} - -inline const Vector4 slerp( floatInVec t, Vector4 unitVec0, Vector4 unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - cosAngle = _vmathVfDot4( unitVec0.get128(), unitVec1.get128() ); - cosAngle = vec_splat( cosAngle, 0 ); - selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); - angle = acosf4( cosAngle ); - tttt = t.get128(); - oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); - angles = vec_mergeh( angles, oneMinusT ); - angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); - sines = sinf4( angles ); - scales = divf4( sines, vec_splat( sines, 0 ) ); - scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); - scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); - return Vector4( vec_madd( unitVec0.get128(), scale0, vec_madd( unitVec1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); -} - -inline vec_float4 Vector4::get128( ) const -{ - return mVec128; -} - -inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ) -{ - twoQuads[0] = _vmath2VfToHalfFloats(vec0.get128(), vec1.get128()); - twoQuads[1] = _vmath2VfToHalfFloats(vec2.get128(), vec3.get128()); -} - -inline Vector4 & Vector4::operator =( Vector4 vec ) -{ - mVec128 = vec.mVec128; - return *this; -} - -inline Vector4 & Vector4::setXYZ( Vector3 vec ) -{ - mVec128 = vec_sel( vec.get128(), mVec128, _VECTORMATH_MASK_0x000F ); - return *this; -} - -inline const Vector3 Vector4::getXYZ( ) const -{ - return Vector3( mVec128 ); -} - -inline Vector4 & Vector4::setX( float _x ) -{ - _vmathVfSetElement(mVec128, _x, 0); - return *this; -} - -inline Vector4 & Vector4::setX( floatInVec _x ) -{ - mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); - return *this; -} - -inline const floatInVec Vector4::getX( ) const -{ - return floatInVec( mVec128, 0 ); -} - -inline Vector4 & Vector4::setY( float _y ) -{ - _vmathVfSetElement(mVec128, _y, 1); - return *this; -} - -inline Vector4 & Vector4::setY( floatInVec _y ) -{ - mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); - return *this; -} - -inline const floatInVec Vector4::getY( ) const -{ - return floatInVec( mVec128, 1 ); -} - -inline Vector4 & Vector4::setZ( float _z ) -{ - _vmathVfSetElement(mVec128, _z, 2); - return *this; -} - -inline Vector4 & Vector4::setZ( floatInVec _z ) -{ - mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); - return *this; -} - -inline const floatInVec Vector4::getZ( ) const -{ - return floatInVec( mVec128, 2 ); -} - -inline Vector4 & Vector4::setW( float _w ) -{ - _vmathVfSetElement(mVec128, _w, 3); - return *this; -} - -inline Vector4 & Vector4::setW( floatInVec _w ) -{ - mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); - return *this; -} - -inline const floatInVec Vector4::getW( ) const -{ - return floatInVec( mVec128, 3 ); -} - -inline Vector4 & Vector4::setElem( int idx, float value ) -{ - _vmathVfSetElement(mVec128, value, idx); - return *this; -} - -inline Vector4 & Vector4::setElem( int idx, floatInVec value ) -{ - mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); - return *this; -} - -inline const floatInVec Vector4::getElem( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline VecIdx Vector4::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline const floatInVec Vector4::operator []( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline const Vector4 Vector4::operator +( Vector4 vec ) const -{ - return Vector4( vec_add( mVec128, vec.mVec128 ) ); -} - -inline const Vector4 Vector4::operator -( Vector4 vec ) const -{ - return Vector4( vec_sub( mVec128, vec.mVec128 ) ); -} - -inline const Vector4 Vector4::operator *( float scalar ) const -{ - return *this * floatInVec(scalar); -} - -inline const Vector4 Vector4::operator *( floatInVec scalar ) const -{ - return Vector4( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline Vector4 & Vector4::operator +=( Vector4 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Vector4 & Vector4::operator -=( Vector4 vec ) -{ - *this = *this - vec; - return *this; -} - -inline Vector4 & Vector4::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline Vector4 & Vector4::operator *=( floatInVec scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Vector4 Vector4::operator /( float scalar ) const -{ - return *this / floatInVec(scalar); -} - -inline const Vector4 Vector4::operator /( floatInVec scalar ) const -{ - return Vector4( divf4( mVec128, scalar.get128() ) ); -} - -inline Vector4 & Vector4::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline Vector4 & Vector4::operator /=( floatInVec scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Vector4 Vector4::operator -( ) const -{ - return Vector4( negatef4( mVec128 ) ); -} - -inline const Vector4 operator *( float scalar, Vector4 vec ) -{ - return floatInVec(scalar) * vec; -} - -inline const Vector4 operator *( floatInVec scalar, Vector4 vec ) -{ - return vec * scalar; -} - -inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( vec_madd( vec0.get128(), vec1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( divf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector4 recipPerElem( Vector4 vec ) -{ - return Vector4( recipf4( vec.get128() ) ); -} - -inline const Vector4 sqrtPerElem( Vector4 vec ) -{ - return Vector4( sqrtf4( vec.get128() ) ); -} - -inline const Vector4 rsqrtPerElem( Vector4 vec ) -{ - return Vector4( rsqrtf4( vec.get128() ) ); -} - -inline const Vector4 absPerElem( Vector4 vec ) -{ - return Vector4( fabsf4( vec.get128() ) ); -} - -inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( copysignf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( fmaxf4( vec0.get128(), vec1.get128() ) ); -} - -inline const floatInVec maxElem( Vector4 vec ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = fmaxf4( vec_splat( vec.get128(), 2 ), result ); - result = fmaxf4( vec_splat( vec.get128(), 3 ), result ); - return floatInVec( result, 0 ); -} - -inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( fminf4( vec0.get128(), vec1.get128() ) ); -} - -inline const floatInVec minElem( Vector4 vec ) -{ - vec_float4 result; - result = fminf4( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = fminf4( vec_splat( vec.get128(), 2 ), result ); - result = fminf4( vec_splat( vec.get128(), 3 ), result ); - return floatInVec( result, 0 ); -} - -inline const floatInVec sum( Vector4 vec ) -{ - vec_float4 result; - result = vec_add( vec_splat( vec.get128(), 1 ), vec.get128() ); - result = vec_add( vec_splat( vec.get128(), 2 ), result ); - result = vec_add( vec_splat( vec.get128(), 3 ), result ); - return floatInVec( result, 0 ); -} - -inline const floatInVec dot( Vector4 vec0, Vector4 vec1 ) -{ - return floatInVec( _vmathVfDot4( vec0.get128(), vec1.get128() ), 0 ); -} - -inline const floatInVec lengthSqr( Vector4 vec ) -{ - return floatInVec( _vmathVfDot4( vec.get128(), vec.get128() ), 0 ); -} - -inline const floatInVec length( Vector4 vec ) -{ - return floatInVec( sqrtf4(_vmathVfDot4( vec.get128(), vec.get128() )), 0 ); -} - -inline const Vector4 normalize( Vector4 vec ) -{ - vec_float4 dot = _vmathVfDot4( vec.get128(), vec.get128() ); - return Vector4( vec_madd( vec.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ) -{ - return select( vec0, vec1, boolInVec(select1) ); -} - -inline const Vector4 select( Vector4 vec0, Vector4 vec1, boolInVec select1 ) -{ - return Vector4( vec_sel( vec0.get128(), vec1.get128(), select1.get128() ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Vector4 vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -inline void print( Vector4 vec, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -inline Point3::Point3( float _x, float _y, float _z ) -{ - if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { - mVec128 = (vec_float4){_x, _y, _z, 0.0f}; - } else { - float *pf = (float *)&mVec128; - pf[0] = _x; - pf[1] = _y; - pf[2] = _z; - } -} - -inline Point3::Point3( floatInVec _x, floatInVec _y, floatInVec _z ) -{ - vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); - mVec128 = vec_mergeh( xz, _y.get128() ); -} - -inline Point3::Point3( Vector3 vec ) -{ - mVec128 = vec.get128(); -} - -inline Point3::Point3( float scalar ) -{ - mVec128 = floatInVec(scalar).get128(); -} - -inline Point3::Point3( floatInVec scalar ) -{ - mVec128 = scalar.get128(); -} - -inline Point3::Point3( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ) -{ - return lerp( floatInVec(t), pnt0, pnt1 ); -} - -inline const Point3 lerp( floatInVec t, Point3 pnt0, Point3 pnt1 ) -{ - return ( pnt0 + ( ( pnt1 - pnt0 ) * t ) ); -} - -inline vec_float4 Point3::get128( ) const -{ - return mVec128; -} - -inline void storeXYZ( Point3 pnt, vec_float4 * quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = _VECTORMATH_MASK_0x000F; - dstVec = vec_sel(pnt.get128(), dstVec, mask); - *quad = dstVec; -} - -inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = vec_sld( xyzx, yzxy, 12 ); - xyz2 = vec_sld( yzxy, zxyz, 8 ); - xyz3 = vec_sld( zxyz, zxyz, 4 ); - pnt0 = Point3( xyzx ); - pnt1 = Point3( xyz1 ); - pnt2 = Point3( xyz2 ); - pnt3 = Point3( xyz3 ); -} - -inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = vec_perm( pnt0.get128(), pnt1.get128(), _VECTORMATH_PERM_XYZA ); - yzxy = vec_perm( pnt1.get128(), pnt2.get128(), _VECTORMATH_PERM_YZAB ); - zxyz = vec_perm( pnt2.get128(), pnt3.get128(), _VECTORMATH_PERM_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - storeXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); - storeXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -inline Point3 & Point3::operator =( Point3 pnt ) -{ - mVec128 = pnt.mVec128; - return *this; -} - -inline Point3 & Point3::setX( float _x ) -{ - _vmathVfSetElement(mVec128, _x, 0); - return *this; -} - -inline Point3 & Point3::setX( floatInVec _x ) -{ - mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); - return *this; -} - -inline const floatInVec Point3::getX( ) const -{ - return floatInVec( mVec128, 0 ); -} - -inline Point3 & Point3::setY( float _y ) -{ - _vmathVfSetElement(mVec128, _y, 1); - return *this; -} - -inline Point3 & Point3::setY( floatInVec _y ) -{ - mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); - return *this; -} - -inline const floatInVec Point3::getY( ) const -{ - return floatInVec( mVec128, 1 ); -} - -inline Point3 & Point3::setZ( float _z ) -{ - _vmathVfSetElement(mVec128, _z, 2); - return *this; -} - -inline Point3 & Point3::setZ( floatInVec _z ) -{ - mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); - return *this; -} - -inline const floatInVec Point3::getZ( ) const -{ - return floatInVec( mVec128, 2 ); -} - -inline Point3 & Point3::setElem( int idx, float value ) -{ - _vmathVfSetElement(mVec128, value, idx); - return *this; -} - -inline Point3 & Point3::setElem( int idx, floatInVec value ) -{ - mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); - return *this; -} - -inline const floatInVec Point3::getElem( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline VecIdx Point3::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline const floatInVec Point3::operator []( int idx ) const -{ - return floatInVec( mVec128, idx ); -} - -inline const Vector3 Point3::operator -( Point3 pnt ) const -{ - return Vector3( vec_sub( mVec128, pnt.mVec128 ) ); -} - -inline const Point3 Point3::operator +( Vector3 vec ) const -{ - return Point3( vec_add( mVec128, vec.get128() ) ); -} - -inline const Point3 Point3::operator -( Vector3 vec ) const -{ - return Point3( vec_sub( mVec128, vec.get128() ) ); -} - -inline Point3 & Point3::operator +=( Vector3 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Point3 & Point3::operator -=( Vector3 vec ) -{ - *this = *this - vec; - return *this; -} - -inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( vec_madd( pnt0.get128(), pnt1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); -} - -inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( divf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const Point3 recipPerElem( Point3 pnt ) -{ - return Point3( recipf4( pnt.get128() ) ); -} - -inline const Point3 sqrtPerElem( Point3 pnt ) -{ - return Point3( sqrtf4( pnt.get128() ) ); -} - -inline const Point3 rsqrtPerElem( Point3 pnt ) -{ - return Point3( rsqrtf4( pnt.get128() ) ); -} - -inline const Point3 absPerElem( Point3 pnt ) -{ - return Point3( fabsf4( pnt.get128() ) ); -} - -inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( copysignf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( fmaxf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const floatInVec maxElem( Point3 pnt ) -{ - vec_float4 result; - result = fmaxf4( vec_splat( pnt.get128(), 1 ), pnt.get128() ); - result = fmaxf4( vec_splat( pnt.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( fminf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const floatInVec minElem( Point3 pnt ) -{ - vec_float4 result; - result = fminf4( vec_splat( pnt.get128(), 1 ), pnt.get128() ); - result = fminf4( vec_splat( pnt.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const floatInVec sum( Point3 pnt ) -{ - vec_float4 result; - result = vec_add( vec_splat( pnt.get128(), 1 ), pnt.get128() ); - result = vec_add( vec_splat( pnt.get128(), 2 ), result ); - return floatInVec( result, 0 ); -} - -inline const Point3 scale( Point3 pnt, float scaleVal ) -{ - return scale( pnt, floatInVec( scaleVal ) ); -} - -inline const Point3 scale( Point3 pnt, floatInVec scaleVal ) -{ - return mulPerElem( pnt, Point3( scaleVal ) ); -} - -inline const Point3 scale( Point3 pnt, Vector3 scaleVec ) -{ - return mulPerElem( pnt, Point3( scaleVec ) ); -} - -inline const floatInVec projection( Point3 pnt, Vector3 unitVec ) -{ - return floatInVec( _vmathVfDot3( pnt.get128(), unitVec.get128() ), 0 ); -} - -inline const floatInVec distSqrFromOrigin( Point3 pnt ) -{ - return lengthSqr( Vector3( pnt ) ); -} - -inline const floatInVec distFromOrigin( Point3 pnt ) -{ - return length( Vector3( pnt ) ); -} - -inline const floatInVec distSqr( Point3 pnt0, Point3 pnt1 ) -{ - return lengthSqr( ( pnt1 - pnt0 ) ); -} - -inline const floatInVec dist( Point3 pnt0, Point3 pnt1 ) -{ - return length( ( pnt1 - pnt0 ) ); -} - -inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ) -{ - return select( pnt0, pnt1, boolInVec(select1) ); -} - -inline const Point3 select( Point3 pnt0, Point3 pnt1, boolInVec select1 ) -{ - return Point3( vec_sel( pnt0.get128(), pnt1.get128(), select1.get128() ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Point3 pnt ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt.get128(); - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -inline void print( Point3 pnt, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt.get128(); - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VEC_AOS_CPP_H +#define _VECTORMATH_VEC_AOS_CPP_H +//----------------------------------------------------------------------------- +// Constants +// for permutes words are labeled [x,y,z,w] [a,b,c,d] + +#define _VECTORMATH_PERM_X 0x00010203 +#define _VECTORMATH_PERM_Y 0x04050607 +#define _VECTORMATH_PERM_Z 0x08090a0b +#define _VECTORMATH_PERM_W 0x0c0d0e0f +#define _VECTORMATH_PERM_A 0x10111213 +#define _VECTORMATH_PERM_B 0x14151617 +#define _VECTORMATH_PERM_C 0x18191a1b +#define _VECTORMATH_PERM_D 0x1c1d1e1f +#define _VECTORMATH_PERM_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A } +#define _VECTORMATH_PERM_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_X, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Y, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B } +#define _VECTORMATH_PERM_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_Z, _VECTORMATH_PERM_A, _VECTORMATH_PERM_B, _VECTORMATH_PERM_C } +#define _VECTORMATH_PERM_XYAW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_Y, _VECTORMATH_PERM_A, _VECTORMATH_PERM_W } +#define _VECTORMATH_PERM_XAZW (vec_uchar16)(vec_uint4){ _VECTORMATH_PERM_X, _VECTORMATH_PERM_A, _VECTORMATH_PERM_Z, _VECTORMATH_PERM_W } +#define _VECTORMATH_MASK_0xF000 (vec_uint4){ 0xffffffff, 0, 0, 0 } +#define _VECTORMATH_MASK_0x0F00 (vec_uint4){ 0, 0xffffffff, 0, 0 } +#define _VECTORMATH_MASK_0x00F0 (vec_uint4){ 0, 0, 0xffffffff, 0 } +#define _VECTORMATH_MASK_0x000F (vec_uint4){ 0, 0, 0, 0xffffffff } +#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } +#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } +#define _VECTORMATH_SLERP_TOL 0.999f + +//----------------------------------------------------------------------------- +// Definitions + +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); + return vec_madd( vec_sld( vec0, vec0, 8 ), vec_sld( vec1, vec1, 8 ), result ); +} + +static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = vec_madd( vec0, vec1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_madd( vec_sld( vec0, vec0, 4 ), vec_sld( vec1, vec1, 4 ), result ); + return vec_add( vec_sld( result, result, 8 ), result ); +} + +static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, result; + tmp0 = vec_perm( vec0, vec0, _VECTORMATH_PERM_YZXW ); + tmp1 = vec_perm( vec1, vec1, _VECTORMATH_PERM_ZXYW ); + tmp2 = vec_perm( vec0, vec0, _VECTORMATH_PERM_ZXYW ); + tmp3 = vec_perm( vec1, vec1, _VECTORMATH_PERM_YZXW ); + result = vec_madd( tmp0, tmp1, (vec_float4){0.0f,0.0f,0.0f,0.0f} ); + result = vec_nmsub( tmp2, tmp3, result ); + return result; +} + +static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) +{ + vec_int4 bexp; + vec_uint4 mant, sign, hfloat; + vec_uint4 notZero, isInf; + const vec_uint4 hfloatInf = (vec_uint4){0x00007c00u,0x00007c00u,0x00007c00u,0x00007c00u}; + const vec_uint4 mergeMant = (vec_uint4){0x000003ffu,0x000003ffu,0x000003ffu,0x000003ffu}; + const vec_uint4 mergeSign = (vec_uint4){0x00008000u,0x00008000u,0x00008000u,0x00008000u}; + + sign = vec_sr((vec_uint4)v, (vec_uint4){16,16,16,16}); + mant = vec_sr((vec_uint4)v, (vec_uint4){13,13,13,13}); + bexp = vec_and(vec_sr((vec_int4)v, (vec_uint4){23,23,23,23}), (vec_int4){0xff,0xff,0xff,0xff}); + + notZero = (vec_uint4)vec_cmpgt(bexp, (vec_int4){112,112,112,112}); + isInf = (vec_uint4)vec_cmpgt(bexp, (vec_int4){142,142,142,142}); + + bexp = vec_add(bexp, (vec_int4){-112,-112,-112,-112}); + bexp = vec_sl(bexp, (vec_uint4){10,10,10,10}); + + hfloat = vec_sel((vec_uint4)bexp, mant, mergeMant); + hfloat = vec_sel((vec_uint4){0,0,0,0}, hfloat, notZero); + hfloat = vec_sel(hfloat, hfloatInf, isInf); + hfloat = vec_sel(hfloat, sign, mergeSign); + + return hfloat; +} + +static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) +{ + vec_uint4 hfloat_u, hfloat_v; + const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; + hfloat_u = _vmathVfToHalfFloatsUnpacked(u); + hfloat_v = _vmathVfToHalfFloatsUnpacked(v); + return (vec_ushort8)vec_perm(hfloat_u, hfloat_v, pack); +} + +#ifndef __GNUC__ +#define __builtin_constant_p(x) 0 +#endif + +static inline vec_float4 _vmathVfInsert(vec_float4 dst, vec_float4 src, int slot) +{ +#ifdef __GNUC__ + if (__builtin_constant_p(slot)) { + dst = vec_sld(dst, dst, slot<<2); + dst = vec_sld(dst, src, 4); + if (slot != 3) dst = vec_sld(dst, dst, (3-slot)<<2); + return dst; + } else +#endif + { + vec_uchar16 shiftpattern = vec_lvsr( 0, (float *)(size_t)(slot<<2) ); + vec_uint4 selectmask = (vec_uint4)vec_perm( (vec_uint4){0,0,0,0}, _VECTORMATH_MASK_0xF000, shiftpattern ); + return vec_sel( dst, src, selectmask ); + } +} + +#define _vmathVfGetElement(vec, slot) ((float *)&(vec))[slot] +#ifdef _VECTORMATH_SET_CONSTS_IN_MEM +#define _vmathVfSetElement(vec, scalar, slot) ((float *)&(vec))[slot] = scalar +#else +#define _vmathVfSetElement(vec, scalar, slot) \ +{ \ + if (__builtin_constant_p(scalar)) { \ + (vec) = _vmathVfInsert(vec, (vec_float4){scalar, scalar, scalar, scalar}, slot); \ + } else { \ + ((float *)&(vec))[slot] = scalar; \ + } \ +} +#endif + +static inline vec_float4 _vmathVfSplatScalar(float scalar) +{ + vec_float4 result; + if (__builtin_constant_p(scalar)) { + result = (vec_float4){scalar, scalar, scalar, scalar}; + } else { + result = vec_ld(0, &scalar); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); + } + return result; +} + +static inline vec_uint4 _vmathVuiSplatScalar(unsigned int scalar) +{ + vec_uint4 result; + if (__builtin_constant_p(scalar)) { + result = (vec_uint4){scalar, scalar, scalar, scalar}; + } else { + result = vec_ld(0, &scalar); + result = vec_splat(vec_perm(result, result, vec_lvsl(0, &scalar)), 0); + } + return result; +} + +#endif + +namespace Vectormath { +namespace Aos { + +#ifdef _VECTORMATH_NO_SCALAR_CAST +inline VecIdx::operator floatInVec() const +{ + return floatInVec(ref, i); +} + +inline float VecIdx::getAsFloat() const +#else +inline VecIdx::operator float() const +#endif +{ + return _vmathVfGetElement(ref, i); +} + +inline float VecIdx::operator =( float scalar ) +{ + _vmathVfSetElement(ref, scalar, i); + return scalar; +} + +inline floatInVec VecIdx::operator =( floatInVec scalar ) +{ + ref = _vmathVfInsert(ref, scalar.get128(), i); + return scalar; +} + +inline floatInVec VecIdx::operator =( const VecIdx& scalar ) +{ + return *this = floatInVec(scalar.ref, scalar.i); +} + +inline floatInVec VecIdx::operator *=( float scalar ) +{ + return *this *= floatInVec(scalar); +} + +inline floatInVec VecIdx::operator *=( floatInVec scalar ) +{ + return *this = floatInVec(ref, i) * scalar; +} + +inline floatInVec VecIdx::operator /=( float scalar ) +{ + return *this /= floatInVec(scalar); +} + +inline floatInVec VecIdx::operator /=( floatInVec scalar ) +{ + return *this = floatInVec(ref, i) / scalar; +} + +inline floatInVec VecIdx::operator +=( float scalar ) +{ + return *this += floatInVec(scalar); +} + +inline floatInVec VecIdx::operator +=( floatInVec scalar ) +{ + return *this = floatInVec(ref, i) + scalar; +} + +inline floatInVec VecIdx::operator -=( float scalar ) +{ + return *this -= floatInVec(scalar); +} + +inline floatInVec VecIdx::operator -=( floatInVec scalar ) +{ + return *this = floatInVec(ref, i) - scalar; +} + +inline Vector3::Vector3( float _x, float _y, float _z ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { + mVec128 = (vec_float4){_x, _y, _z, 0.0f}; + } else { + float *pf = (float *)&mVec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = 0.0f; + } +} + +inline Vector3::Vector3( floatInVec _x, floatInVec _y, floatInVec _z ) +{ + vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); + vec_float4 yw = vec_mergeh( _y.get128(), ((vec_float4){0.0f, 0.0f, 0.0f, 0.0f})); + mVec128 = vec_mergeh( xz, yw ); +} + +inline Vector3::Vector3( Point3 pnt ) +{ + mVec128 = pnt.get128(); +} + +inline Vector3::Vector3( float scalar ) +{ + mVec128 = floatInVec(scalar).get128(); +} + +inline Vector3::Vector3( floatInVec scalar ) +{ + mVec128 = scalar.get128(); +} + +inline Vector3::Vector3( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Vector3 Vector3::xAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_1000 ); +} + +inline const Vector3 Vector3::yAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_0100 ); +} + +inline const Vector3 Vector3::zAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_0010 ); +} + +inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ) +{ + return lerp( floatInVec(t), vec0, vec1 ); +} + +inline const Vector3 lerp( floatInVec t, Vector3 vec0, Vector3 vec1 ) +{ + return ( vec0 + ( ( vec1 - vec0 ) * t ) ); +} + +inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ) +{ + return slerp( floatInVec(t), unitVec0, unitVec1 ); +} + +inline const Vector3 slerp( floatInVec t, Vector3 unitVec0, Vector3 unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = t.get128(); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + return Vector3( vec_madd( unitVec0.get128(), scale0, vec_madd( unitVec1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); +} + +inline vec_float4 Vector3::get128( ) const +{ + return mVec128; +} + +inline void loadXYZ( Vector3 & vec, const vec_float4 * quad ) +{ + vec = Vector3( *quad ); +} + +inline void storeXYZ( Vector3 vec, vec_float4 * quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = _VECTORMATH_MASK_0x000F; + dstVec = vec_sel(vec.get128(), dstVec, mask); + *quad = dstVec; +} + +inline void loadXYZ( Vector3 & vec, const float * fptr ) +{ + vec_float4 vec0 = vec_ld(0, fptr); + vec_float4 vec1 = vec_ld(16, fptr); + vec = Vector3( vec_perm(vec0, vec1, vec_lvsl(0, fptr)) ); +} + +inline void storeXYZ( Vector3 vec, float * fptr ) +{ + vec_float4 vsrc = vec.get128(); + vec_float4 x = vec_splat(vsrc, 0); + vec_float4 y = vec_splat(vsrc, 1); + vec_float4 z = vec_splat(vsrc, 2); + vec_ste(x, 0, fptr); + vec_ste(y, 4, fptr); + vec_ste(z, 8, fptr); +} + +inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = vec_sld( xyzx, yzxy, 12 ); + xyz2 = vec_sld( yzxy, zxyz, 8 ); + xyz3 = vec_sld( zxyz, zxyz, 4 ); + vec0 = Vector3( xyzx ); + vec1 = Vector3( xyz1 ); + vec2 = Vector3( xyz2 ); + vec3 = Vector3( xyz3 ); +} + +inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = vec_perm( vec0.get128(), vec1.get128(), _VECTORMATH_PERM_XYZA ); + yzxy = vec_perm( vec1.get128(), vec2.get128(), _VECTORMATH_PERM_YZAB ); + zxyz = vec_perm( vec2.get128(), vec3.get128(), _VECTORMATH_PERM_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + storeXYZArray( vec0, vec1, vec2, vec3, xyz0 ); + storeXYZArray( vec4, vec5, vec6, vec7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +inline Vector3 & Vector3::operator =( Vector3 vec ) +{ + mVec128 = vec.mVec128; + return *this; +} + +inline Vector3 & Vector3::setX( float _x ) +{ + _vmathVfSetElement(mVec128, _x, 0); + return *this; +} + +inline Vector3 & Vector3::setX( floatInVec _x ) +{ + mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); + return *this; +} + +inline const floatInVec Vector3::getX( ) const +{ + return floatInVec( mVec128, 0 ); +} + +inline Vector3 & Vector3::setY( float _y ) +{ + _vmathVfSetElement(mVec128, _y, 1); + return *this; +} + +inline Vector3 & Vector3::setY( floatInVec _y ) +{ + mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); + return *this; +} + +inline const floatInVec Vector3::getY( ) const +{ + return floatInVec( mVec128, 1 ); +} + +inline Vector3 & Vector3::setZ( float _z ) +{ + _vmathVfSetElement(mVec128, _z, 2); + return *this; +} + +inline Vector3 & Vector3::setZ( floatInVec _z ) +{ + mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); + return *this; +} + +inline const floatInVec Vector3::getZ( ) const +{ + return floatInVec( mVec128, 2 ); +} + +inline Vector3 & Vector3::setElem( int idx, float value ) +{ + _vmathVfSetElement(mVec128, value, idx); + return *this; +} + +inline Vector3 & Vector3::setElem( int idx, floatInVec value ) +{ + mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); + return *this; +} + +inline const floatInVec Vector3::getElem( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline VecIdx Vector3::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline const floatInVec Vector3::operator []( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline const Vector3 Vector3::operator +( Vector3 vec ) const +{ + return Vector3( vec_add( mVec128, vec.mVec128 ) ); +} + +inline const Vector3 Vector3::operator -( Vector3 vec ) const +{ + return Vector3( vec_sub( mVec128, vec.mVec128 ) ); +} + +inline const Point3 Vector3::operator +( Point3 pnt ) const +{ + return Point3( vec_add( mVec128, pnt.get128() ) ); +} + +inline const Vector3 Vector3::operator *( float scalar ) const +{ + return *this * floatInVec(scalar); +} + +inline const Vector3 Vector3::operator *( floatInVec scalar ) const +{ + return Vector3( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline Vector3 & Vector3::operator +=( Vector3 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Vector3 & Vector3::operator -=( Vector3 vec ) +{ + *this = *this - vec; + return *this; +} + +inline Vector3 & Vector3::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline Vector3 & Vector3::operator *=( floatInVec scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Vector3 Vector3::operator /( float scalar ) const +{ + return *this / floatInVec(scalar); +} + +inline const Vector3 Vector3::operator /( floatInVec scalar ) const +{ + return Vector3( divf4( mVec128, scalar.get128() ) ); +} + +inline Vector3 & Vector3::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline Vector3 & Vector3::operator /=( floatInVec scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline bool Vector3::operator == (const Vector3& vec) const +{ + return vec_all_gt(vec_cmpeq(vec_sel(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F), vec_sel(vec.mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)),((vec_uint4){0,0,0,0})); +} + +inline bool Vector3::operator != (const Vector3& vec) const +{ + return !(*this == vec); +} + +inline bool Vector3::operator < (const Vector3& vec) const +{ + return vec_all_gt(vec_cmpgt(vec_sel(vec.mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F), vec_sel(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)), ((vec_uint4){0,0,0,0})); +} + +inline bool Vector3::operator <= (const Vector3& vec) const +{ + return !(*this > vec); +} + +inline bool Vector3::operator > (const Vector3& vec) const +{ + return vec_all_gt(vec_cmpgt(vec_sel(mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F), vec_sel(vec.mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)), ((vec_uint4){0,0,0,0})); +} + +inline bool Vector3::operator >= (const Vector3& vec) const +{ + return !(*this < vec); +} + +inline const Vector3 Vector3::operator -( ) const +{ + return Vector3( negatef4( mVec128 ) ); +} + +inline const Vector3 operator *( float scalar, Vector3 vec ) +{ + return floatInVec(scalar) * vec; +} + +inline const Vector3 operator *( floatInVec scalar, Vector3 vec ) +{ + return vec * scalar; +} + +inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( vec_madd( vec0.get128(), vec1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( divf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 recipPerElem( Vector3 vec ) +{ + return Vector3( recipf4( vec.get128() ) ); +} + +inline const Vector3 sqrtPerElem( Vector3 vec ) +{ + return Vector3( sqrtf4( vec.get128() ) ); +} + +inline const Vector3 rsqrtPerElem( Vector3 vec ) +{ + return Vector3( rsqrtf4( vec.get128() ) ); +} + +inline const Vector3 absPerElem( Vector3 vec ) +{ + return Vector3( fabsf4( vec.get128() ) ); +} + +inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( copysignf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( fmaxf4( vec0.get128(), vec1.get128() ) ); +} + +inline const floatInVec maxElem( Vector3 vec ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = fmaxf4( vec_splat( vec.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( fminf4( vec0.get128(), vec1.get128() ) ); +} + +inline const floatInVec minElem( Vector3 vec ) +{ + vec_float4 result; + result = fminf4( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = fminf4( vec_splat( vec.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const floatInVec sum( Vector3 vec ) +{ + vec_float4 result; + result = vec_add( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = vec_add( vec_splat( vec.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const floatInVec dot( Vector3 vec0, Vector3 vec1 ) +{ + return floatInVec( _vmathVfDot3( vec0.get128(), vec1.get128() ), 0 ); +} + +inline const floatInVec lengthSqr( Vector3 vec ) +{ + return floatInVec( _vmathVfDot3( vec.get128(), vec.get128() ), 0 ); +} + +inline const floatInVec length( Vector3 vec ) +{ + return floatInVec( sqrtf4(_vmathVfDot3( vec.get128(), vec.get128() )), 0 ); +} + +inline const Vector3 normalize( Vector3 vec ) +{ + vec_float4 dot = _vmathVfDot3( vec.get128(), vec.get128() ); + dot = vec_splat( dot, 0 ); + return Vector3( vec_madd( vec.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( _vmathVfCross( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ) +{ + return select( vec0, vec1, boolInVec(select1) ); +} + +inline const Vector3 select( Vector3 vec0, Vector3 vec1, boolInVec select1 ) +{ + return Vector3( vec_sel( vec0.get128(), vec1.get128(), select1.get128() ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Vector3 vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +inline void print( Vector3 vec, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +inline Vector4::Vector4( float _x, float _y, float _z, float _w ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & + __builtin_constant_p(_z) & __builtin_constant_p(_w)) { + mVec128 = (vec_float4){_x, _y, _z, _w}; + } else { + float *pf = (float *)&mVec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = _w; + } +} + +inline Vector4::Vector4( floatInVec _x, floatInVec _y, floatInVec _z, floatInVec _w ) +{ + vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); + vec_float4 yw = vec_mergeh( _y.get128(), _w.get128() ); + mVec128 = vec_mergeh( xz, yw ); +} + +inline Vector4::Vector4( Vector3 xyz, float _w ) +{ + mVec128 = xyz.get128(); + _vmathVfSetElement(mVec128, _w, 3); +} + +inline Vector4::Vector4( Vector3 xyz, floatInVec _w ) +{ + mVec128 = xyz.get128(); + mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); +} + +inline Vector4::Vector4( Vector3 vec ) +{ + mVec128 = vec.get128(); + mVec128 = _vmathVfInsert(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), 3); +} + +inline Vector4::Vector4( Point3 pnt ) +{ + mVec128 = pnt.get128(); + mVec128 = _vmathVfInsert(mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), 3); +} + +inline Vector4::Vector4( Quat quat ) +{ + mVec128 = quat.get128(); +} + +inline Vector4::Vector4( float scalar ) +{ + mVec128 = floatInVec(scalar).get128(); +} + +inline Vector4::Vector4( floatInVec scalar ) +{ + mVec128 = scalar.get128(); +} + +inline Vector4::Vector4( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Vector4 Vector4::xAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_1000 ); +} + +inline const Vector4 Vector4::yAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0100 ); +} + +inline const Vector4 Vector4::zAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0010 ); +} + +inline const Vector4 Vector4::wAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0001 ); +} + +inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ) +{ + return lerp( floatInVec(t), vec0, vec1 ); +} + +inline const Vector4 lerp( floatInVec t, Vector4 vec0, Vector4 vec1 ) +{ + return ( vec0 + ( ( vec1 - vec0 ) * t ) ); +} + +inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ) +{ + return slerp( floatInVec(t), unitVec0, unitVec1 ); +} + +inline const Vector4 slerp( floatInVec t, Vector4 unitVec0, Vector4 unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + cosAngle = _vmathVfDot4( unitVec0.get128(), unitVec1.get128() ); + cosAngle = vec_splat( cosAngle, 0 ); + selectMask = (vec_uint4)vec_cmpgt( ((vec_float4){_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL,_VECTORMATH_SLERP_TOL}), cosAngle ); + angle = acosf4( cosAngle ); + tttt = t.get128(); + oneMinusT = vec_sub( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( ((vec_float4){1.0f,1.0f,1.0f,1.0f}), tttt ); + angles = vec_mergeh( angles, oneMinusT ); + angles = vec_madd( angles, angle, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ); + sines = sinf4( angles ); + scales = divf4( sines, vec_splat( sines, 0 ) ); + scale0 = vec_sel( oneMinusT, vec_splat( scales, 1 ), selectMask ); + scale1 = vec_sel( tttt, vec_splat( scales, 2 ), selectMask ); + return Vector4( vec_madd( unitVec0.get128(), scale0, vec_madd( unitVec1.get128(), scale1, ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ) ); +} + +inline vec_float4 Vector4::get128( ) const +{ + return mVec128; +} + +inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ) +{ + twoQuads[0] = _vmath2VfToHalfFloats(vec0.get128(), vec1.get128()); + twoQuads[1] = _vmath2VfToHalfFloats(vec2.get128(), vec3.get128()); +} + +inline Vector4 & Vector4::operator =( Vector4 vec ) +{ + mVec128 = vec.mVec128; + return *this; +} + +inline Vector4 & Vector4::setXYZ( Vector3 vec ) +{ + mVec128 = vec_sel( vec.get128(), mVec128, _VECTORMATH_MASK_0x000F ); + return *this; +} + +inline const Vector3 Vector4::getXYZ( ) const +{ + return Vector3( mVec128 ); +} + +inline Vector4 & Vector4::setX( float _x ) +{ + _vmathVfSetElement(mVec128, _x, 0); + return *this; +} + +inline Vector4 & Vector4::setX( floatInVec _x ) +{ + mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); + return *this; +} + +inline const floatInVec Vector4::getX( ) const +{ + return floatInVec( mVec128, 0 ); +} + +inline Vector4 & Vector4::setY( float _y ) +{ + _vmathVfSetElement(mVec128, _y, 1); + return *this; +} + +inline Vector4 & Vector4::setY( floatInVec _y ) +{ + mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); + return *this; +} + +inline const floatInVec Vector4::getY( ) const +{ + return floatInVec( mVec128, 1 ); +} + +inline Vector4 & Vector4::setZ( float _z ) +{ + _vmathVfSetElement(mVec128, _z, 2); + return *this; +} + +inline Vector4 & Vector4::setZ( floatInVec _z ) +{ + mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); + return *this; +} + +inline const floatInVec Vector4::getZ( ) const +{ + return floatInVec( mVec128, 2 ); +} + +inline Vector4 & Vector4::setW( float _w ) +{ + _vmathVfSetElement(mVec128, _w, 3); + return *this; +} + +inline Vector4 & Vector4::setW( floatInVec _w ) +{ + mVec128 = _vmathVfInsert(mVec128, _w.get128(), 3); + return *this; +} + +inline const floatInVec Vector4::getW( ) const +{ + return floatInVec( mVec128, 3 ); +} + +inline Vector4 & Vector4::setElem( int idx, float value ) +{ + _vmathVfSetElement(mVec128, value, idx); + return *this; +} + +inline Vector4 & Vector4::setElem( int idx, floatInVec value ) +{ + mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); + return *this; +} + +inline const floatInVec Vector4::getElem( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline VecIdx Vector4::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline const floatInVec Vector4::operator []( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline const Vector4 Vector4::operator +( Vector4 vec ) const +{ + return Vector4( vec_add( mVec128, vec.mVec128 ) ); +} + +inline const Vector4 Vector4::operator -( Vector4 vec ) const +{ + return Vector4( vec_sub( mVec128, vec.mVec128 ) ); +} + +inline const Vector4 Vector4::operator *( float scalar ) const +{ + return *this * floatInVec(scalar); +} + +inline const Vector4 Vector4::operator *( floatInVec scalar ) const +{ + return Vector4( vec_madd( mVec128, scalar.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline Vector4 & Vector4::operator +=( Vector4 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Vector4 & Vector4::operator -=( Vector4 vec ) +{ + *this = *this - vec; + return *this; +} + +inline Vector4 & Vector4::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline Vector4 & Vector4::operator *=( floatInVec scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Vector4 Vector4::operator /( float scalar ) const +{ + return *this / floatInVec(scalar); +} + +inline const Vector4 Vector4::operator /( floatInVec scalar ) const +{ + return Vector4( divf4( mVec128, scalar.get128() ) ); +} + +inline Vector4 & Vector4::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline Vector4 & Vector4::operator /=( floatInVec scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline const Vector4 Vector4::operator -( ) const +{ + return Vector4( negatef4( mVec128 ) ); +} + +inline bool Vector4::operator == (const Vector4& vec) const +{ + return vec_all_gt(vec_cmpeq(mVec128, vec.mVec128),((vec_uint4){0,0,0,0})); +} + +inline bool Vector4::operator != (const Vector4& vec) const +{ + return !(*this == vec); +} + +inline bool Vector4::operator < (const Vector4& vec) const +{ + return vec_all_gt(vec_cmpgt(vec.mVec128, mVec128),((vec_uint4){0,0,0,0})); +} + +inline bool Vector4::operator <= (const Vector4& vec) const +{ + return !(*this > vec); +} + +inline bool Vector4::operator > (const Vector4& vec) const +{ + return vec_all_gt(vec_cmpgt(mVec128, vec.mVec128),((vec_uint4){0,0,0,0})); +} + +inline bool Vector4::operator >= (const Vector4& vec) const +{ + return !(*this < vec); +} + +inline const Vector4 operator *( float scalar, Vector4 vec ) +{ + return floatInVec(scalar) * vec; +} + +inline const Vector4 operator *( floatInVec scalar, Vector4 vec ) +{ + return vec * scalar; +} + +inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( vec_madd( vec0.get128(), vec1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( divf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector4 recipPerElem( Vector4 vec ) +{ + return Vector4( recipf4( vec.get128() ) ); +} + +inline const Vector4 sqrtPerElem( Vector4 vec ) +{ + return Vector4( sqrtf4( vec.get128() ) ); +} + +inline const Vector4 rsqrtPerElem( Vector4 vec ) +{ + return Vector4( rsqrtf4( vec.get128() ) ); +} + +inline const Vector4 absPerElem( Vector4 vec ) +{ + return Vector4( fabsf4( vec.get128() ) ); +} + +inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( copysignf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( fmaxf4( vec0.get128(), vec1.get128() ) ); +} + +inline const floatInVec maxElem( Vector4 vec ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = fmaxf4( vec_splat( vec.get128(), 2 ), result ); + result = fmaxf4( vec_splat( vec.get128(), 3 ), result ); + return floatInVec( result, 0 ); +} + +inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( fminf4( vec0.get128(), vec1.get128() ) ); +} + +inline const floatInVec minElem( Vector4 vec ) +{ + vec_float4 result; + result = fminf4( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = fminf4( vec_splat( vec.get128(), 2 ), result ); + result = fminf4( vec_splat( vec.get128(), 3 ), result ); + return floatInVec( result, 0 ); +} + +inline const floatInVec sum( Vector4 vec ) +{ + vec_float4 result; + result = vec_add( vec_splat( vec.get128(), 1 ), vec.get128() ); + result = vec_add( vec_splat( vec.get128(), 2 ), result ); + result = vec_add( vec_splat( vec.get128(), 3 ), result ); + return floatInVec( result, 0 ); +} + +inline const floatInVec dot( Vector4 vec0, Vector4 vec1 ) +{ + return floatInVec( _vmathVfDot4( vec0.get128(), vec1.get128() ), 0 ); +} + +inline const floatInVec lengthSqr( Vector4 vec ) +{ + return floatInVec( _vmathVfDot4( vec.get128(), vec.get128() ), 0 ); +} + +inline const floatInVec length( Vector4 vec ) +{ + return floatInVec( sqrtf4(_vmathVfDot4( vec.get128(), vec.get128() )), 0 ); +} + +inline const Vector4 normalize( Vector4 vec ) +{ + vec_float4 dot = _vmathVfDot4( vec.get128(), vec.get128() ); + return Vector4( vec_madd( vec.get128(), rsqrtf4( dot ), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ) +{ + return select( vec0, vec1, boolInVec(select1) ); +} + +inline const Vector4 select( Vector4 vec0, Vector4 vec1, boolInVec select1 ) +{ + return Vector4( vec_sel( vec0.get128(), vec1.get128(), select1.get128() ) ); +} + +inline void loadXYZW( Vector4 & vec, const vec_float4 * quad ) +{ + vec = Vector4( *quad ); +} + +inline void loadXYZW( Vector4 & vec, const float * fptr ) +{ + vec_float4 vec0 = vec_ld(0, fptr); + vec_float4 vec1 = vec_ld(16, fptr); + vec = Vector4( vec_perm(vec0, vec1, vec_lvsl(0, fptr)) ); +} + +inline void storeXYZW( Vector4 vec, float * fptr ) +{ + vec_float4 vsrc = vec.get128(); + vec_float4 x = vec_splat(vsrc, 0); + vec_float4 y = vec_splat(vsrc, 1); + vec_float4 z = vec_splat(vsrc, 2); + vec_float4 w = vec_splat(vsrc, 3); + vec_ste(x, 0, fptr); + vec_ste(y, 4, fptr); + vec_ste(z, 8, fptr); + vec_ste(w, 12, fptr); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Vector4 vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +inline void print( Vector4 vec, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +inline Point3::Point3( float _x, float _y, float _z ) +{ + if (__builtin_constant_p(_x) & __builtin_constant_p(_y) & __builtin_constant_p(_z)) { + mVec128 = (vec_float4){_x, _y, _z, 0.0f}; + } else { + float *pf = (float *)&mVec128; + pf[0] = _x; + pf[1] = _y; + pf[2] = _z; + pf[3] = 0.0f; + } +} + +inline Point3::Point3( floatInVec _x, floatInVec _y, floatInVec _z ) +{ + vec_float4 xz = vec_mergeh( _x.get128(), _z.get128() ); + vec_float4 yw = vec_mergeh( _y.get128(), ((vec_float4){0.0f, 0.0f, 0.0f, 0.0f})); + mVec128 = vec_mergeh( xz, yw ); +} + +inline Point3::Point3( Vector3 vec ) +{ + mVec128 = vec.get128(); +} + +inline Point3::Point3( float scalar ) +{ + mVec128 = floatInVec(scalar).get128(); +} + +inline Point3::Point3( floatInVec scalar ) +{ + mVec128 = scalar.get128(); +} + +inline Point3::Point3( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ) +{ + return lerp( floatInVec(t), pnt0, pnt1 ); +} + +inline const Point3 lerp( floatInVec t, Point3 pnt0, Point3 pnt1 ) +{ + return ( pnt0 + ( ( pnt1 - pnt0 ) * t ) ); +} + +inline vec_float4 Point3::get128( ) const +{ + return mVec128; +} + +inline void loadXYZ( Point3 & pnt, const float * fptr ) +{ + vec_float4 vec0 = vec_ld(0, fptr); + vec_float4 vec1 = vec_ld(16, fptr); + pnt = Point3( vec_perm(vec0, vec1, vec_lvsl(0, fptr)) ); +} + +inline void storeXYZ( Point3 pnt, vec_float4 * quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = _VECTORMATH_MASK_0x000F; + dstVec = vec_sel(pnt.get128(), dstVec, mask); + *quad = dstVec; +} + +inline void storeXYZ( Point3 pnt, float * fptr ) +{ + vec_float4 vsrc = pnt.get128(); + vec_float4 x = vec_splat(vsrc, 0); + vec_float4 y = vec_splat(vsrc, 1); + vec_float4 z = vec_splat(vsrc, 2); + vec_ste(x, 0, fptr); + vec_ste(y, 4, fptr); + vec_ste(z, 8, fptr); +} + +inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = vec_sld( xyzx, yzxy, 12 ); + xyz2 = vec_sld( yzxy, zxyz, 8 ); + xyz3 = vec_sld( zxyz, zxyz, 4 ); + pnt0 = Point3( xyzx ); + pnt1 = Point3( xyz1 ); + pnt2 = Point3( xyz2 ); + pnt3 = Point3( xyz3 ); +} + +inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = vec_perm( pnt0.get128(), pnt1.get128(), _VECTORMATH_PERM_XYZA ); + yzxy = vec_perm( pnt1.get128(), pnt2.get128(), _VECTORMATH_PERM_YZAB ); + zxyz = vec_perm( pnt2.get128(), pnt3.get128(), _VECTORMATH_PERM_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + storeXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); + storeXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +inline Point3 & Point3::operator =( Point3 pnt ) +{ + mVec128 = pnt.mVec128; + return *this; +} + +inline Point3 & Point3::setX( float _x ) +{ + _vmathVfSetElement(mVec128, _x, 0); + return *this; +} + +inline Point3 & Point3::setX( floatInVec _x ) +{ + mVec128 = _vmathVfInsert(mVec128, _x.get128(), 0); + return *this; +} + +inline const floatInVec Point3::getX( ) const +{ + return floatInVec( mVec128, 0 ); +} + +inline Point3 & Point3::setY( float _y ) +{ + _vmathVfSetElement(mVec128, _y, 1); + return *this; +} + +inline Point3 & Point3::setY( floatInVec _y ) +{ + mVec128 = _vmathVfInsert(mVec128, _y.get128(), 1); + return *this; +} + +inline const floatInVec Point3::getY( ) const +{ + return floatInVec( mVec128, 1 ); +} + +inline Point3 & Point3::setZ( float _z ) +{ + _vmathVfSetElement(mVec128, _z, 2); + return *this; +} + +inline Point3 & Point3::setZ( floatInVec _z ) +{ + mVec128 = _vmathVfInsert(mVec128, _z.get128(), 2); + return *this; +} + +inline const floatInVec Point3::getZ( ) const +{ + return floatInVec( mVec128, 2 ); +} + +inline Point3 & Point3::setElem( int idx, float value ) +{ + _vmathVfSetElement(mVec128, value, idx); + return *this; +} + +inline Point3 & Point3::setElem( int idx, floatInVec value ) +{ + mVec128 = _vmathVfInsert(mVec128, value.get128(), idx); + return *this; +} + +inline const floatInVec Point3::getElem( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline VecIdx Point3::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline const floatInVec Point3::operator []( int idx ) const +{ + return floatInVec( mVec128, idx ); +} + +inline const Vector3 Point3::operator -( Point3 pnt ) const +{ + return Vector3( vec_sub( mVec128, pnt.mVec128 ) ); +} + +inline const Point3 Point3::operator +( Vector3 vec ) const +{ + return Point3( vec_add( mVec128, vec.get128() ) ); +} + +inline const Point3 Point3::operator -( Vector3 vec ) const +{ + return Point3( vec_sub( mVec128, vec.get128() ) ); +} + +inline Point3 & Point3::operator +=( Vector3 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Point3 & Point3::operator -=( Vector3 vec ) +{ + *this = *this - vec; + return *this; +} + +inline bool Point3::operator == (const Point3& pnt) const +{ + return vec_all_gt(vec_cmpeq(vec_sel(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F), vec_sel(pnt.mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)),((vec_uint4){0,0,0,0})); +} + +inline bool Point3::operator != (const Point3& pnt) const +{ + return !(*this == pnt); +} + +inline bool Point3::operator < (const Point3& pnt) const +{ + return vec_all_gt(vec_cmpgt(vec_sel(pnt.mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F), vec_sel(mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)), ((vec_uint4){0,0,0,0})); +} + +inline bool Point3::operator <= (const Point3& pnt) const +{ + return !(*this > pnt); +} + +inline bool Point3::operator > (const Point3& pnt) const +{ + return vec_all_gt(vec_cmpgt(vec_sel(mVec128, ((vec_float4){1.0f,1.0f,1.0f,1.0f}), _VECTORMATH_MASK_0x000F), vec_sel(pnt.mVec128, ((vec_float4){0.0f,0.0f,0.0f,0.0f}), _VECTORMATH_MASK_0x000F)), ((vec_uint4){0,0,0,0})); +} + +inline bool Point3::operator >= (const Point3& pnt) const +{ + return !(*this < pnt); +} + +inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( vec_madd( pnt0.get128(), pnt1.get128(), ((vec_float4){0.0f,0.0f,0.0f,0.0f}) ) ); +} + +inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( divf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const Point3 recipPerElem( Point3 pnt ) +{ + return Point3( recipf4( pnt.get128() ) ); +} + +inline const Point3 sqrtPerElem( Point3 pnt ) +{ + return Point3( sqrtf4( pnt.get128() ) ); +} + +inline const Point3 rsqrtPerElem( Point3 pnt ) +{ + return Point3( rsqrtf4( pnt.get128() ) ); +} + +inline const Point3 absPerElem( Point3 pnt ) +{ + return Point3( fabsf4( pnt.get128() ) ); +} + +inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( copysignf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( fmaxf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const floatInVec maxElem( Point3 pnt ) +{ + vec_float4 result; + result = fmaxf4( vec_splat( pnt.get128(), 1 ), pnt.get128() ); + result = fmaxf4( vec_splat( pnt.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( fminf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const floatInVec minElem( Point3 pnt ) +{ + vec_float4 result; + result = fminf4( vec_splat( pnt.get128(), 1 ), pnt.get128() ); + result = fminf4( vec_splat( pnt.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const floatInVec sum( Point3 pnt ) +{ + vec_float4 result; + result = vec_add( vec_splat( pnt.get128(), 1 ), pnt.get128() ); + result = vec_add( vec_splat( pnt.get128(), 2 ), result ); + return floatInVec( result, 0 ); +} + +inline const Point3 scale( Point3 pnt, float scaleVal ) +{ + return scale( pnt, floatInVec( scaleVal ) ); +} + +inline const Point3 scale( Point3 pnt, floatInVec scaleVal ) +{ + return mulPerElem( pnt, Point3( scaleVal ) ); +} + +inline const Point3 scale( Point3 pnt, Vector3 scaleVec ) +{ + return mulPerElem( pnt, Point3( scaleVec ) ); +} + +inline const floatInVec projection( Point3 pnt, Vector3 unitVec ) +{ + return floatInVec( _vmathVfDot3( pnt.get128(), unitVec.get128() ), 0 ); +} + +inline const floatInVec distSqrFromOrigin( Point3 pnt ) +{ + return lengthSqr( Vector3( pnt ) ); +} + +inline const floatInVec distFromOrigin( Point3 pnt ) +{ + return length( Vector3( pnt ) ); +} + +inline const floatInVec distSqr( Point3 pnt0, Point3 pnt1 ) +{ + return lengthSqr( ( pnt1 - pnt0 ) ); +} + +inline const floatInVec dist( Point3 pnt0, Point3 pnt1 ) +{ + return length( ( pnt1 - pnt0 ) ); +} + +inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ) +{ + return select( pnt0, pnt1, boolInVec(select1) ); +} + +inline const Point3 select( Point3 pnt0, Point3 pnt1, boolInVec select1 ) +{ + return Point3( vec_sel( pnt0.get128(), pnt1.get128(), select1.get128() ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Point3 pnt ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt.get128(); + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +inline void print( Point3 pnt, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt.get128(); + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/ppu/cpp/vecidx_aos.h b/common/vectormath/ppu/cpp/vecidx_aos.h index df335757..86ddf84f 100644 --- a/common/vectormath/ppu/cpp/vecidx_aos.h +++ b/common/vectormath/ppu/cpp/vecidx_aos.h @@ -1,80 +1,80 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VECIDX_AOS_H -#define _VECTORMATH_VECIDX_AOS_H - -#include "floatInVec.h" - -namespace Vectormath { -namespace Aos { - -//----------------------------------------------------------------------------- -// VecIdx -// Used in setting elements of Vector3, Vector4, Point3, or Quat with the -// subscripting operator. -// - -class VecIdx -{ -private: - typedef vec_float4 vec_float4_t; - vec_float4_t &ref __attribute__ ((aligned(16))); - int i __attribute__ ((aligned(16))); -public: - inline VecIdx( vec_float4_t& vec, int idx ): ref(vec) { i = idx; } - - // implicitly casts to float unless _VECTORMATH_NO_SCALAR_CAST defined - // in which case, implicitly casts to floatInVec, and one must call - // getAsFloat to convert to float. - // -#ifdef _VECTORMATH_NO_SCALAR_CAST - inline operator floatInVec() const; - inline float getAsFloat() const; -#else - inline operator float() const; -#endif - - inline float operator =( float scalar ); - inline floatInVec operator =( floatInVec scalar ); - inline floatInVec operator =( const VecIdx& scalar ); - inline floatInVec operator *=( float scalar ); - inline floatInVec operator *=( floatInVec scalar ); - inline floatInVec operator /=( float scalar ); - inline floatInVec operator /=( floatInVec scalar ); - inline floatInVec operator +=( float scalar ); - inline floatInVec operator +=( floatInVec scalar ); - inline floatInVec operator -=( float scalar ); - inline floatInVec operator -=( floatInVec scalar ); -}; - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VECIDX_AOS_H +#define _VECTORMATH_VECIDX_AOS_H + +#include "floatInVec.h" + +namespace Vectormath { +namespace Aos { + +//----------------------------------------------------------------------------- +// VecIdx +// Used in setting elements of Vector3, Vector4, Point3, or Quat with the +// subscripting operator. +// + +class VecIdx +{ +private: + typedef vec_float4 vec_float4_t; + vec_float4_t &ref __attribute__ ((aligned(16))); + int i __attribute__ ((aligned(16))); +public: + inline VecIdx( vec_float4_t& vec, int idx ): ref(vec) { i = idx; } + + // implicitly casts to float unless _VECTORMATH_NO_SCALAR_CAST defined + // in which case, implicitly casts to floatInVec, and one must call + // getAsFloat to convert to float. + // +#ifdef _VECTORMATH_NO_SCALAR_CAST + inline operator floatInVec() const; + inline float getAsFloat() const; +#else + inline operator float() const; +#endif + + inline float operator =( float scalar ); + inline floatInVec operator =( floatInVec scalar ); + inline floatInVec operator =( const VecIdx& scalar ); + inline floatInVec operator *=( float scalar ); + inline floatInVec operator *=( floatInVec scalar ); + inline floatInVec operator /=( float scalar ); + inline floatInVec operator /=( floatInVec scalar ); + inline floatInVec operator +=( float scalar ); + inline floatInVec operator +=( floatInVec scalar ); + inline floatInVec operator -=( float scalar ); + inline floatInVec operator -=( floatInVec scalar ); +}; + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/ppu/cpp/vectormath_aos.h b/common/vectormath/ppu/cpp/vectormath_aos.h index 0a7fa173..8d0ed834 100644 --- a/common/vectormath/ppu/cpp/vectormath_aos.h +++ b/common/vectormath/ppu/cpp/vectormath_aos.h @@ -1,2244 +1,2369 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_AOS_CPP_PPU_H -#define _VECTORMATH_AOS_CPP_PPU_H - -#include -#include -#include "vecidx_aos.h" -#include "floatInVec.h" -#include "boolInVec.h" - -#ifdef _VECTORMATH_DEBUG -#include -#endif - -namespace Vectormath { - -namespace Aos { - -//----------------------------------------------------------------------------- -// Forward Declarations -// - -class Vector3; -class Vector4; -class Point3; -class Quat; -class Matrix3; -class Matrix4; -class Transform3; - -// A 3-D vector in array-of-structures format -// -class Vector3 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Vector3( ) { }; - - // Construct a 3-D vector from x, y, and z elements - // - inline Vector3( float x, float y, float z ); - - // Construct a 3-D vector from x, y, and z elements (scalar data contained in vector data type) - // - inline Vector3( floatInVec x, floatInVec y, floatInVec z ); - - // Copy elements from a 3-D point into a 3-D vector - // - explicit inline Vector3( Point3 pnt ); - - // Set all elements of a 3-D vector to the same scalar value - // - explicit inline Vector3( float scalar ); - - // Set all elements of a 3-D vector to the same scalar value (scalar data contained in vector data type) - // - explicit inline Vector3( floatInVec scalar ); - - // Set vector float data in a 3-D vector - // - explicit inline Vector3( vec_float4 vf4 ); - - // Get vector float data from a 3-D vector - // - inline vec_float4 get128( ) const; - - // Assign one 3-D vector to another - // - inline Vector3 & operator =( Vector3 vec ); - - // Set the x element of a 3-D vector - // - inline Vector3 & setX( float x ); - - // Set the y element of a 3-D vector - // - inline Vector3 & setY( float y ); - - // Set the z element of a 3-D vector - // - inline Vector3 & setZ( float z ); - - // Set the x element of a 3-D vector (scalar data contained in vector data type) - // - inline Vector3 & setX( floatInVec x ); - - // Set the y element of a 3-D vector (scalar data contained in vector data type) - // - inline Vector3 & setY( floatInVec y ); - - // Set the z element of a 3-D vector (scalar data contained in vector data type) - // - inline Vector3 & setZ( floatInVec z ); - - // Get the x element of a 3-D vector - // - inline const floatInVec getX( ) const; - - // Get the y element of a 3-D vector - // - inline const floatInVec getY( ) const; - - // Get the z element of a 3-D vector - // - inline const floatInVec getZ( ) const; - - // Set an x, y, or z element of a 3-D vector by index - // - inline Vector3 & setElem( int idx, float value ); - - // Set an x, y, or z element of a 3-D vector by index (scalar data contained in vector data type) - // - inline Vector3 & setElem( int idx, floatInVec value ); - - // Get an x, y, or z element of a 3-D vector by index - // - inline const floatInVec getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline const floatInVec operator []( int idx ) const; - - // Add two 3-D vectors - // - inline const Vector3 operator +( Vector3 vec ) const; - - // Subtract a 3-D vector from another 3-D vector - // - inline const Vector3 operator -( Vector3 vec ) const; - - // Add a 3-D vector to a 3-D point - // - inline const Point3 operator +( Point3 pnt ) const; - - // Multiply a 3-D vector by a scalar - // - inline const Vector3 operator *( float scalar ) const; - - // Divide a 3-D vector by a scalar - // - inline const Vector3 operator /( float scalar ) const; - - // Multiply a 3-D vector by a scalar (scalar data contained in vector data type) - // - inline const Vector3 operator *( floatInVec scalar ) const; - - // Divide a 3-D vector by a scalar (scalar data contained in vector data type) - // - inline const Vector3 operator /( floatInVec scalar ) const; - - // Perform compound assignment and addition with a 3-D vector - // - inline Vector3 & operator +=( Vector3 vec ); - - // Perform compound assignment and subtraction by a 3-D vector - // - inline Vector3 & operator -=( Vector3 vec ); - - // Perform compound assignment and multiplication by a scalar - // - inline Vector3 & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Vector3 & operator /=( float scalar ); - - // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) - // - inline Vector3 & operator *=( floatInVec scalar ); - - // Perform compound assignment and division by a scalar (scalar data contained in vector data type) - // - inline Vector3 & operator /=( floatInVec scalar ); - - // Negate all elements of a 3-D vector - // - inline const Vector3 operator -( ) const; - - // Construct x axis - // - static inline const Vector3 xAxis( ); - - // Construct y axis - // - static inline const Vector3 yAxis( ); - - // Construct z axis - // - static inline const Vector3 zAxis( ); - -}; - -// Multiply a 3-D vector by a scalar -// -inline const Vector3 operator *( float scalar, Vector3 vec ); - -// Multiply a 3-D vector by a scalar (scalar data contained in vector data type) -// -inline const Vector3 operator *( floatInVec scalar, Vector3 vec ); - -// Multiply two 3-D vectors per element -// -inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ); - -// Divide two 3-D vectors per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ); - -// Compute the reciprocal of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Vector3 recipPerElem( Vector3 vec ); - -// Compute the square root of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Vector3 sqrtPerElem( Vector3 vec ); - -// Compute the reciprocal square root of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Vector3 rsqrtPerElem( Vector3 vec ); - -// Compute the absolute value of a 3-D vector per element -// -inline const Vector3 absPerElem( Vector3 vec ); - -// Copy sign from one 3-D vector to another, per element -// -inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ); - -// Maximum of two 3-D vectors per element -// -inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ); - -// Minimum of two 3-D vectors per element -// -inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ); - -// Maximum element of a 3-D vector -// -inline const floatInVec maxElem( Vector3 vec ); - -// Minimum element of a 3-D vector -// -inline const floatInVec minElem( Vector3 vec ); - -// Compute the sum of all elements of a 3-D vector -// -inline const floatInVec sum( Vector3 vec ); - -// Compute the dot product of two 3-D vectors -// -inline const floatInVec dot( Vector3 vec0, Vector3 vec1 ); - -// Compute the square of the length of a 3-D vector -// -inline const floatInVec lengthSqr( Vector3 vec ); - -// Compute the length of a 3-D vector -// -inline const floatInVec length( Vector3 vec ); - -// Normalize a 3-D vector -// NOTE: -// The result is unpredictable when all elements of vec are at or near zero. -// -inline const Vector3 normalize( Vector3 vec ); - -// Compute cross product of two 3-D vectors -// -inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ); - -// Outer product of two 3-D vectors -// -inline const Matrix3 outer( Vector3 vec0, Vector3 vec1 ); - -// Pre-multiply a row vector by a 3x3 matrix -// NOTE: -// Slower than column post-multiply. -// -inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ); - -// Cross-product matrix of a 3-D vector -// -inline const Matrix3 crossMatrix( Vector3 vec ); - -// Create cross-product matrix and multiply -// NOTE: -// Faster than separately creating a cross-product matrix and multiplying. -// -inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ); - -// Linear interpolation between two 3-D vectors -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ); - -// Linear interpolation between two 3-D vectors (scalar data contained in vector data type) -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector3 lerp( floatInVec t, Vector3 vec0, Vector3 vec1 ); - -// Spherical linear interpolation between two 3-D vectors -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ); - -// Spherical linear interpolation between two 3-D vectors (scalar data contained in vector data type) -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector3 slerp( floatInVec t, Vector3 unitVec0, Vector3 unitVec1 ); - -// Conditionally select between two 3-D vectors -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ); - -// Conditionally select between two 3-D vectors (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Vector3 select( Vector3 vec0, Vector3 vec1, boolInVec select1 ); - -// Store x, y, and z elements of a 3-D vector in the first three words of a quadword. -// The value of the fourth word (the word with the highest address) remains unchanged -// -inline void storeXYZ( Vector3 vec, vec_float4 * quad ); - -// Load four three-float 3-D vectors, stored in three quadwords -// -inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ); - -// Store four 3-D vectors in three quadwords -// -inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ); - -// Store eight 3-D vectors as half-floats -// -inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3-D vector -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector3 vec ); - -// Print a 3-D vector and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector3 vec, const char * name ); - -#endif - -// A 4-D vector in array-of-structures format -// -class Vector4 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Vector4( ) { }; - - // Construct a 4-D vector from x, y, z, and w elements - // - inline Vector4( float x, float y, float z, float w ); - - // Construct a 4-D vector from x, y, z, and w elements (scalar data contained in vector data type) - // - inline Vector4( floatInVec x, floatInVec y, floatInVec z, floatInVec w ); - - // Construct a 4-D vector from a 3-D vector and a scalar - // - inline Vector4( Vector3 xyz, float w ); - - // Construct a 4-D vector from a 3-D vector and a scalar (scalar data contained in vector data type) - // - inline Vector4( Vector3 xyz, floatInVec w ); - - // Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 - // - explicit inline Vector4( Vector3 vec ); - - // Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 - // - explicit inline Vector4( Point3 pnt ); - - // Copy elements from a quaternion into a 4-D vector - // - explicit inline Vector4( Quat quat ); - - // Set all elements of a 4-D vector to the same scalar value - // - explicit inline Vector4( float scalar ); - - // Set all elements of a 4-D vector to the same scalar value (scalar data contained in vector data type) - // - explicit inline Vector4( floatInVec scalar ); - - // Set vector float data in a 4-D vector - // - explicit inline Vector4( vec_float4 vf4 ); - - // Get vector float data from a 4-D vector - // - inline vec_float4 get128( ) const; - - // Assign one 4-D vector to another - // - inline Vector4 & operator =( Vector4 vec ); - - // Set the x, y, and z elements of a 4-D vector - // NOTE: - // This function does not change the w element. - // - inline Vector4 & setXYZ( Vector3 vec ); - - // Get the x, y, and z elements of a 4-D vector - // - inline const Vector3 getXYZ( ) const; - - // Set the x element of a 4-D vector - // - inline Vector4 & setX( float x ); - - // Set the y element of a 4-D vector - // - inline Vector4 & setY( float y ); - - // Set the z element of a 4-D vector - // - inline Vector4 & setZ( float z ); - - // Set the w element of a 4-D vector - // - inline Vector4 & setW( float w ); - - // Set the x element of a 4-D vector (scalar data contained in vector data type) - // - inline Vector4 & setX( floatInVec x ); - - // Set the y element of a 4-D vector (scalar data contained in vector data type) - // - inline Vector4 & setY( floatInVec y ); - - // Set the z element of a 4-D vector (scalar data contained in vector data type) - // - inline Vector4 & setZ( floatInVec z ); - - // Set the w element of a 4-D vector (scalar data contained in vector data type) - // - inline Vector4 & setW( floatInVec w ); - - // Get the x element of a 4-D vector - // - inline const floatInVec getX( ) const; - - // Get the y element of a 4-D vector - // - inline const floatInVec getY( ) const; - - // Get the z element of a 4-D vector - // - inline const floatInVec getZ( ) const; - - // Get the w element of a 4-D vector - // - inline const floatInVec getW( ) const; - - // Set an x, y, z, or w element of a 4-D vector by index - // - inline Vector4 & setElem( int idx, float value ); - - // Set an x, y, z, or w element of a 4-D vector by index (scalar data contained in vector data type) - // - inline Vector4 & setElem( int idx, floatInVec value ); - - // Get an x, y, z, or w element of a 4-D vector by index - // - inline const floatInVec getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline const floatInVec operator []( int idx ) const; - - // Add two 4-D vectors - // - inline const Vector4 operator +( Vector4 vec ) const; - - // Subtract a 4-D vector from another 4-D vector - // - inline const Vector4 operator -( Vector4 vec ) const; - - // Multiply a 4-D vector by a scalar - // - inline const Vector4 operator *( float scalar ) const; - - // Divide a 4-D vector by a scalar - // - inline const Vector4 operator /( float scalar ) const; - - // Multiply a 4-D vector by a scalar (scalar data contained in vector data type) - // - inline const Vector4 operator *( floatInVec scalar ) const; - - // Divide a 4-D vector by a scalar (scalar data contained in vector data type) - // - inline const Vector4 operator /( floatInVec scalar ) const; - - // Perform compound assignment and addition with a 4-D vector - // - inline Vector4 & operator +=( Vector4 vec ); - - // Perform compound assignment and subtraction by a 4-D vector - // - inline Vector4 & operator -=( Vector4 vec ); - - // Perform compound assignment and multiplication by a scalar - // - inline Vector4 & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Vector4 & operator /=( float scalar ); - - // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) - // - inline Vector4 & operator *=( floatInVec scalar ); - - // Perform compound assignment and division by a scalar (scalar data contained in vector data type) - // - inline Vector4 & operator /=( floatInVec scalar ); - - // Negate all elements of a 4-D vector - // - inline const Vector4 operator -( ) const; - - // Construct x axis - // - static inline const Vector4 xAxis( ); - - // Construct y axis - // - static inline const Vector4 yAxis( ); - - // Construct z axis - // - static inline const Vector4 zAxis( ); - - // Construct w axis - // - static inline const Vector4 wAxis( ); - -}; - -// Multiply a 4-D vector by a scalar -// -inline const Vector4 operator *( float scalar, Vector4 vec ); - -// Multiply a 4-D vector by a scalar (scalar data contained in vector data type) -// -inline const Vector4 operator *( floatInVec scalar, Vector4 vec ); - -// Multiply two 4-D vectors per element -// -inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ); - -// Divide two 4-D vectors per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ); - -// Compute the reciprocal of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Vector4 recipPerElem( Vector4 vec ); - -// Compute the square root of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Vector4 sqrtPerElem( Vector4 vec ); - -// Compute the reciprocal square root of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Vector4 rsqrtPerElem( Vector4 vec ); - -// Compute the absolute value of a 4-D vector per element -// -inline const Vector4 absPerElem( Vector4 vec ); - -// Copy sign from one 4-D vector to another, per element -// -inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ); - -// Maximum of two 4-D vectors per element -// -inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ); - -// Minimum of two 4-D vectors per element -// -inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ); - -// Maximum element of a 4-D vector -// -inline const floatInVec maxElem( Vector4 vec ); - -// Minimum element of a 4-D vector -// -inline const floatInVec minElem( Vector4 vec ); - -// Compute the sum of all elements of a 4-D vector -// -inline const floatInVec sum( Vector4 vec ); - -// Compute the dot product of two 4-D vectors -// -inline const floatInVec dot( Vector4 vec0, Vector4 vec1 ); - -// Compute the square of the length of a 4-D vector -// -inline const floatInVec lengthSqr( Vector4 vec ); - -// Compute the length of a 4-D vector -// -inline const floatInVec length( Vector4 vec ); - -// Normalize a 4-D vector -// NOTE: -// The result is unpredictable when all elements of vec are at or near zero. -// -inline const Vector4 normalize( Vector4 vec ); - -// Outer product of two 4-D vectors -// -inline const Matrix4 outer( Vector4 vec0, Vector4 vec1 ); - -// Linear interpolation between two 4-D vectors -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ); - -// Linear interpolation between two 4-D vectors (scalar data contained in vector data type) -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector4 lerp( floatInVec t, Vector4 vec0, Vector4 vec1 ); - -// Spherical linear interpolation between two 4-D vectors -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ); - -// Spherical linear interpolation between two 4-D vectors (scalar data contained in vector data type) -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector4 slerp( floatInVec t, Vector4 unitVec0, Vector4 unitVec1 ); - -// Conditionally select between two 4-D vectors -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ); - -// Conditionally select between two 4-D vectors (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Vector4 select( Vector4 vec0, Vector4 vec1, boolInVec select1 ); - -// Store four 4-D vectors as half-floats -// -inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 4-D vector -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector4 vec ); - -// Print a 4-D vector and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector4 vec, const char * name ); - -#endif - -// A 3-D point in array-of-structures format -// -class Point3 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Point3( ) { }; - - // Construct a 3-D point from x, y, and z elements - // - inline Point3( float x, float y, float z ); - - // Construct a 3-D point from x, y, and z elements (scalar data contained in vector data type) - // - inline Point3( floatInVec x, floatInVec y, floatInVec z ); - - // Copy elements from a 3-D vector into a 3-D point - // - explicit inline Point3( Vector3 vec ); - - // Set all elements of a 3-D point to the same scalar value - // - explicit inline Point3( float scalar ); - - // Set all elements of a 3-D point to the same scalar value (scalar data contained in vector data type) - // - explicit inline Point3( floatInVec scalar ); - - // Set vector float data in a 3-D point - // - explicit inline Point3( vec_float4 vf4 ); - - // Get vector float data from a 3-D point - // - inline vec_float4 get128( ) const; - - // Assign one 3-D point to another - // - inline Point3 & operator =( Point3 pnt ); - - // Set the x element of a 3-D point - // - inline Point3 & setX( float x ); - - // Set the y element of a 3-D point - // - inline Point3 & setY( float y ); - - // Set the z element of a 3-D point - // - inline Point3 & setZ( float z ); - - // Set the x element of a 3-D point (scalar data contained in vector data type) - // - inline Point3 & setX( floatInVec x ); - - // Set the y element of a 3-D point (scalar data contained in vector data type) - // - inline Point3 & setY( floatInVec y ); - - // Set the z element of a 3-D point (scalar data contained in vector data type) - // - inline Point3 & setZ( floatInVec z ); - - // Get the x element of a 3-D point - // - inline const floatInVec getX( ) const; - - // Get the y element of a 3-D point - // - inline const floatInVec getY( ) const; - - // Get the z element of a 3-D point - // - inline const floatInVec getZ( ) const; - - // Set an x, y, or z element of a 3-D point by index - // - inline Point3 & setElem( int idx, float value ); - - // Set an x, y, or z element of a 3-D point by index (scalar data contained in vector data type) - // - inline Point3 & setElem( int idx, floatInVec value ); - - // Get an x, y, or z element of a 3-D point by index - // - inline const floatInVec getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline const floatInVec operator []( int idx ) const; - - // Subtract a 3-D point from another 3-D point - // - inline const Vector3 operator -( Point3 pnt ) const; - - // Add a 3-D point to a 3-D vector - // - inline const Point3 operator +( Vector3 vec ) const; - - // Subtract a 3-D vector from a 3-D point - // - inline const Point3 operator -( Vector3 vec ) const; - - // Perform compound assignment and addition with a 3-D vector - // - inline Point3 & operator +=( Vector3 vec ); - - // Perform compound assignment and subtraction by a 3-D vector - // - inline Point3 & operator -=( Vector3 vec ); - -}; - -// Multiply two 3-D points per element -// -inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ); - -// Divide two 3-D points per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ); - -// Compute the reciprocal of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Point3 recipPerElem( Point3 pnt ); - -// Compute the square root of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Point3 sqrtPerElem( Point3 pnt ); - -// Compute the reciprocal square root of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Point3 rsqrtPerElem( Point3 pnt ); - -// Compute the absolute value of a 3-D point per element -// -inline const Point3 absPerElem( Point3 pnt ); - -// Copy sign from one 3-D point to another, per element -// -inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ); - -// Maximum of two 3-D points per element -// -inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ); - -// Minimum of two 3-D points per element -// -inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ); - -// Maximum element of a 3-D point -// -inline const floatInVec maxElem( Point3 pnt ); - -// Minimum element of a 3-D point -// -inline const floatInVec minElem( Point3 pnt ); - -// Compute the sum of all elements of a 3-D point -// -inline const floatInVec sum( Point3 pnt ); - -// Apply uniform scale to a 3-D point -// -inline const Point3 scale( Point3 pnt, float scaleVal ); - -// Apply uniform scale to a 3-D point (scalar data contained in vector data type) -// -inline const Point3 scale( Point3 pnt, floatInVec scaleVal ); - -// Apply non-uniform scale to a 3-D point -// -inline const Point3 scale( Point3 pnt, Vector3 scaleVec ); - -// Scalar projection of a 3-D point on a unit-length 3-D vector -// -inline const floatInVec projection( Point3 pnt, Vector3 unitVec ); - -// Compute the square of the distance of a 3-D point from the coordinate-system origin -// -inline const floatInVec distSqrFromOrigin( Point3 pnt ); - -// Compute the distance of a 3-D point from the coordinate-system origin -// -inline const floatInVec distFromOrigin( Point3 pnt ); - -// Compute the square of the distance between two 3-D points -// -inline const floatInVec distSqr( Point3 pnt0, Point3 pnt1 ); - -// Compute the distance between two 3-D points -// -inline const floatInVec dist( Point3 pnt0, Point3 pnt1 ); - -// Linear interpolation between two 3-D points -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ); - -// Linear interpolation between two 3-D points (scalar data contained in vector data type) -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Point3 lerp( floatInVec t, Point3 pnt0, Point3 pnt1 ); - -// Conditionally select between two 3-D points -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ); - -// Conditionally select between two 3-D points (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Point3 select( Point3 pnt0, Point3 pnt1, boolInVec select1 ); - -// Store x, y, and z elements of a 3-D point in the first three words of a quadword. -// The value of the fourth word (the word with the highest address) remains unchanged -// -inline void storeXYZ( Point3 pnt, vec_float4 * quad ); - -// Load four three-float 3-D points, stored in three quadwords -// -inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ); - -// Store four 3-D points in three quadwords -// -inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ); - -// Store eight 3-D points as half-floats -// -inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3-D point -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Point3 pnt ); - -// Print a 3-D point and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Point3 pnt, const char * name ); - -#endif - -// A quaternion in array-of-structures format -// -class Quat -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Quat( ) { }; - - // Construct a quaternion from x, y, z, and w elements - // - inline Quat( float x, float y, float z, float w ); - - // Construct a quaternion from x, y, z, and w elements (scalar data contained in vector data type) - // - inline Quat( floatInVec x, floatInVec y, floatInVec z, floatInVec w ); - - // Construct a quaternion from a 3-D vector and a scalar - // - inline Quat( Vector3 xyz, float w ); - - // Construct a quaternion from a 3-D vector and a scalar (scalar data contained in vector data type) - // - inline Quat( Vector3 xyz, floatInVec w ); - - // Copy elements from a 4-D vector into a quaternion - // - explicit inline Quat( Vector4 vec ); - - // Convert a rotation matrix to a unit-length quaternion - // - explicit inline Quat( const Matrix3 & rotMat ); - - // Set all elements of a quaternion to the same scalar value - // - explicit inline Quat( float scalar ); - - // Set all elements of a quaternion to the same scalar value (scalar data contained in vector data type) - // - explicit inline Quat( floatInVec scalar ); - - // Set vector float data in a quaternion - // - explicit inline Quat( vec_float4 vf4 ); - - // Get vector float data from a quaternion - // - inline vec_float4 get128( ) const; - - // Assign one quaternion to another - // - inline Quat & operator =( Quat quat ); - - // Set the x, y, and z elements of a quaternion - // NOTE: - // This function does not change the w element. - // - inline Quat & setXYZ( Vector3 vec ); - - // Get the x, y, and z elements of a quaternion - // - inline const Vector3 getXYZ( ) const; - - // Set the x element of a quaternion - // - inline Quat & setX( float x ); - - // Set the y element of a quaternion - // - inline Quat & setY( float y ); - - // Set the z element of a quaternion - // - inline Quat & setZ( float z ); - - // Set the w element of a quaternion - // - inline Quat & setW( float w ); - - // Set the x element of a quaternion (scalar data contained in vector data type) - // - inline Quat & setX( floatInVec x ); - - // Set the y element of a quaternion (scalar data contained in vector data type) - // - inline Quat & setY( floatInVec y ); - - // Set the z element of a quaternion (scalar data contained in vector data type) - // - inline Quat & setZ( floatInVec z ); - - // Set the w element of a quaternion (scalar data contained in vector data type) - // - inline Quat & setW( floatInVec w ); - - // Get the x element of a quaternion - // - inline const floatInVec getX( ) const; - - // Get the y element of a quaternion - // - inline const floatInVec getY( ) const; - - // Get the z element of a quaternion - // - inline const floatInVec getZ( ) const; - - // Get the w element of a quaternion - // - inline const floatInVec getW( ) const; - - // Set an x, y, z, or w element of a quaternion by index - // - inline Quat & setElem( int idx, float value ); - - // Set an x, y, z, or w element of a quaternion by index (scalar data contained in vector data type) - // - inline Quat & setElem( int idx, floatInVec value ); - - // Get an x, y, z, or w element of a quaternion by index - // - inline const floatInVec getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline const floatInVec operator []( int idx ) const; - - // Add two quaternions - // - inline const Quat operator +( Quat quat ) const; - - // Subtract a quaternion from another quaternion - // - inline const Quat operator -( Quat quat ) const; - - // Multiply two quaternions - // - inline const Quat operator *( Quat quat ) const; - - // Multiply a quaternion by a scalar - // - inline const Quat operator *( float scalar ) const; - - // Divide a quaternion by a scalar - // - inline const Quat operator /( float scalar ) const; - - // Multiply a quaternion by a scalar (scalar data contained in vector data type) - // - inline const Quat operator *( floatInVec scalar ) const; - - // Divide a quaternion by a scalar (scalar data contained in vector data type) - // - inline const Quat operator /( floatInVec scalar ) const; - - // Perform compound assignment and addition with a quaternion - // - inline Quat & operator +=( Quat quat ); - - // Perform compound assignment and subtraction by a quaternion - // - inline Quat & operator -=( Quat quat ); - - // Perform compound assignment and multiplication by a quaternion - // - inline Quat & operator *=( Quat quat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Quat & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Quat & operator /=( float scalar ); - - // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) - // - inline Quat & operator *=( floatInVec scalar ); - - // Perform compound assignment and division by a scalar (scalar data contained in vector data type) - // - inline Quat & operator /=( floatInVec scalar ); - - // Negate all elements of a quaternion - // - inline const Quat operator -( ) const; - - // Construct an identity quaternion - // - static inline const Quat identity( ); - - // Construct a quaternion to rotate between two unit-length 3-D vectors - // NOTE: - // The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. - // - static inline const Quat rotation( Vector3 unitVec0, Vector3 unitVec1 ); - - // Construct a quaternion to rotate around a unit-length 3-D vector - // - static inline const Quat rotation( float radians, Vector3 unitVec ); - - // Construct a quaternion to rotate around a unit-length 3-D vector (scalar data contained in vector data type) - // - static inline const Quat rotation( floatInVec radians, Vector3 unitVec ); - - // Construct a quaternion to rotate around the x axis - // - static inline const Quat rotationX( float radians ); - - // Construct a quaternion to rotate around the y axis - // - static inline const Quat rotationY( float radians ); - - // Construct a quaternion to rotate around the z axis - // - static inline const Quat rotationZ( float radians ); - - // Construct a quaternion to rotate around the x axis (scalar data contained in vector data type) - // - static inline const Quat rotationX( floatInVec radians ); - - // Construct a quaternion to rotate around the y axis (scalar data contained in vector data type) - // - static inline const Quat rotationY( floatInVec radians ); - - // Construct a quaternion to rotate around the z axis (scalar data contained in vector data type) - // - static inline const Quat rotationZ( floatInVec radians ); - -}; - -// Multiply a quaternion by a scalar -// -inline const Quat operator *( float scalar, Quat quat ); - -// Multiply a quaternion by a scalar (scalar data contained in vector data type) -// -inline const Quat operator *( floatInVec scalar, Quat quat ); - -// Compute the conjugate of a quaternion -// -inline const Quat conj( Quat quat ); - -// Use a unit-length quaternion to rotate a 3-D vector -// -inline const Vector3 rotate( Quat unitQuat, Vector3 vec ); - -// Compute the dot product of two quaternions -// -inline const floatInVec dot( Quat quat0, Quat quat1 ); - -// Compute the norm of a quaternion -// -inline const floatInVec norm( Quat quat ); - -// Compute the length of a quaternion -// -inline const floatInVec length( Quat quat ); - -// Normalize a quaternion -// NOTE: -// The result is unpredictable when all elements of quat are at or near zero. -// -inline const Quat normalize( Quat quat ); - -// Linear interpolation between two quaternions -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Quat lerp( float t, Quat quat0, Quat quat1 ); - -// Linear interpolation between two quaternions (scalar data contained in vector data type) -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Quat lerp( floatInVec t, Quat quat0, Quat quat1 ); - -// Spherical linear interpolation between two quaternions -// NOTE: -// Interpolates along the shortest path between orientations. -// Does not clamp t between 0 and 1. -// -inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ); - -// Spherical linear interpolation between two quaternions (scalar data contained in vector data type) -// NOTE: -// Interpolates along the shortest path between orientations. -// Does not clamp t between 0 and 1. -// -inline const Quat slerp( floatInVec t, Quat unitQuat0, Quat unitQuat1 ); - -// Spherical quadrangle interpolation -// -inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); - -// Spherical quadrangle interpolation (scalar data contained in vector data type) -// -inline const Quat squad( floatInVec t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); - -// Conditionally select between two quaternions -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Quat select( Quat quat0, Quat quat1, bool select1 ); - -// Conditionally select between two quaternions (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Quat select( Quat quat0, Quat quat1, boolInVec select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a quaternion -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Quat quat ); - -// Print a quaternion and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Quat quat, const char * name ); - -#endif - -// A 3x3 matrix in array-of-structures format -// -class Matrix3 -{ - Vector3 mCol0; - Vector3 mCol1; - Vector3 mCol2; - -public: - // Default constructor; does no initialization - // - inline Matrix3( ) { }; - - // Copy a 3x3 matrix - // - inline Matrix3( const Matrix3 & mat ); - - // Construct a 3x3 matrix containing the specified columns - // - inline Matrix3( Vector3 col0, Vector3 col1, Vector3 col2 ); - - // Construct a 3x3 rotation matrix from a unit-length quaternion - // - explicit inline Matrix3( Quat unitQuat ); - - // Set all elements of a 3x3 matrix to the same scalar value - // - explicit inline Matrix3( float scalar ); - - // Set all elements of a 3x3 matrix to the same scalar value (scalar data contained in vector data type) - // - explicit inline Matrix3( floatInVec scalar ); - - // Assign one 3x3 matrix to another - // - inline Matrix3 & operator =( const Matrix3 & mat ); - - // Set column 0 of a 3x3 matrix - // - inline Matrix3 & setCol0( Vector3 col0 ); - - // Set column 1 of a 3x3 matrix - // - inline Matrix3 & setCol1( Vector3 col1 ); - - // Set column 2 of a 3x3 matrix - // - inline Matrix3 & setCol2( Vector3 col2 ); - - // Get column 0 of a 3x3 matrix - // - inline const Vector3 getCol0( ) const; - - // Get column 1 of a 3x3 matrix - // - inline const Vector3 getCol1( ) const; - - // Get column 2 of a 3x3 matrix - // - inline const Vector3 getCol2( ) const; - - // Set the column of a 3x3 matrix referred to by the specified index - // - inline Matrix3 & setCol( int col, Vector3 vec ); - - // Set the row of a 3x3 matrix referred to by the specified index - // - inline Matrix3 & setRow( int row, Vector3 vec ); - - // Get the column of a 3x3 matrix referred to by the specified index - // - inline const Vector3 getCol( int col ) const; - - // Get the row of a 3x3 matrix referred to by the specified index - // - inline const Vector3 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector3 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector3 operator []( int col ) const; - - // Set the element of a 3x3 matrix referred to by column and row indices - // - inline Matrix3 & setElem( int col, int row, float val ); - - // Set the element of a 3x3 matrix referred to by column and row indices (scalar data contained in vector data type) - // - inline Matrix3 & setElem( int col, int row, floatInVec val ); - - // Get the element of a 3x3 matrix referred to by column and row indices - // - inline const floatInVec getElem( int col, int row ) const; - - // Add two 3x3 matrices - // - inline const Matrix3 operator +( const Matrix3 & mat ) const; - - // Subtract a 3x3 matrix from another 3x3 matrix - // - inline const Matrix3 operator -( const Matrix3 & mat ) const; - - // Negate all elements of a 3x3 matrix - // - inline const Matrix3 operator -( ) const; - - // Multiply a 3x3 matrix by a scalar - // - inline const Matrix3 operator *( float scalar ) const; - - // Multiply a 3x3 matrix by a scalar (scalar data contained in vector data type) - // - inline const Matrix3 operator *( floatInVec scalar ) const; - - // Multiply a 3x3 matrix by a 3-D vector - // - inline const Vector3 operator *( Vector3 vec ) const; - - // Multiply two 3x3 matrices - // - inline const Matrix3 operator *( const Matrix3 & mat ) const; - - // Perform compound assignment and addition with a 3x3 matrix - // - inline Matrix3 & operator +=( const Matrix3 & mat ); - - // Perform compound assignment and subtraction by a 3x3 matrix - // - inline Matrix3 & operator -=( const Matrix3 & mat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Matrix3 & operator *=( float scalar ); - - // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) - // - inline Matrix3 & operator *=( floatInVec scalar ); - - // Perform compound assignment and multiplication by a 3x3 matrix - // - inline Matrix3 & operator *=( const Matrix3 & mat ); - - // Construct an identity 3x3 matrix - // - static inline const Matrix3 identity( ); - - // Construct a 3x3 matrix to rotate around the x axis - // - static inline const Matrix3 rotationX( float radians ); - - // Construct a 3x3 matrix to rotate around the y axis - // - static inline const Matrix3 rotationY( float radians ); - - // Construct a 3x3 matrix to rotate around the z axis - // - static inline const Matrix3 rotationZ( float radians ); - - // Construct a 3x3 matrix to rotate around the x axis (scalar data contained in vector data type) - // - static inline const Matrix3 rotationX( floatInVec radians ); - - // Construct a 3x3 matrix to rotate around the y axis (scalar data contained in vector data type) - // - static inline const Matrix3 rotationY( floatInVec radians ); - - // Construct a 3x3 matrix to rotate around the z axis (scalar data contained in vector data type) - // - static inline const Matrix3 rotationZ( floatInVec radians ); - - // Construct a 3x3 matrix to rotate around the x, y, and z axes - // - static inline const Matrix3 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 3x3 matrix to rotate around a unit-length 3-D vector - // - static inline const Matrix3 rotation( float radians, Vector3 unitVec ); - - // Construct a 3x3 matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) - // - static inline const Matrix3 rotation( floatInVec radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Matrix3 rotation( Quat unitQuat ); - - // Construct a 3x3 matrix to perform scaling - // - static inline const Matrix3 scale( Vector3 scaleVec ); - -}; -// Multiply a 3x3 matrix by a scalar -// -inline const Matrix3 operator *( float scalar, const Matrix3 & mat ); - -// Multiply a 3x3 matrix by a scalar (scalar data contained in vector data type) -// -inline const Matrix3 operator *( floatInVec scalar, const Matrix3 & mat ); - -// Append (post-multiply) a scale transformation to a 3x3 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 3x3 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ); - -// Multiply two 3x3 matrices per element -// -inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ); - -// Compute the absolute value of a 3x3 matrix per element -// -inline const Matrix3 absPerElem( const Matrix3 & mat ); - -// Transpose of a 3x3 matrix -// -inline const Matrix3 transpose( const Matrix3 & mat ); - -// Compute the inverse of a 3x3 matrix -// NOTE: -// Result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix3 inverse( const Matrix3 & mat ); - -// Determinant of a 3x3 matrix -// -inline const floatInVec determinant( const Matrix3 & mat ); - -// Conditionally select between two 3x3 matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ); - -// Conditionally select between two 3x3 matrices (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, boolInVec select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3x3 matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix3 & mat ); - -// Print a 3x3 matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix3 & mat, const char * name ); - -#endif - -// A 4x4 matrix in array-of-structures format -// -class Matrix4 -{ - Vector4 mCol0; - Vector4 mCol1; - Vector4 mCol2; - Vector4 mCol3; - -public: - // Default constructor; does no initialization - // - inline Matrix4( ) { }; - - // Copy a 4x4 matrix - // - inline Matrix4( const Matrix4 & mat ); - - // Construct a 4x4 matrix containing the specified columns - // - inline Matrix4( Vector4 col0, Vector4 col1, Vector4 col2, Vector4 col3 ); - - // Construct a 4x4 matrix from a 3x4 transformation matrix - // - explicit inline Matrix4( const Transform3 & mat ); - - // Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector - // - inline Matrix4( const Matrix3 & mat, Vector3 translateVec ); - - // Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector - // - inline Matrix4( Quat unitQuat, Vector3 translateVec ); - - // Set all elements of a 4x4 matrix to the same scalar value - // - explicit inline Matrix4( float scalar ); - - // Set all elements of a 4x4 matrix to the same scalar value (scalar data contained in vector data type) - // - explicit inline Matrix4( floatInVec scalar ); - - // Assign one 4x4 matrix to another - // - inline Matrix4 & operator =( const Matrix4 & mat ); - - // Set the upper-left 3x3 submatrix - // NOTE: - // This function does not change the bottom row elements. - // - inline Matrix4 & setUpper3x3( const Matrix3 & mat3 ); - - // Get the upper-left 3x3 submatrix of a 4x4 matrix - // - inline const Matrix3 getUpper3x3( ) const; - - // Set translation component - // NOTE: - // This function does not change the bottom row elements. - // - inline Matrix4 & setTranslation( Vector3 translateVec ); - - // Get the translation component of a 4x4 matrix - // - inline const Vector3 getTranslation( ) const; - - // Set column 0 of a 4x4 matrix - // - inline Matrix4 & setCol0( Vector4 col0 ); - - // Set column 1 of a 4x4 matrix - // - inline Matrix4 & setCol1( Vector4 col1 ); - - // Set column 2 of a 4x4 matrix - // - inline Matrix4 & setCol2( Vector4 col2 ); - - // Set column 3 of a 4x4 matrix - // - inline Matrix4 & setCol3( Vector4 col3 ); - - // Get column 0 of a 4x4 matrix - // - inline const Vector4 getCol0( ) const; - - // Get column 1 of a 4x4 matrix - // - inline const Vector4 getCol1( ) const; - - // Get column 2 of a 4x4 matrix - // - inline const Vector4 getCol2( ) const; - - // Get column 3 of a 4x4 matrix - // - inline const Vector4 getCol3( ) const; - - // Set the column of a 4x4 matrix referred to by the specified index - // - inline Matrix4 & setCol( int col, Vector4 vec ); - - // Set the row of a 4x4 matrix referred to by the specified index - // - inline Matrix4 & setRow( int row, Vector4 vec ); - - // Get the column of a 4x4 matrix referred to by the specified index - // - inline const Vector4 getCol( int col ) const; - - // Get the row of a 4x4 matrix referred to by the specified index - // - inline const Vector4 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector4 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector4 operator []( int col ) const; - - // Set the element of a 4x4 matrix referred to by column and row indices - // - inline Matrix4 & setElem( int col, int row, float val ); - - // Set the element of a 4x4 matrix referred to by column and row indices (scalar data contained in vector data type) - // - inline Matrix4 & setElem( int col, int row, floatInVec val ); - - // Get the element of a 4x4 matrix referred to by column and row indices - // - inline const floatInVec getElem( int col, int row ) const; - - // Add two 4x4 matrices - // - inline const Matrix4 operator +( const Matrix4 & mat ) const; - - // Subtract a 4x4 matrix from another 4x4 matrix - // - inline const Matrix4 operator -( const Matrix4 & mat ) const; - - // Negate all elements of a 4x4 matrix - // - inline const Matrix4 operator -( ) const; - - // Multiply a 4x4 matrix by a scalar - // - inline const Matrix4 operator *( float scalar ) const; - - // Multiply a 4x4 matrix by a scalar (scalar data contained in vector data type) - // - inline const Matrix4 operator *( floatInVec scalar ) const; - - // Multiply a 4x4 matrix by a 4-D vector - // - inline const Vector4 operator *( Vector4 vec ) const; - - // Multiply a 4x4 matrix by a 3-D vector - // - inline const Vector4 operator *( Vector3 vec ) const; - - // Multiply a 4x4 matrix by a 3-D point - // - inline const Vector4 operator *( Point3 pnt ) const; - - // Multiply two 4x4 matrices - // - inline const Matrix4 operator *( const Matrix4 & mat ) const; - - // Multiply a 4x4 matrix by a 3x4 transformation matrix - // - inline const Matrix4 operator *( const Transform3 & tfrm ) const; - - // Perform compound assignment and addition with a 4x4 matrix - // - inline Matrix4 & operator +=( const Matrix4 & mat ); - - // Perform compound assignment and subtraction by a 4x4 matrix - // - inline Matrix4 & operator -=( const Matrix4 & mat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Matrix4 & operator *=( float scalar ); - - // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) - // - inline Matrix4 & operator *=( floatInVec scalar ); - - // Perform compound assignment and multiplication by a 4x4 matrix - // - inline Matrix4 & operator *=( const Matrix4 & mat ); - - // Perform compound assignment and multiplication by a 3x4 transformation matrix - // - inline Matrix4 & operator *=( const Transform3 & tfrm ); - - // Construct an identity 4x4 matrix - // - static inline const Matrix4 identity( ); - - // Construct a 4x4 matrix to rotate around the x axis - // - static inline const Matrix4 rotationX( float radians ); - - // Construct a 4x4 matrix to rotate around the y axis - // - static inline const Matrix4 rotationY( float radians ); - - // Construct a 4x4 matrix to rotate around the z axis - // - static inline const Matrix4 rotationZ( float radians ); - - // Construct a 4x4 matrix to rotate around the x axis (scalar data contained in vector data type) - // - static inline const Matrix4 rotationX( floatInVec radians ); - - // Construct a 4x4 matrix to rotate around the y axis (scalar data contained in vector data type) - // - static inline const Matrix4 rotationY( floatInVec radians ); - - // Construct a 4x4 matrix to rotate around the z axis (scalar data contained in vector data type) - // - static inline const Matrix4 rotationZ( floatInVec radians ); - - // Construct a 4x4 matrix to rotate around the x, y, and z axes - // - static inline const Matrix4 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 4x4 matrix to rotate around a unit-length 3-D vector - // - static inline const Matrix4 rotation( float radians, Vector3 unitVec ); - - // Construct a 4x4 matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) - // - static inline const Matrix4 rotation( floatInVec radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Matrix4 rotation( Quat unitQuat ); - - // Construct a 4x4 matrix to perform scaling - // - static inline const Matrix4 scale( Vector3 scaleVec ); - - // Construct a 4x4 matrix to perform translation - // - static inline const Matrix4 translation( Vector3 translateVec ); - - // Construct viewing matrix based on eye position, position looked at, and up direction - // - static inline const Matrix4 lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ); - - // Construct a perspective projection matrix - // - static inline const Matrix4 perspective( float fovyRadians, float aspect, float zNear, float zFar ); - - // Construct a perspective projection matrix based on frustum - // - static inline const Matrix4 frustum( float left, float right, float bottom, float top, float zNear, float zFar ); - - // Construct an orthographic projection matrix - // - static inline const Matrix4 orthographic( float left, float right, float bottom, float top, float zNear, float zFar ); - -}; -// Multiply a 4x4 matrix by a scalar -// -inline const Matrix4 operator *( float scalar, const Matrix4 & mat ); - -// Multiply a 4x4 matrix by a scalar (scalar data contained in vector data type) -// -inline const Matrix4 operator *( floatInVec scalar, const Matrix4 & mat ); - -// Append (post-multiply) a scale transformation to a 4x4 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 4x4 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ); - -// Multiply two 4x4 matrices per element -// -inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ); - -// Compute the absolute value of a 4x4 matrix per element -// -inline const Matrix4 absPerElem( const Matrix4 & mat ); - -// Transpose of a 4x4 matrix -// -inline const Matrix4 transpose( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix -// NOTE: -// Result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix4 inverse( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix4 affineInverse( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. -// -inline const Matrix4 orthoInverse( const Matrix4 & mat ); - -// Determinant of a 4x4 matrix -// -inline const floatInVec determinant( const Matrix4 & mat ); - -// Conditionally select between two 4x4 matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ); - -// Conditionally select between two 4x4 matrices (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, boolInVec select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 4x4 matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix4 & mat ); - -// Print a 4x4 matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix4 & mat, const char * name ); - -#endif - -// A 3x4 transformation matrix in array-of-structures format -// -class Transform3 -{ - Vector3 mCol0; - Vector3 mCol1; - Vector3 mCol2; - Vector3 mCol3; - -public: - // Default constructor; does no initialization - // - inline Transform3( ) { }; - - // Copy a 3x4 transformation matrix - // - inline Transform3( const Transform3 & tfrm ); - - // Construct a 3x4 transformation matrix containing the specified columns - // - inline Transform3( Vector3 col0, Vector3 col1, Vector3 col2, Vector3 col3 ); - - // Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector - // - inline Transform3( const Matrix3 & tfrm, Vector3 translateVec ); - - // Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector - // - inline Transform3( Quat unitQuat, Vector3 translateVec ); - - // Set all elements of a 3x4 transformation matrix to the same scalar value - // - explicit inline Transform3( float scalar ); - - // Set all elements of a 3x4 transformation matrix to the same scalar value (scalar data contained in vector data type) - // - explicit inline Transform3( floatInVec scalar ); - - // Assign one 3x4 transformation matrix to another - // - inline Transform3 & operator =( const Transform3 & tfrm ); - - // Set the upper-left 3x3 submatrix - // - inline Transform3 & setUpper3x3( const Matrix3 & mat3 ); - - // Get the upper-left 3x3 submatrix of a 3x4 transformation matrix - // - inline const Matrix3 getUpper3x3( ) const; - - // Set translation component - // - inline Transform3 & setTranslation( Vector3 translateVec ); - - // Get the translation component of a 3x4 transformation matrix - // - inline const Vector3 getTranslation( ) const; - - // Set column 0 of a 3x4 transformation matrix - // - inline Transform3 & setCol0( Vector3 col0 ); - - // Set column 1 of a 3x4 transformation matrix - // - inline Transform3 & setCol1( Vector3 col1 ); - - // Set column 2 of a 3x4 transformation matrix - // - inline Transform3 & setCol2( Vector3 col2 ); - - // Set column 3 of a 3x4 transformation matrix - // - inline Transform3 & setCol3( Vector3 col3 ); - - // Get column 0 of a 3x4 transformation matrix - // - inline const Vector3 getCol0( ) const; - - // Get column 1 of a 3x4 transformation matrix - // - inline const Vector3 getCol1( ) const; - - // Get column 2 of a 3x4 transformation matrix - // - inline const Vector3 getCol2( ) const; - - // Get column 3 of a 3x4 transformation matrix - // - inline const Vector3 getCol3( ) const; - - // Set the column of a 3x4 transformation matrix referred to by the specified index - // - inline Transform3 & setCol( int col, Vector3 vec ); - - // Set the row of a 3x4 transformation matrix referred to by the specified index - // - inline Transform3 & setRow( int row, Vector4 vec ); - - // Get the column of a 3x4 transformation matrix referred to by the specified index - // - inline const Vector3 getCol( int col ) const; - - // Get the row of a 3x4 transformation matrix referred to by the specified index - // - inline const Vector4 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector3 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector3 operator []( int col ) const; - - // Set the element of a 3x4 transformation matrix referred to by column and row indices - // - inline Transform3 & setElem( int col, int row, float val ); - - // Set the element of a 3x4 transformation matrix referred to by column and row indices (scalar data contained in vector data type) - // - inline Transform3 & setElem( int col, int row, floatInVec val ); - - // Get the element of a 3x4 transformation matrix referred to by column and row indices - // - inline const floatInVec getElem( int col, int row ) const; - - // Multiply a 3x4 transformation matrix by a 3-D vector - // - inline const Vector3 operator *( Vector3 vec ) const; - - // Multiply a 3x4 transformation matrix by a 3-D point - // - inline const Point3 operator *( Point3 pnt ) const; - - // Multiply two 3x4 transformation matrices - // - inline const Transform3 operator *( const Transform3 & tfrm ) const; - - // Perform compound assignment and multiplication by a 3x4 transformation matrix - // - inline Transform3 & operator *=( const Transform3 & tfrm ); - - // Construct an identity 3x4 transformation matrix - // - static inline const Transform3 identity( ); - - // Construct a 3x4 transformation matrix to rotate around the x axis - // - static inline const Transform3 rotationX( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the y axis - // - static inline const Transform3 rotationY( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the z axis - // - static inline const Transform3 rotationZ( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the x axis (scalar data contained in vector data type) - // - static inline const Transform3 rotationX( floatInVec radians ); - - // Construct a 3x4 transformation matrix to rotate around the y axis (scalar data contained in vector data type) - // - static inline const Transform3 rotationY( floatInVec radians ); - - // Construct a 3x4 transformation matrix to rotate around the z axis (scalar data contained in vector data type) - // - static inline const Transform3 rotationZ( floatInVec radians ); - - // Construct a 3x4 transformation matrix to rotate around the x, y, and z axes - // - static inline const Transform3 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector - // - static inline const Transform3 rotation( float radians, Vector3 unitVec ); - - // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) - // - static inline const Transform3 rotation( floatInVec radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Transform3 rotation( Quat unitQuat ); - - // Construct a 3x4 transformation matrix to perform scaling - // - static inline const Transform3 scale( Vector3 scaleVec ); - - // Construct a 3x4 transformation matrix to perform translation - // - static inline const Transform3 translation( Vector3 translateVec ); - -}; -// Append (post-multiply) a scale transformation to a 3x4 transformation matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ); - -// Multiply two 3x4 transformation matrices per element -// -inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ); - -// Compute the absolute value of a 3x4 transformation matrix per element -// -inline const Transform3 absPerElem( const Transform3 & tfrm ); - -// Inverse of a 3x4 transformation matrix -// NOTE: -// Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. -// -inline const Transform3 inverse( const Transform3 & tfrm ); - -// Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. -// -inline const Transform3 orthoInverse( const Transform3 & tfrm ); - -// Conditionally select between two 3x4 transformation matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// However, the transfer of select1 to a VMX register may use more processing time than a branch. -// Use the boolInVec version for better performance. -// -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ); - -// Conditionally select between two 3x4 transformation matrices (scalar data contained in vector data type) -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, boolInVec select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3x4 transformation matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Transform3 & tfrm ); - -// Print a 3x4 transformation matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Transform3 & tfrm, const char * name ); - -#endif - -} // namespace Aos -} // namespace Vectormath - -#include "vec_aos.h" -#include "quat_aos.h" -#include "mat_aos.h" - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_AOS_CPP_PPU_H +#define _VECTORMATH_AOS_CPP_PPU_H + +#include +#include +#include "vecidx_aos.h" +#include "floatInVec.h" +#include "boolInVec.h" + +#ifdef _VECTORMATH_DEBUG +#include +#endif + +namespace Vectormath { + +namespace Aos { + +//----------------------------------------------------------------------------- +// Forward Declarations +// + +class Vector3; +class Vector4; +class Point3; +class Quat; +class Matrix3; +class Matrix4; +class Transform3; + +// A 3-D vector in array-of-structures format +// +class Vector3 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Vector3( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 3-D vector from x, y, and z elements + // + inline Vector3( float x, float y, float z ); + + // Construct a 3-D vector from x, y, and z elements (scalar data contained in vector data type) + // + inline Vector3( floatInVec x, floatInVec y, floatInVec z ); + + // Copy elements from a 3-D point into a 3-D vector + // + explicit inline Vector3( Point3 pnt ); + + // Set all elements of a 3-D vector to the same scalar value + // + explicit inline Vector3( float scalar ); + + // Set all elements of a 3-D vector to the same scalar value (scalar data contained in vector data type) + // + explicit inline Vector3( floatInVec scalar ); + + // Set vector float data in a 3-D vector + // + explicit inline Vector3( vec_float4 vf4 ); + + // Get vector float data from a 3-D vector + // + inline vec_float4 get128( ) const; + + // Assign one 3-D vector to another + // + inline Vector3 & operator =( Vector3 vec ); + + // Set the x element of a 3-D vector + // + inline Vector3 & setX( float x ); + + // Set the y element of a 3-D vector + // + inline Vector3 & setY( float y ); + + // Set the z element of a 3-D vector + // + inline Vector3 & setZ( float z ); + + // Set the x element of a 3-D vector (scalar data contained in vector data type) + // + inline Vector3 & setX( floatInVec x ); + + // Set the y element of a 3-D vector (scalar data contained in vector data type) + // + inline Vector3 & setY( floatInVec y ); + + // Set the z element of a 3-D vector (scalar data contained in vector data type) + // + inline Vector3 & setZ( floatInVec z ); + + // Get the x element of a 3-D vector + // + inline const floatInVec getX( ) const; + + // Get the y element of a 3-D vector + // + inline const floatInVec getY( ) const; + + // Get the z element of a 3-D vector + // + inline const floatInVec getZ( ) const; + + // Set an x, y, or z element of a 3-D vector by index + // + inline Vector3 & setElem( int idx, float value ); + + // Set an x, y, or z element of a 3-D vector by index (scalar data contained in vector data type) + // + inline Vector3 & setElem( int idx, floatInVec value ); + + // Get an x, y, or z element of a 3-D vector by index + // + inline const floatInVec getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline const floatInVec operator []( int idx ) const; + + // Add two 3-D vectors + // + inline const Vector3 operator +( Vector3 vec ) const; + + // Subtract a 3-D vector from another 3-D vector + // + inline const Vector3 operator -( Vector3 vec ) const; + + // Add a 3-D vector to a 3-D point + // + inline const Point3 operator +( Point3 pnt ) const; + + // Multiply a 3-D vector by a scalar + // + inline const Vector3 operator *( float scalar ) const; + + // Divide a 3-D vector by a scalar + // + inline const Vector3 operator /( float scalar ) const; + + // Multiply a 3-D vector by a scalar (scalar data contained in vector data type) + // + inline const Vector3 operator *( floatInVec scalar ) const; + + // Divide a 3-D vector by a scalar (scalar data contained in vector data type) + // + inline const Vector3 operator /( floatInVec scalar ) const; + + // Perform compound assignment and addition with a 3-D vector + // + inline Vector3 & operator +=( Vector3 vec ); + + // Perform compound assignment and subtraction by a 3-D vector + // + inline Vector3 & operator -=( Vector3 vec ); + + // Perform compound assignment and multiplication by a scalar + // + inline Vector3 & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Vector3 & operator /=( float scalar ); + + // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) + // + inline Vector3 & operator *=( floatInVec scalar ); + + // Perform compound assignment and division by a scalar (scalar data contained in vector data type) + // + inline Vector3 & operator /=( floatInVec scalar ); + + // Negate all elements of a 3-D vector + // + inline const Vector3 operator -( ) const; + + // Perform equality comparsion of two 3-D vector + // + inline bool operator == (const Vector3& vec) const; + + // Perform equality comparsion of two 3-D vector + // + inline bool operator != (const Vector3& vec) const; + + // Perform lower than comparsion of two 3-D vector + // + inline bool operator < (const Vector3& vec) const; + + // Perform lower or equal comparsion of two 3-D vector + // + inline bool operator <= (const Vector3& vec) const; + + // Perform greater than comparsion of two 3-D vector + // + inline bool operator > (const Vector3& vec) const; + + // Perform greater or equal comparsion of two 3-D vector + // + inline bool operator >= (const Vector3& vec) const; + + // Construct x axis + // + static inline const Vector3 xAxis( ); + + // Construct y axis + // + static inline const Vector3 yAxis( ); + + // Construct z axis + // + static inline const Vector3 zAxis( ); + +}; + +// Multiply a 3-D vector by a scalar +// +inline const Vector3 operator *( float scalar, Vector3 vec ); + +// Multiply a 3-D vector by a scalar (scalar data contained in vector data type) +// +inline const Vector3 operator *( floatInVec scalar, Vector3 vec ); + +// Multiply two 3-D vectors per element +// +inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ); + +// Divide two 3-D vectors per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ); + +// Compute the reciprocal of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Vector3 recipPerElem( Vector3 vec ); + +// Compute the square root of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Vector3 sqrtPerElem( Vector3 vec ); + +// Compute the reciprocal square root of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Vector3 rsqrtPerElem( Vector3 vec ); + +// Compute the absolute value of a 3-D vector per element +// +inline const Vector3 absPerElem( Vector3 vec ); + +// Copy sign from one 3-D vector to another, per element +// +inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ); + +// Maximum of two 3-D vectors per element +// +inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ); + +// Minimum of two 3-D vectors per element +// +inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ); + +// Maximum element of a 3-D vector +// +inline const floatInVec maxElem( Vector3 vec ); + +// Minimum element of a 3-D vector +// +inline const floatInVec minElem( Vector3 vec ); + +// Compute the sum of all elements of a 3-D vector +// +inline const floatInVec sum( Vector3 vec ); + +// Compute the dot product of two 3-D vectors +// +inline const floatInVec dot( Vector3 vec0, Vector3 vec1 ); + +// Compute the square of the length of a 3-D vector +// +inline const floatInVec lengthSqr( Vector3 vec ); + +// Compute the length of a 3-D vector +// +inline const floatInVec length( Vector3 vec ); + +// Normalize a 3-D vector +// NOTE: +// The result is unpredictable when all elements of vec are at or near zero. +// +inline const Vector3 normalize( Vector3 vec ); + +// Compute cross product of two 3-D vectors +// +inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ); + +// Outer product of two 3-D vectors +// +inline const Matrix3 outer( Vector3 vec0, Vector3 vec1 ); + +// Pre-multiply a row vector by a 3x3 matrix +// NOTE: +// Slower than column post-multiply. +// +inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ); + +// Cross-product matrix of a 3-D vector +// +inline const Matrix3 crossMatrix( Vector3 vec ); + +// Create cross-product matrix and multiply +// NOTE: +// Faster than separately creating a cross-product matrix and multiplying. +// +inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ); + +// Linear interpolation between two 3-D vectors +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ); + +// Linear interpolation between two 3-D vectors (scalar data contained in vector data type) +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector3 lerp( floatInVec t, Vector3 vec0, Vector3 vec1 ); + +// Spherical linear interpolation between two 3-D vectors +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ); + +// Spherical linear interpolation between two 3-D vectors (scalar data contained in vector data type) +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector3 slerp( floatInVec t, Vector3 unitVec0, Vector3 unitVec1 ); + +// Conditionally select between two 3-D vectors +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ); + +// Conditionally select between two 3-D vectors (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Vector3 select( Vector3 vec0, Vector3 vec1, boolInVec select1 ); + +// Load x, y, and z elements from the first three words of a quadword. +// +// +inline void loadXYZ( Vector3 & vec, const vec_float4 * quad ); + +// Load x, y, and z elements from the first three words of a float array. +// +// +inline void loadXYZ( Vector3 & vec, const float * fptr ); + +// Store x, y, and z elements of a 3-D vector in the first three words of a quadword. +// The value of the fourth word (the word with the highest address) remains unchanged +// +inline void storeXYZ( Vector3 vec, vec_float4 * quad ); + +// Store x, y, and z elements of a 3-D vector in the first three words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZ( Vector3 vec, float * fptr ); + +// Load four three-float 3-D vectors, stored in three quadwords +// +inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ); + +// Store four 3-D vectors in three quadwords +// +inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ); + +// Store eight 3-D vectors as half-floats +// +inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3-D vector +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector3 vec ); + +// Print a 3-D vector and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector3 vec, const char * name ); + +#endif + +// A 4-D vector in array-of-structures format +// +class Vector4 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Vector4( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 4-D vector from x, y, z, and w elements + // + inline Vector4( float x, float y, float z, float w ); + + // Construct a 4-D vector from x, y, z, and w elements (scalar data contained in vector data type) + // + inline Vector4( floatInVec x, floatInVec y, floatInVec z, floatInVec w ); + + // Construct a 4-D vector from a 3-D vector and a scalar + // + inline Vector4( Vector3 xyz, float w ); + + // Construct a 4-D vector from a 3-D vector and a scalar (scalar data contained in vector data type) + // + inline Vector4( Vector3 xyz, floatInVec w ); + + // Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 + // + explicit inline Vector4( Vector3 vec ); + + // Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 + // + explicit inline Vector4( Point3 pnt ); + + // Copy elements from a quaternion into a 4-D vector + // + explicit inline Vector4( Quat quat ); + + // Set all elements of a 4-D vector to the same scalar value + // + explicit inline Vector4( float scalar ); + + // Set all elements of a 4-D vector to the same scalar value (scalar data contained in vector data type) + // + explicit inline Vector4( floatInVec scalar ); + + // Set vector float data in a 4-D vector + // + explicit inline Vector4( vec_float4 vf4 ); + + // Get vector float data from a 4-D vector + // + inline vec_float4 get128( ) const; + + // Assign one 4-D vector to another + // + inline Vector4 & operator =( Vector4 vec ); + + // Set the x, y, and z elements of a 4-D vector + // NOTE: + // This function does not change the w element. + // + inline Vector4 & setXYZ( Vector3 vec ); + + // Get the x, y, and z elements of a 4-D vector + // + inline const Vector3 getXYZ( ) const; + + // Set the x element of a 4-D vector + // + inline Vector4 & setX( float x ); + + // Set the y element of a 4-D vector + // + inline Vector4 & setY( float y ); + + // Set the z element of a 4-D vector + // + inline Vector4 & setZ( float z ); + + // Set the w element of a 4-D vector + // + inline Vector4 & setW( float w ); + + // Set the x element of a 4-D vector (scalar data contained in vector data type) + // + inline Vector4 & setX( floatInVec x ); + + // Set the y element of a 4-D vector (scalar data contained in vector data type) + // + inline Vector4 & setY( floatInVec y ); + + // Set the z element of a 4-D vector (scalar data contained in vector data type) + // + inline Vector4 & setZ( floatInVec z ); + + // Set the w element of a 4-D vector (scalar data contained in vector data type) + // + inline Vector4 & setW( floatInVec w ); + + // Get the x element of a 4-D vector + // + inline const floatInVec getX( ) const; + + // Get the y element of a 4-D vector + // + inline const floatInVec getY( ) const; + + // Get the z element of a 4-D vector + // + inline const floatInVec getZ( ) const; + + // Get the w element of a 4-D vector + // + inline const floatInVec getW( ) const; + + // Set an x, y, z, or w element of a 4-D vector by index + // + inline Vector4 & setElem( int idx, float value ); + + // Set an x, y, z, or w element of a 4-D vector by index (scalar data contained in vector data type) + // + inline Vector4 & setElem( int idx, floatInVec value ); + + // Get an x, y, z, or w element of a 4-D vector by index + // + inline const floatInVec getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline const floatInVec operator []( int idx ) const; + + // Add two 4-D vectors + // + inline const Vector4 operator +( Vector4 vec ) const; + + // Subtract a 4-D vector from another 4-D vector + // + inline const Vector4 operator -( Vector4 vec ) const; + + // Multiply a 4-D vector by a scalar + // + inline const Vector4 operator *( float scalar ) const; + + // Divide a 4-D vector by a scalar + // + inline const Vector4 operator /( float scalar ) const; + + // Multiply a 4-D vector by a scalar (scalar data contained in vector data type) + // + inline const Vector4 operator *( floatInVec scalar ) const; + + // Divide a 4-D vector by a scalar (scalar data contained in vector data type) + // + inline const Vector4 operator /( floatInVec scalar ) const; + + // Perform compound assignment and addition with a 4-D vector + // + inline Vector4 & operator +=( Vector4 vec ); + + // Perform compound assignment and subtraction by a 4-D vector + // + inline Vector4 & operator -=( Vector4 vec ); + + // Perform compound assignment and multiplication by a scalar + // + inline Vector4 & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Vector4 & operator /=( float scalar ); + + // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) + // + inline Vector4 & operator *=( floatInVec scalar ); + + // Perform compound assignment and division by a scalar (scalar data contained in vector data type) + // + inline Vector4 & operator /=( floatInVec scalar ); + + // Negate all elements of a 4-D vector + // + inline const Vector4 operator -( ) const; + + // Perform equality comparsion of two 4-D vector + // + inline bool operator == (const Vector4& vec) const; + + // Perform equality comparsion of two 4-D vector + // + inline bool operator != (const Vector4& vec) const; + + // Perform lower than comparsion of two 4-D vector + // + inline bool operator < (const Vector4& vec) const; + + // Perform lower or equal comparsion of two 4-D vector + // + inline bool operator <= (const Vector4& vec) const; + + // Perform greater than comparsion of two 4-D vector + // + inline bool operator > (const Vector4& vec) const; + + // Perform greater or equal comparsion of two 4-D vector + // + inline bool operator >= (const Vector4& vec) const; + + // Construct x axis + // + static inline const Vector4 xAxis( ); + + // Construct y axis + // + static inline const Vector4 yAxis( ); + + // Construct z axis + // + static inline const Vector4 zAxis( ); + + // Construct w axis + // + static inline const Vector4 wAxis( ); + +}; + +// Multiply a 4-D vector by a scalar +// +inline const Vector4 operator *( float scalar, Vector4 vec ); + +// Multiply a 4-D vector by a scalar (scalar data contained in vector data type) +// +inline const Vector4 operator *( floatInVec scalar, Vector4 vec ); + +// Multiply two 4-D vectors per element +// +inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ); + +// Divide two 4-D vectors per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ); + +// Compute the reciprocal of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Vector4 recipPerElem( Vector4 vec ); + +// Compute the square root of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Vector4 sqrtPerElem( Vector4 vec ); + +// Compute the reciprocal square root of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Vector4 rsqrtPerElem( Vector4 vec ); + +// Compute the absolute value of a 4-D vector per element +// +inline const Vector4 absPerElem( Vector4 vec ); + +// Copy sign from one 4-D vector to another, per element +// +inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ); + +// Maximum of two 4-D vectors per element +// +inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ); + +// Minimum of two 4-D vectors per element +// +inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ); + +// Maximum element of a 4-D vector +// +inline const floatInVec maxElem( Vector4 vec ); + +// Minimum element of a 4-D vector +// +inline const floatInVec minElem( Vector4 vec ); + +// Compute the sum of all elements of a 4-D vector +// +inline const floatInVec sum( Vector4 vec ); + +// Compute the dot product of two 4-D vectors +// +inline const floatInVec dot( Vector4 vec0, Vector4 vec1 ); + +// Compute the square of the length of a 4-D vector +// +inline const floatInVec lengthSqr( Vector4 vec ); + +// Compute the length of a 4-D vector +// +inline const floatInVec length( Vector4 vec ); + +// Normalize a 4-D vector +// NOTE: +// The result is unpredictable when all elements of vec are at or near zero. +// +inline const Vector4 normalize( Vector4 vec ); + +// Outer product of two 4-D vectors +// +inline const Matrix4 outer( Vector4 vec0, Vector4 vec1 ); + +// Linear interpolation between two 4-D vectors +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ); + +// Linear interpolation between two 4-D vectors (scalar data contained in vector data type) +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector4 lerp( floatInVec t, Vector4 vec0, Vector4 vec1 ); + +// Spherical linear interpolation between two 4-D vectors +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ); + +// Spherical linear interpolation between two 4-D vectors (scalar data contained in vector data type) +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector4 slerp( floatInVec t, Vector4 unitVec0, Vector4 unitVec1 ); + +// Conditionally select between two 4-D vectors +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ); + +// Conditionally select between two 4-D vectors (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Vector4 select( Vector4 vec0, Vector4 vec1, boolInVec select1 ); + +// Store four 4-D vectors as half-floats +// +inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ); + +// Load x, y, z, and w elements from the first four words of a float array. +// +// +inline void loadXYZW( Vector4 & vec, const float * fptr ); + +// Store x, y, z, and w elements of a 4-D vector in the first four words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZW( Vector4 vec, float * fptr ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 4-D vector +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector4 vec ); + +// Print a 4-D vector and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector4 vec, const char * name ); + +#endif + +// A 3-D point in array-of-structures format +// +class Point3 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Point3( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 3-D point from x, y, and z elements + // + inline Point3( float x, float y, float z ); + + // Construct a 3-D point from x, y, and z elements (scalar data contained in vector data type) + // + inline Point3( floatInVec x, floatInVec y, floatInVec z ); + + // Copy elements from a 3-D vector into a 3-D point + // + explicit inline Point3( Vector3 vec ); + + // Set all elements of a 3-D point to the same scalar value + // + explicit inline Point3( float scalar ); + + // Set all elements of a 3-D point to the same scalar value (scalar data contained in vector data type) + // + explicit inline Point3( floatInVec scalar ); + + // Set vector float data in a 3-D point + // + explicit inline Point3( vec_float4 vf4 ); + + // Get vector float data from a 3-D point + // + inline vec_float4 get128( ) const; + + // Assign one 3-D point to another + // + inline Point3 & operator =( Point3 pnt ); + + // Set the x element of a 3-D point + // + inline Point3 & setX( float x ); + + // Set the y element of a 3-D point + // + inline Point3 & setY( float y ); + + // Set the z element of a 3-D point + // + inline Point3 & setZ( float z ); + + // Set the x element of a 3-D point (scalar data contained in vector data type) + // + inline Point3 & setX( floatInVec x ); + + // Set the y element of a 3-D point (scalar data contained in vector data type) + // + inline Point3 & setY( floatInVec y ); + + // Set the z element of a 3-D point (scalar data contained in vector data type) + // + inline Point3 & setZ( floatInVec z ); + + // Get the x element of a 3-D point + // + inline const floatInVec getX( ) const; + + // Get the y element of a 3-D point + // + inline const floatInVec getY( ) const; + + // Get the z element of a 3-D point + // + inline const floatInVec getZ( ) const; + + // Set an x, y, or z element of a 3-D point by index + // + inline Point3 & setElem( int idx, float value ); + + // Set an x, y, or z element of a 3-D point by index (scalar data contained in vector data type) + // + inline Point3 & setElem( int idx, floatInVec value ); + + // Get an x, y, or z element of a 3-D point by index + // + inline const floatInVec getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline const floatInVec operator []( int idx ) const; + + // Subtract a 3-D point from another 3-D point + // + inline const Vector3 operator -( Point3 pnt ) const; + + // Add a 3-D point to a 3-D vector + // + inline const Point3 operator +( Vector3 vec ) const; + + // Subtract a 3-D vector from a 3-D point + // + inline const Point3 operator -( Vector3 vec ) const; + + // Perform compound assignment and addition with a 3-D vector + // + inline Point3 & operator +=( Vector3 vec ); + + // Perform compound assignment and subtraction by a 3-D vector + // + inline Point3 & operator -=( Vector3 vec ); + + // Perform equality comparsion of two 3-D point + // + inline bool operator == (const Point3& vec) const; + + // Perform equality comparsion of two 3-D point + // + inline bool operator != (const Point3& vec) const; + + // Perform lower than comparsion of two 3-D point + // + inline bool operator < (const Point3& vec) const; + + // Perform lower or equal comparsion of two 3-D point + // + inline bool operator <= (const Point3& vec) const; + + // Perform greater than comparsion of two 3-D point + // + inline bool operator > (const Point3& vec) const; + + // Perform greater or equal comparsion of two 3-D point + // + inline bool operator >= (const Point3& vec) const; +}; + +// Multiply two 3-D points per element +// +inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ); + +// Divide two 3-D points per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ); + +// Compute the reciprocal of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Point3 recipPerElem( Point3 pnt ); + +// Compute the square root of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Point3 sqrtPerElem( Point3 pnt ); + +// Compute the reciprocal square root of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Point3 rsqrtPerElem( Point3 pnt ); + +// Compute the absolute value of a 3-D point per element +// +inline const Point3 absPerElem( Point3 pnt ); + +// Copy sign from one 3-D point to another, per element +// +inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ); + +// Maximum of two 3-D points per element +// +inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ); + +// Minimum of two 3-D points per element +// +inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ); + +// Maximum element of a 3-D point +// +inline const floatInVec maxElem( Point3 pnt ); + +// Minimum element of a 3-D point +// +inline const floatInVec minElem( Point3 pnt ); + +// Compute the sum of all elements of a 3-D point +// +inline const floatInVec sum( Point3 pnt ); + +// Apply uniform scale to a 3-D point +// +inline const Point3 scale( Point3 pnt, float scaleVal ); + +// Apply uniform scale to a 3-D point (scalar data contained in vector data type) +// +inline const Point3 scale( Point3 pnt, floatInVec scaleVal ); + +// Apply non-uniform scale to a 3-D point +// +inline const Point3 scale( Point3 pnt, Vector3 scaleVec ); + +// Scalar projection of a 3-D point on a unit-length 3-D vector +// +inline const floatInVec projection( Point3 pnt, Vector3 unitVec ); + +// Compute the square of the distance of a 3-D point from the coordinate-system origin +// +inline const floatInVec distSqrFromOrigin( Point3 pnt ); + +// Compute the distance of a 3-D point from the coordinate-system origin +// +inline const floatInVec distFromOrigin( Point3 pnt ); + +// Compute the square of the distance between two 3-D points +// +inline const floatInVec distSqr( Point3 pnt0, Point3 pnt1 ); + +// Compute the distance between two 3-D points +// +inline const floatInVec dist( Point3 pnt0, Point3 pnt1 ); + +// Linear interpolation between two 3-D points +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ); + +// Linear interpolation between two 3-D points (scalar data contained in vector data type) +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Point3 lerp( floatInVec t, Point3 pnt0, Point3 pnt1 ); + +// Conditionally select between two 3-D points +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ); + +// Conditionally select between two 3-D points (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Point3 select( Point3 pnt0, Point3 pnt1, boolInVec select1 ); + +// Load x, y, and z elements from the first three words of a quadword. +// +// +inline void loadXYZ( Point3 & pnt, const vec_float4 * quad ); + +// Load x, y, and z elements from the first three words of a float array. +// +// +inline void loadXYZ( Point3 & pnt, const float * fptr ); + +// Store x, y, and z elements of a 3-D point in the first three words of a quadword. +// The value of the fourth word (the word with the highest address) remains unchanged +// +inline void storeXYZ( Point3 pnt, vec_float4 * quad ); + +// Store x, y, and z elements of a 3-D point in the first three words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZ( Point3 pnt, float * fptr ); + +// Load four three-float 3-D points, stored in three quadwords +// +inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ); + +// Store four 3-D points in three quadwords +// +inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ); + +// Store eight 3-D points as half-floats +// +inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3-D point +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Point3 pnt ); + +// Print a 3-D point and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Point3 pnt, const char * name ); + +#endif + +// A quaternion in array-of-structures format +// +class Quat +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Quat( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a quaternion from x, y, z, and w elements + // + inline Quat( float x, float y, float z, float w ); + + // Construct a quaternion from x, y, z, and w elements (scalar data contained in vector data type) + // + inline Quat( floatInVec x, floatInVec y, floatInVec z, floatInVec w ); + + // Construct a quaternion from a 3-D vector and a scalar + // + inline Quat( Vector3 xyz, float w ); + + // Construct a quaternion from a 3-D vector and a scalar (scalar data contained in vector data type) + // + inline Quat( Vector3 xyz, floatInVec w ); + + // Copy elements from a 4-D vector into a quaternion + // + explicit inline Quat( Vector4 vec ); + + // Convert a rotation matrix to a unit-length quaternion + // + explicit inline Quat( const Matrix3 & rotMat ); + + // Set all elements of a quaternion to the same scalar value + // + explicit inline Quat( float scalar ); + + // Set all elements of a quaternion to the same scalar value (scalar data contained in vector data type) + // + explicit inline Quat( floatInVec scalar ); + + // Set vector float data in a quaternion + // + explicit inline Quat( vec_float4 vf4 ); + + // Get vector float data from a quaternion + // + inline vec_float4 get128( ) const; + + // Assign one quaternion to another + // + inline Quat & operator =( Quat quat ); + + // Set the x, y, and z elements of a quaternion + // NOTE: + // This function does not change the w element. + // + inline Quat & setXYZ( Vector3 vec ); + + // Get the x, y, and z elements of a quaternion + // + inline const Vector3 getXYZ( ) const; + + // Set the x element of a quaternion + // + inline Quat & setX( float x ); + + // Set the y element of a quaternion + // + inline Quat & setY( float y ); + + // Set the z element of a quaternion + // + inline Quat & setZ( float z ); + + // Set the w element of a quaternion + // + inline Quat & setW( float w ); + + // Set the x element of a quaternion (scalar data contained in vector data type) + // + inline Quat & setX( floatInVec x ); + + // Set the y element of a quaternion (scalar data contained in vector data type) + // + inline Quat & setY( floatInVec y ); + + // Set the z element of a quaternion (scalar data contained in vector data type) + // + inline Quat & setZ( floatInVec z ); + + // Set the w element of a quaternion (scalar data contained in vector data type) + // + inline Quat & setW( floatInVec w ); + + // Get the x element of a quaternion + // + inline const floatInVec getX( ) const; + + // Get the y element of a quaternion + // + inline const floatInVec getY( ) const; + + // Get the z element of a quaternion + // + inline const floatInVec getZ( ) const; + + // Get the w element of a quaternion + // + inline const floatInVec getW( ) const; + + // Set an x, y, z, or w element of a quaternion by index + // + inline Quat & setElem( int idx, float value ); + + // Set an x, y, z, or w element of a quaternion by index (scalar data contained in vector data type) + // + inline Quat & setElem( int idx, floatInVec value ); + + // Get an x, y, z, or w element of a quaternion by index + // + inline const floatInVec getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline const floatInVec operator []( int idx ) const; + + // Add two quaternions + // + inline const Quat operator +( Quat quat ) const; + + // Subtract a quaternion from another quaternion + // + inline const Quat operator -( Quat quat ) const; + + // Multiply two quaternions + // + inline const Quat operator *( Quat quat ) const; + + // Multiply a quaternion by a scalar + // + inline const Quat operator *( float scalar ) const; + + // Divide a quaternion by a scalar + // + inline const Quat operator /( float scalar ) const; + + // Multiply a quaternion by a scalar (scalar data contained in vector data type) + // + inline const Quat operator *( floatInVec scalar ) const; + + // Divide a quaternion by a scalar (scalar data contained in vector data type) + // + inline const Quat operator /( floatInVec scalar ) const; + + // Perform compound assignment and addition with a quaternion + // + inline Quat & operator +=( Quat quat ); + + // Perform compound assignment and subtraction by a quaternion + // + inline Quat & operator -=( Quat quat ); + + // Perform compound assignment and multiplication by a quaternion + // + inline Quat & operator *=( Quat quat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Quat & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Quat & operator /=( float scalar ); + + // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) + // + inline Quat & operator *=( floatInVec scalar ); + + // Perform compound assignment and division by a scalar (scalar data contained in vector data type) + // + inline Quat & operator /=( floatInVec scalar ); + + // Negate all elements of a quaternion + // + inline const Quat operator -( ) const; + + // Construct an identity quaternion + // + static inline const Quat identity( ); + + // Construct a quaternion to rotate between two unit-length 3-D vectors + // NOTE: + // The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. + // + static inline const Quat rotation( Vector3 unitVec0, Vector3 unitVec1 ); + + // Construct a quaternion to rotate around a unit-length 3-D vector + // + static inline const Quat rotation( float radians, Vector3 unitVec ); + + // Construct a quaternion to rotate around a unit-length 3-D vector (scalar data contained in vector data type) + // + static inline const Quat rotation( floatInVec radians, Vector3 unitVec ); + + // Construct a quaternion to rotate around the x axis + // + static inline const Quat rotationX( float radians ); + + // Construct a quaternion to rotate around the y axis + // + static inline const Quat rotationY( float radians ); + + // Construct a quaternion to rotate around the z axis + // + static inline const Quat rotationZ( float radians ); + + // Construct a quaternion to rotate around the x axis (scalar data contained in vector data type) + // + static inline const Quat rotationX( floatInVec radians ); + + // Construct a quaternion to rotate around the y axis (scalar data contained in vector data type) + // + static inline const Quat rotationY( floatInVec radians ); + + // Construct a quaternion to rotate around the z axis (scalar data contained in vector data type) + // + static inline const Quat rotationZ( floatInVec radians ); + +}; + +// Multiply a quaternion by a scalar +// +inline const Quat operator *( float scalar, Quat quat ); + +// Multiply a quaternion by a scalar (scalar data contained in vector data type) +// +inline const Quat operator *( floatInVec scalar, Quat quat ); + +// Compute the conjugate of a quaternion +// +inline const Quat conj( Quat quat ); + +// Use a unit-length quaternion to rotate a 3-D vector +// +inline const Vector3 rotate( Quat unitQuat, Vector3 vec ); + +// Compute the dot product of two quaternions +// +inline const floatInVec dot( Quat quat0, Quat quat1 ); + +// Compute the norm of a quaternion +// +inline const floatInVec norm( Quat quat ); + +// Compute the length of a quaternion +// +inline const floatInVec length( Quat quat ); + +// Normalize a quaternion +// NOTE: +// The result is unpredictable when all elements of quat are at or near zero. +// +inline const Quat normalize( Quat quat ); + +// Linear interpolation between two quaternions +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Quat lerp( float t, Quat quat0, Quat quat1 ); + +// Linear interpolation between two quaternions (scalar data contained in vector data type) +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Quat lerp( floatInVec t, Quat quat0, Quat quat1 ); + +// Spherical linear interpolation between two quaternions +// NOTE: +// Interpolates along the shortest path between orientations. +// Does not clamp t between 0 and 1. +// +inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ); + +// Spherical linear interpolation between two quaternions (scalar data contained in vector data type) +// NOTE: +// Interpolates along the shortest path between orientations. +// Does not clamp t between 0 and 1. +// +inline const Quat slerp( floatInVec t, Quat unitQuat0, Quat unitQuat1 ); + +// Spherical quadrangle interpolation +// +inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); + +// Spherical quadrangle interpolation (scalar data contained in vector data type) +// +inline const Quat squad( floatInVec t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); + +// Load x, y, z, and w elements from the first four words of a float array. +// +// +inline void loadXYZW( Quat & quat, const float * fptr ); + +// Store x, y, z, and w elements of a quaternion in the first four words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZW( Quat quat, float * fptr ); + +// Conditionally select between two quaternions +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Quat select( Quat quat0, Quat quat1, bool select1 ); + +// Conditionally select between two quaternions (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Quat select( Quat quat0, Quat quat1, boolInVec select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a quaternion +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Quat quat ); + +// Print a quaternion and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Quat quat, const char * name ); + +#endif + +// A 3x3 matrix in array-of-structures format +// +class Matrix3 +{ + Vector3 mCol0; + Vector3 mCol1; + Vector3 mCol2; + +public: + // Default constructor; does no initialization + // + inline Matrix3( ) { }; + + // Copy a 3x3 matrix + // + inline Matrix3( const Matrix3 & mat ); + + // Construct a 3x3 matrix containing the specified columns + // + inline Matrix3( Vector3 col0, Vector3 col1, Vector3 col2 ); + + // Construct a 3x3 rotation matrix from a unit-length quaternion + // + explicit inline Matrix3( Quat unitQuat ); + + // Set all elements of a 3x3 matrix to the same scalar value + // + explicit inline Matrix3( float scalar ); + + // Set all elements of a 3x3 matrix to the same scalar value (scalar data contained in vector data type) + // + explicit inline Matrix3( floatInVec scalar ); + + // Assign one 3x3 matrix to another + // + inline Matrix3 & operator =( const Matrix3 & mat ); + + // Set column 0 of a 3x3 matrix + // + inline Matrix3 & setCol0( Vector3 col0 ); + + // Set column 1 of a 3x3 matrix + // + inline Matrix3 & setCol1( Vector3 col1 ); + + // Set column 2 of a 3x3 matrix + // + inline Matrix3 & setCol2( Vector3 col2 ); + + // Get column 0 of a 3x3 matrix + // + inline const Vector3 getCol0( ) const; + + // Get column 1 of a 3x3 matrix + // + inline const Vector3 getCol1( ) const; + + // Get column 2 of a 3x3 matrix + // + inline const Vector3 getCol2( ) const; + + // Set the column of a 3x3 matrix referred to by the specified index + // + inline Matrix3 & setCol( int col, Vector3 vec ); + + // Set the row of a 3x3 matrix referred to by the specified index + // + inline Matrix3 & setRow( int row, Vector3 vec ); + + // Get the column of a 3x3 matrix referred to by the specified index + // + inline const Vector3 getCol( int col ) const; + + // Get the row of a 3x3 matrix referred to by the specified index + // + inline const Vector3 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector3 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector3 operator []( int col ) const; + + // Set the element of a 3x3 matrix referred to by column and row indices + // + inline Matrix3 & setElem( int col, int row, float val ); + + // Set the element of a 3x3 matrix referred to by column and row indices (scalar data contained in vector data type) + // + inline Matrix3 & setElem( int col, int row, floatInVec val ); + + // Get the element of a 3x3 matrix referred to by column and row indices + // + inline const floatInVec getElem( int col, int row ) const; + + // Add two 3x3 matrices + // + inline const Matrix3 operator +( const Matrix3 & mat ) const; + + // Subtract a 3x3 matrix from another 3x3 matrix + // + inline const Matrix3 operator -( const Matrix3 & mat ) const; + + // Negate all elements of a 3x3 matrix + // + inline const Matrix3 operator -( ) const; + + // Multiply a 3x3 matrix by a scalar + // + inline const Matrix3 operator *( float scalar ) const; + + // Multiply a 3x3 matrix by a scalar (scalar data contained in vector data type) + // + inline const Matrix3 operator *( floatInVec scalar ) const; + + // Multiply a 3x3 matrix by a 3-D vector + // + inline const Vector3 operator *( Vector3 vec ) const; + + // Multiply two 3x3 matrices + // + inline const Matrix3 operator *( const Matrix3 & mat ) const; + + // Perform compound assignment and addition with a 3x3 matrix + // + inline Matrix3 & operator +=( const Matrix3 & mat ); + + // Perform compound assignment and subtraction by a 3x3 matrix + // + inline Matrix3 & operator -=( const Matrix3 & mat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Matrix3 & operator *=( float scalar ); + + // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) + // + inline Matrix3 & operator *=( floatInVec scalar ); + + // Perform compound assignment and multiplication by a 3x3 matrix + // + inline Matrix3 & operator *=( const Matrix3 & mat ); + + // Construct an identity 3x3 matrix + // + static inline const Matrix3 identity( ); + + // Construct a 3x3 matrix to rotate around the x axis + // + static inline const Matrix3 rotationX( float radians ); + + // Construct a 3x3 matrix to rotate around the y axis + // + static inline const Matrix3 rotationY( float radians ); + + // Construct a 3x3 matrix to rotate around the z axis + // + static inline const Matrix3 rotationZ( float radians ); + + // Construct a 3x3 matrix to rotate around the x axis (scalar data contained in vector data type) + // + static inline const Matrix3 rotationX( floatInVec radians ); + + // Construct a 3x3 matrix to rotate around the y axis (scalar data contained in vector data type) + // + static inline const Matrix3 rotationY( floatInVec radians ); + + // Construct a 3x3 matrix to rotate around the z axis (scalar data contained in vector data type) + // + static inline const Matrix3 rotationZ( floatInVec radians ); + + // Construct a 3x3 matrix to rotate around the x, y, and z axes + // + static inline const Matrix3 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 3x3 matrix to rotate around a unit-length 3-D vector + // + static inline const Matrix3 rotation( float radians, Vector3 unitVec ); + + // Construct a 3x3 matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) + // + static inline const Matrix3 rotation( floatInVec radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Matrix3 rotation( Quat unitQuat ); + + // Construct a 3x3 matrix to perform scaling + // + static inline const Matrix3 scale( Vector3 scaleVec ); + +}; +// Multiply a 3x3 matrix by a scalar +// +inline const Matrix3 operator *( float scalar, const Matrix3 & mat ); + +// Multiply a 3x3 matrix by a scalar (scalar data contained in vector data type) +// +inline const Matrix3 operator *( floatInVec scalar, const Matrix3 & mat ); + +// Append (post-multiply) a scale transformation to a 3x3 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 3x3 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ); + +// Multiply two 3x3 matrices per element +// +inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ); + +// Compute the absolute value of a 3x3 matrix per element +// +inline const Matrix3 absPerElem( const Matrix3 & mat ); + +// Transpose of a 3x3 matrix +// +inline const Matrix3 transpose( const Matrix3 & mat ); + +// Compute the inverse of a 3x3 matrix +// NOTE: +// Result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix3 inverse( const Matrix3 & mat ); + +// Determinant of a 3x3 matrix +// +inline const floatInVec determinant( const Matrix3 & mat ); + +// Conditionally select between two 3x3 matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ); + +// Conditionally select between two 3x3 matrices (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, boolInVec select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3x3 matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix3 & mat ); + +// Print a 3x3 matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix3 & mat, const char * name ); + +#endif + +// A 4x4 matrix in array-of-structures format +// +class Matrix4 +{ + Vector4 mCol0; + Vector4 mCol1; + Vector4 mCol2; + Vector4 mCol3; + +public: + // Default constructor; does no initialization + // + inline Matrix4( ) { }; + + // Copy a 4x4 matrix + // + inline Matrix4( const Matrix4 & mat ); + + // Construct a 4x4 matrix containing the specified columns + // + inline Matrix4( Vector4 col0, Vector4 col1, Vector4 col2, Vector4 col3 ); + + // Construct a 4x4 matrix from a 3x4 transformation matrix + // + explicit inline Matrix4( const Transform3 & mat ); + + // Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector + // + inline Matrix4( const Matrix3 & mat, Vector3 translateVec ); + + // Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector + // + inline Matrix4( Quat unitQuat, Vector3 translateVec ); + + // Set all elements of a 4x4 matrix to the same scalar value + // + explicit inline Matrix4( float scalar ); + + // Set all elements of a 4x4 matrix to the same scalar value (scalar data contained in vector data type) + // + explicit inline Matrix4( floatInVec scalar ); + + // Assign one 4x4 matrix to another + // + inline Matrix4 & operator =( const Matrix4 & mat ); + + // Set the upper-left 3x3 submatrix + // NOTE: + // This function does not change the bottom row elements. + // + inline Matrix4 & setUpper3x3( const Matrix3 & mat3 ); + + // Get the upper-left 3x3 submatrix of a 4x4 matrix + // + inline const Matrix3 getUpper3x3( ) const; + + // Set translation component + // NOTE: + // This function does not change the bottom row elements. + // + inline Matrix4 & setTranslation( Vector3 translateVec ); + + // Get the translation component of a 4x4 matrix + // + inline const Vector3 getTranslation( ) const; + + // Set column 0 of a 4x4 matrix + // + inline Matrix4 & setCol0( Vector4 col0 ); + + // Set column 1 of a 4x4 matrix + // + inline Matrix4 & setCol1( Vector4 col1 ); + + // Set column 2 of a 4x4 matrix + // + inline Matrix4 & setCol2( Vector4 col2 ); + + // Set column 3 of a 4x4 matrix + // + inline Matrix4 & setCol3( Vector4 col3 ); + + // Get column 0 of a 4x4 matrix + // + inline const Vector4 getCol0( ) const; + + // Get column 1 of a 4x4 matrix + // + inline const Vector4 getCol1( ) const; + + // Get column 2 of a 4x4 matrix + // + inline const Vector4 getCol2( ) const; + + // Get column 3 of a 4x4 matrix + // + inline const Vector4 getCol3( ) const; + + // Set the column of a 4x4 matrix referred to by the specified index + // + inline Matrix4 & setCol( int col, Vector4 vec ); + + // Set the row of a 4x4 matrix referred to by the specified index + // + inline Matrix4 & setRow( int row, Vector4 vec ); + + // Get the column of a 4x4 matrix referred to by the specified index + // + inline const Vector4 getCol( int col ) const; + + // Get the row of a 4x4 matrix referred to by the specified index + // + inline const Vector4 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector4 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector4 operator []( int col ) const; + + // Set the element of a 4x4 matrix referred to by column and row indices + // + inline Matrix4 & setElem( int col, int row, float val ); + + // Set the element of a 4x4 matrix referred to by column and row indices (scalar data contained in vector data type) + // + inline Matrix4 & setElem( int col, int row, floatInVec val ); + + // Get the element of a 4x4 matrix referred to by column and row indices + // + inline const floatInVec getElem( int col, int row ) const; + + // Add two 4x4 matrices + // + inline const Matrix4 operator +( const Matrix4 & mat ) const; + + // Subtract a 4x4 matrix from another 4x4 matrix + // + inline const Matrix4 operator -( const Matrix4 & mat ) const; + + // Negate all elements of a 4x4 matrix + // + inline const Matrix4 operator -( ) const; + + // Multiply a 4x4 matrix by a scalar + // + inline const Matrix4 operator *( float scalar ) const; + + // Multiply a 4x4 matrix by a scalar (scalar data contained in vector data type) + // + inline const Matrix4 operator *( floatInVec scalar ) const; + + // Multiply a 4x4 matrix by a 4-D vector + // + inline const Vector4 operator *( Vector4 vec ) const; + + // Multiply a 4x4 matrix by a 3-D vector + // + inline const Vector4 operator *( Vector3 vec ) const; + + // Multiply a 4x4 matrix by a 3-D point + // + inline const Vector4 operator *( Point3 pnt ) const; + + // Multiply two 4x4 matrices + // + inline const Matrix4 operator *( const Matrix4 & mat ) const; + + // Multiply a 4x4 matrix by a 3x4 transformation matrix + // + inline const Matrix4 operator *( const Transform3 & tfrm ) const; + + // Perform compound assignment and addition with a 4x4 matrix + // + inline Matrix4 & operator +=( const Matrix4 & mat ); + + // Perform compound assignment and subtraction by a 4x4 matrix + // + inline Matrix4 & operator -=( const Matrix4 & mat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Matrix4 & operator *=( float scalar ); + + // Perform compound assignment and multiplication by a scalar (scalar data contained in vector data type) + // + inline Matrix4 & operator *=( floatInVec scalar ); + + // Perform compound assignment and multiplication by a 4x4 matrix + // + inline Matrix4 & operator *=( const Matrix4 & mat ); + + // Perform compound assignment and multiplication by a 3x4 transformation matrix + // + inline Matrix4 & operator *=( const Transform3 & tfrm ); + + inline bool operator == (const Matrix4& mat) const; + + inline bool operator != (const Matrix4& mat) const; + + // Construct an identity 4x4 matrix + // + static inline const Matrix4 identity( ); + + // Construct a 4x4 matrix to rotate around the x axis + // + static inline const Matrix4 rotationX( float radians ); + + // Construct a 4x4 matrix to rotate around the y axis + // + static inline const Matrix4 rotationY( float radians ); + + // Construct a 4x4 matrix to rotate around the z axis + // + static inline const Matrix4 rotationZ( float radians ); + + // Construct a 4x4 matrix to rotate around the x axis (scalar data contained in vector data type) + // + static inline const Matrix4 rotationX( floatInVec radians ); + + // Construct a 4x4 matrix to rotate around the y axis (scalar data contained in vector data type) + // + static inline const Matrix4 rotationY( floatInVec radians ); + + // Construct a 4x4 matrix to rotate around the z axis (scalar data contained in vector data type) + // + static inline const Matrix4 rotationZ( floatInVec radians ); + + // Construct a 4x4 matrix to rotate around the x, y, and z axes + // + static inline const Matrix4 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 4x4 matrix to rotate around a unit-length 3-D vector + // + static inline const Matrix4 rotation( float radians, Vector3 unitVec ); + + // Construct a 4x4 matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) + // + static inline const Matrix4 rotation( floatInVec radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Matrix4 rotation( Quat unitQuat ); + + // Construct a 4x4 matrix to perform scaling + // + static inline const Matrix4 scale( Vector3 scaleVec ); + + // Construct a 4x4 matrix to perform translation + // + static inline const Matrix4 translation( Vector3 translateVec ); + + // Construct viewing matrix based on eye position, position looked at, and up direction + // + static inline const Matrix4 lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ); + + // Construct a perspective projection matrix + // + static inline const Matrix4 perspective( float fovyRadians, float aspect, float zNear, float zFar ); + + // Construct a perspective projection matrix based on frustum + // + static inline const Matrix4 frustum( float left, float right, float bottom, float top, float zNear, float zFar ); + + // Construct an orthographic projection matrix + // + static inline const Matrix4 orthographic( float left, float right, float bottom, float top, float zNear, float zFar ); + +}; +// Multiply a 4x4 matrix by a scalar +// +inline const Matrix4 operator *( float scalar, const Matrix4 & mat ); + +// Multiply a 4x4 matrix by a scalar (scalar data contained in vector data type) +// +inline const Matrix4 operator *( floatInVec scalar, const Matrix4 & mat ); + +// Append (post-multiply) a scale transformation to a 4x4 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 4x4 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ); + +// Multiply two 4x4 matrices per element +// +inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ); + +// Compute the absolute value of a 4x4 matrix per element +// +inline const Matrix4 absPerElem( const Matrix4 & mat ); + +// Transpose of a 4x4 matrix +// +inline const Matrix4 transpose( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix +// NOTE: +// Result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix4 inverse( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix4 affineInverse( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. +// +inline const Matrix4 orthoInverse( const Matrix4 & mat ); + +// Determinant of a 4x4 matrix +// +inline const floatInVec determinant( const Matrix4 & mat ); + +// Conditionally select between two 4x4 matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ); + +// Conditionally select between two 4x4 matrices (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, boolInVec select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 4x4 matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix4 & mat ); + +// Print a 4x4 matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix4 & mat, const char * name ); + +#endif + +// A 3x4 transformation matrix in array-of-structures format +// +class Transform3 +{ + Vector3 mCol0; + Vector3 mCol1; + Vector3 mCol2; + Vector3 mCol3; + +public: + // Default constructor; does no initialization + // + inline Transform3( ) { }; + + // Copy a 3x4 transformation matrix + // + inline Transform3( const Transform3 & tfrm ); + + // Construct a 3x4 transformation matrix containing the specified columns + // + inline Transform3( Vector3 col0, Vector3 col1, Vector3 col2, Vector3 col3 ); + + // Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector + // + inline Transform3( const Matrix3 & tfrm, Vector3 translateVec ); + + // Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector + // + inline Transform3( Quat unitQuat, Vector3 translateVec ); + + // Set all elements of a 3x4 transformation matrix to the same scalar value + // + explicit inline Transform3( float scalar ); + + // Set all elements of a 3x4 transformation matrix to the same scalar value (scalar data contained in vector data type) + // + explicit inline Transform3( floatInVec scalar ); + + // Assign one 3x4 transformation matrix to another + // + inline Transform3 & operator =( const Transform3 & tfrm ); + + // Set the upper-left 3x3 submatrix + // + inline Transform3 & setUpper3x3( const Matrix3 & mat3 ); + + // Get the upper-left 3x3 submatrix of a 3x4 transformation matrix + // + inline const Matrix3 getUpper3x3( ) const; + + // Set translation component + // + inline Transform3 & setTranslation( Vector3 translateVec ); + + // Get the translation component of a 3x4 transformation matrix + // + inline const Vector3 getTranslation( ) const; + + // Set column 0 of a 3x4 transformation matrix + // + inline Transform3 & setCol0( Vector3 col0 ); + + // Set column 1 of a 3x4 transformation matrix + // + inline Transform3 & setCol1( Vector3 col1 ); + + // Set column 2 of a 3x4 transformation matrix + // + inline Transform3 & setCol2( Vector3 col2 ); + + // Set column 3 of a 3x4 transformation matrix + // + inline Transform3 & setCol3( Vector3 col3 ); + + // Get column 0 of a 3x4 transformation matrix + // + inline const Vector3 getCol0( ) const; + + // Get column 1 of a 3x4 transformation matrix + // + inline const Vector3 getCol1( ) const; + + // Get column 2 of a 3x4 transformation matrix + // + inline const Vector3 getCol2( ) const; + + // Get column 3 of a 3x4 transformation matrix + // + inline const Vector3 getCol3( ) const; + + // Set the column of a 3x4 transformation matrix referred to by the specified index + // + inline Transform3 & setCol( int col, Vector3 vec ); + + // Set the row of a 3x4 transformation matrix referred to by the specified index + // + inline Transform3 & setRow( int row, Vector4 vec ); + + // Get the column of a 3x4 transformation matrix referred to by the specified index + // + inline const Vector3 getCol( int col ) const; + + // Get the row of a 3x4 transformation matrix referred to by the specified index + // + inline const Vector4 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector3 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector3 operator []( int col ) const; + + // Set the element of a 3x4 transformation matrix referred to by column and row indices + // + inline Transform3 & setElem( int col, int row, float val ); + + // Set the element of a 3x4 transformation matrix referred to by column and row indices (scalar data contained in vector data type) + // + inline Transform3 & setElem( int col, int row, floatInVec val ); + + // Get the element of a 3x4 transformation matrix referred to by column and row indices + // + inline const floatInVec getElem( int col, int row ) const; + + // Multiply a 3x4 transformation matrix by a 3-D vector + // + inline const Vector3 operator *( Vector3 vec ) const; + + // Multiply a 3x4 transformation matrix by a 3-D point + // + inline const Point3 operator *( Point3 pnt ) const; + + // Multiply two 3x4 transformation matrices + // + inline const Transform3 operator *( const Transform3 & tfrm ) const; + + // Perform compound assignment and multiplication by a 3x4 transformation matrix + // + inline Transform3 & operator *=( const Transform3 & tfrm ); + + // Construct an identity 3x4 transformation matrix + // + static inline const Transform3 identity( ); + + // Construct a 3x4 transformation matrix to rotate around the x axis + // + static inline const Transform3 rotationX( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the y axis + // + static inline const Transform3 rotationY( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the z axis + // + static inline const Transform3 rotationZ( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the x axis (scalar data contained in vector data type) + // + static inline const Transform3 rotationX( floatInVec radians ); + + // Construct a 3x4 transformation matrix to rotate around the y axis (scalar data contained in vector data type) + // + static inline const Transform3 rotationY( floatInVec radians ); + + // Construct a 3x4 transformation matrix to rotate around the z axis (scalar data contained in vector data type) + // + static inline const Transform3 rotationZ( floatInVec radians ); + + // Construct a 3x4 transformation matrix to rotate around the x, y, and z axes + // + static inline const Transform3 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector + // + static inline const Transform3 rotation( float radians, Vector3 unitVec ); + + // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector (scalar data contained in vector data type) + // + static inline const Transform3 rotation( floatInVec radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Transform3 rotation( Quat unitQuat ); + + // Construct a 3x4 transformation matrix to perform scaling + // + static inline const Transform3 scale( Vector3 scaleVec ); + + // Construct a 3x4 transformation matrix to perform translation + // + static inline const Transform3 translation( Vector3 translateVec ); + +}; +// Append (post-multiply) a scale transformation to a 3x4 transformation matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ); + +// Multiply two 3x4 transformation matrices per element +// +inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ); + +// Compute the absolute value of a 3x4 transformation matrix per element +// +inline const Transform3 absPerElem( const Transform3 & tfrm ); + +// Inverse of a 3x4 transformation matrix +// NOTE: +// Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. +// +inline const Transform3 inverse( const Transform3 & tfrm ); + +// Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. +// +inline const Transform3 orthoInverse( const Transform3 & tfrm ); + +// Conditionally select between two 3x4 transformation matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// However, the transfer of select1 to a VMX register may use more processing time than a branch. +// Use the boolInVec version for better performance. +// +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ); + +// Conditionally select between two 3x4 transformation matrices (scalar data contained in vector data type) +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, boolInVec select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3x4 transformation matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Transform3 & tfrm ); + +// Print a 3x4 transformation matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Transform3 & tfrm, const char * name ); + +#endif + +} // namespace Aos +} // namespace Vectormath + +#include "vec_aos.h" +#include "quat_aos.h" +#include "mat_aos.h" + +#endif diff --git a/common/vectormath/spu/c/mat_aos.h b/common/vectormath/spu/c/mat_aos.h index d6b4cb0b..f738e880 100644 --- a/common/vectormath/spu/c/mat_aos.h +++ b/common/vectormath/spu/c/mat_aos.h @@ -1,1833 +1,1833 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_MAT_AOS_C_H -#define _VECTORMATH_MAT_AOS_C_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Constants - * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - */ -#define _VECTORMATH_SHUF_XAYB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_ZCWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_ZBW0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XCY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_0ZB0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_C0X0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_YA00 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_Z }) -#define _VECTORMATH_SHUF_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X }) -#define _VECTORMATH_SHUF_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y }) -#define _VECTORMATH_SHUF_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_ZAY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_BZX0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_0ZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A }) -#define _VECTORMATH_SHUF_Z0XB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_YX0C ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_CZD0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_D, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_BBY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_PI_OVER_2 1.570796327f - -/*----------------------------------------------------------------------------- - * Definitions - */ -static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( &result->col0, &mat->col0 ); - vmathV3Copy( &result->col1, &mat->col1 ); - vmathV3Copy( &result->col2, &mat->col2 ); -} - -static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ) -{ - vmathV3MakeFromScalar( &result->col0, scalar ); - vmathV3MakeFromScalar( &result->col1, scalar ); - vmathV3MakeFromScalar( &result->col2, scalar ); -} - -static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) -{ - vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - vec_uint4 select_x = (vec_uint4)spu_maskb(0xf000); - vec_uint4 select_z = (vec_uint4)spu_maskb(0x00f0); - xyzw_2 = spu_add( unitQuat->vec128, unitQuat->vec128 ); - wwww = spu_shuffle( unitQuat->vec128, unitQuat->vec128, shuffle_wwww ); - yzxw = spu_shuffle( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_SHUF_YZXW ); - zxyw = spu_shuffle( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_SHUF_ZXYW ); - yzxw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_YZXW ); - zxyw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_ZXYW ); - tmp0 = spu_mul( yzxw_2, wwww ); - tmp1 = spu_nmsub( yzxw, yzxw_2, spu_splats(1.0f) ); - tmp2 = spu_mul( yzxw, xyzw_2 ); - tmp0 = spu_madd( zxyw, xyzw_2, tmp0 ); - tmp1 = spu_nmsub( zxyw, zxyw_2, tmp1 ); - tmp2 = spu_nmsub( zxyw_2, wwww, tmp2 ); - tmp3 = spu_sel( tmp0, tmp1, select_x ); - tmp4 = spu_sel( tmp1, tmp2, select_x ); - tmp5 = spu_sel( tmp2, tmp0, select_x ); - result->col0.vec128 = spu_sel( tmp3, tmp2, select_z ); - result->col1.vec128 = spu_sel( tmp4, tmp0, select_z ); - result->col2.vec128 = spu_sel( tmp5, tmp1, select_z ); -} - -static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col0, _col0 ); - vmathV3Copy( &result->col1, _col1 ); - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *_col0 ) -{ - vmathV3Copy( &result->col0, _col0 ); -} - -static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *_col1 ) -{ - vmathV3Copy( &result->col1, _col1 ); -} - -static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ) -{ - vmathV3Copy( (&result->col0 + col), vec ); -} - -static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ) -{ - vmathV3SetElem( &result->col0, row, vmathV3GetElem( vec, 0 ) ); - vmathV3SetElem( &result->col1, row, vmathV3GetElem( vec, 1 ) ); - vmathV3SetElem( &result->col2, row, vmathV3GetElem( vec, 2 ) ); -} - -static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ) -{ - VmathVector3 tmpV3_0; - vmathM3GetCol( &tmpV3_0, result, col ); - vmathV3SetElem( &tmpV3_0, row, val ); - vmathM3SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ) -{ - VmathVector3 tmpV3_0; - vmathM3GetCol( &tmpV3_0, mat, col ); - return vmathV3GetElem( &tmpV3_0, row ); -} - -static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col0 ); -} - -static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col1 ); -} - -static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Copy( result, &mat->col2 ); -} - -static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ) -{ - vmathV3Copy( result, (&mat->col0 + col) ); -} - -static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ) -{ - vmathV3MakeFromElems( result, vmathV3GetElem( &mat->col0, row ), vmathV3GetElem( &mat->col1, row ), vmathV3GetElem( &mat->col2, row ) ); -} - -static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, res0, res1, res2; - tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); - res0 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_XAYB ); - res1 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); - res2 = spu_shuffle( tmp1, mat->col1.vec128, _VECTORMATH_SHUF_XCY0 ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; - tmp2 = _vmathVfCross( mat->col0.vec128, mat->col1.vec128 ); - tmp0 = _vmathVfCross( mat->col1.vec128, mat->col2.vec128 ); - tmp1 = _vmathVfCross( mat->col2.vec128, mat->col0.vec128 ); - dot = _vmathVfDot3( tmp2, mat->col2.vec128 ); - dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); - invdet = recipf4( dot ); - tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); - tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); - inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); - inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); - inv0 = spu_mul( inv0, invdet ); - inv1 = spu_mul( inv1, invdet ); - inv2 = spu_mul( inv2, invdet ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; -} - -static inline float vmathM3Determinant( const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0; - vmathV3Cross( &tmpV3_0, &mat->col0, &mat->col1 ); - return vmathV3Dot( &mat->col2, &tmpV3_0 ); -} - -static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3Add( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3Add( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3Add( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3Sub( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3Sub( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3Sub( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3Neg( &result->col0, &mat->col0 ); - vmathV3Neg( &result->col1, &mat->col1 ); - vmathV3Neg( &result->col2, &mat->col2 ); -} - -static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ) -{ - vmathV3AbsPerElem( &result->col0, &mat->col0 ); - vmathV3AbsPerElem( &result->col1, &mat->col1 ); - vmathV3AbsPerElem( &result->col2, &mat->col2 ); -} - -static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ) -{ - vmathV3ScalarMul( &result->col0, &mat->col0, scalar ); - vmathV3ScalarMul( &result->col1, &mat->col1, scalar ); - vmathV3ScalarMul( &result->col2, &mat->col2, scalar ); -} - -static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); - res = spu_mul( mat->col0.vec128, xxxx ); - res = spu_madd( mat->col1.vec128, yyyy, res ); - res = spu_madd( mat->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - VmathMatrix3 tmpResult; - vmathM3MulV3( &tmpResult.col0, mat0, &mat1->col0 ); - vmathM3MulV3( &tmpResult.col1, mat0, &mat1->col1 ); - vmathM3MulV3( &tmpResult.col2, mat0, &mat1->col2 ); - vmathM3Copy( result, &tmpResult ); -} - -static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) -{ - vmathV3MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV3MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV3MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); -} - -static inline void vmathM3MakeIdentity( VmathMatrix3 *result ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); -} - -static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - vmathV3MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV3MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; -} - -static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV3MakeZAxis( &result->col2 ); -} - -static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ->vec128; - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - result->col0.vec128 = spu_mul( Z0, Y0 ); - result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); - result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); -} - -static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - axis = unitVec->vec128; - sincosf4( spu_splats( radians ), &s, &c ); - xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); - yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); - zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); - oneMinusC = spu_sub( spu_splats(1.0f), c ); - axisS = spu_mul( axis, s ); - negAxisS = negatef4( axisS ); - tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); - tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); - tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); - tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); - tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); - tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); - result->col0.vec128 = spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ); - result->col1.vec128 = spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ); - result->col2.vec128 = spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ); -} - -static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) -{ - vmathM3MakeFromQ( result, unitQuat ); -} - -static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); - result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); - result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); -} - -static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ) -{ - vmathV3ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); - vmathV3ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); - vmathV3ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); -} - -static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ) -{ - vmathV3MulPerElem( &result->col0, &mat->col0, scaleVec ); - vmathV3MulPerElem( &result->col1, &mat->col1, scaleVec ); - vmathV3MulPerElem( &result->col2, &mat->col2, scaleVec ); -} - -static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ) -{ - vmathV3Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); - vmathV3Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); - vmathV3Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathM3Print( const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; - vmathM3GetRow( &tmpV3_0, mat, 0 ); - vmathV3Print( &tmpV3_0 ); - vmathM3GetRow( &tmpV3_1, mat, 1 ); - vmathV3Print( &tmpV3_1 ); - vmathM3GetRow( &tmpV3_2, mat, 2 ); - vmathV3Print( &tmpV3_2 ); -} - -static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ) -{ - printf("%s:\n", name); - vmathM3Print( mat ); -} - -#endif - -static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( &result->col0, &mat->col0 ); - vmathV4Copy( &result->col1, &mat->col1 ); - vmathV4Copy( &result->col2, &mat->col2 ); - vmathV4Copy( &result->col3, &mat->col3 ); -} - -static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ) -{ - vmathV4MakeFromScalar( &result->col0, scalar ); - vmathV4MakeFromScalar( &result->col1, scalar ); - vmathV4MakeFromScalar( &result->col2, scalar ); - vmathV4MakeFromScalar( &result->col3, scalar ); -} - -static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ) -{ - vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, &mat->col3, 1.0f ); -} - -static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *_col0, const VmathVector4 *_col1, const VmathVector4 *_col2, const VmathVector4 *_col3 ) -{ - vmathV4Copy( &result->col0, _col0 ); - vmathV4Copy( &result->col1, _col1 ); - vmathV4Copy( &result->col2, _col2 ); - vmathV4Copy( &result->col3, _col3 ); -} - -static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ) -{ - vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) -{ - VmathMatrix3 mat; - vmathM3MakeFromQ( &mat, unitQuat ); - vmathV4MakeFromV3Scalar( &result->col0, &mat.col0, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col1, &mat.col1, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col2, &mat.col2, 0.0f ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *_col0 ) -{ - vmathV4Copy( &result->col0, _col0 ); -} - -static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *_col1 ) -{ - vmathV4Copy( &result->col1, _col1 ); -} - -static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *_col2 ) -{ - vmathV4Copy( &result->col2, _col2 ); -} - -static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *_col3 ) -{ - vmathV4Copy( &result->col3, _col3 ); -} - -static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ) -{ - vmathV4Copy( (&result->col0 + col), vec ); -} - -static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ) -{ - vmathV4SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); - vmathV4SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); - vmathV4SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); - vmathV4SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); -} - -static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ) -{ - VmathVector4 tmpV3_0; - vmathM4GetCol( &tmpV3_0, result, col ); - vmathV4SetElem( &tmpV3_0, row, val ); - vmathM4SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ) -{ - VmathVector4 tmpV4_0; - vmathM4GetCol( &tmpV4_0, mat, col ); - return vmathV4GetElem( &tmpV4_0, row ); -} - -static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col0 ); -} - -static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col1 ); -} - -static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col2 ); -} - -static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Copy( result, &mat->col3 ); -} - -static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ) -{ - vmathV4Copy( result, (&mat->col0 + col) ); -} - -static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ) -{ - vmathV4MakeFromElems( result, vmathV4GetElem( &mat->col0, row ), vmathV4GetElem( &mat->col1, row ), vmathV4GetElem( &mat->col2, row ), vmathV4GetElem( &mat->col3, row ) ); -} - -static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; - tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat->col1.vec128, mat->col3.vec128, _VECTORMATH_SHUF_XAYB ); - tmp2 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); - tmp3 = spu_shuffle( mat->col1.vec128, mat->col3.vec128, _VECTORMATH_SHUF_ZCWD ); - res0 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_XAYB ); - res1 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_ZCWD ); - res2 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_XAYB ); - res3 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_ZCWD ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; - result->col3.vec128 = res3; -} - -static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 in0, in1, in2, in3; - vec_float4 tmp0, tmp1, tmp2, tmp3; - vec_float4 cof0, cof1, cof2, cof3; - vec_float4 t0, t1, t2, t3; - vec_float4 t01, t02, t03, t12, t23; - vec_float4 t1r, t2r; - vec_float4 t01r, t02r, t03r, t12r, t23r; - vec_float4 t1r3, t1r3r; - vec_float4 det, det1, det2, det3, invdet; - in0 = mat->col0.vec128; - in1 = mat->col1.vec128; - in2 = mat->col2.vec128; - in3 = mat->col3.vec128; - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ - tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ - tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ - tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ - t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ - t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ - t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ - t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = spu_mul(t2, t3); /* CL GP KD OH */ - t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ - cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ - cof1 = spu_mul(t0, t23); /* AGP ECL IOH MKD */ - t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ - cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ - cof1 = spu_msub(t0, t23r, cof1); /* AOH EKD IGP MCL - cof1 */ - cof1 = spu_rlqwbyte(cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ - - t12 = spu_mul(t1, t2); /* JC NG BK FO */ - t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ - cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - cof3 = spu_mul(t0, t12); /* ANG EJC IFO MBK */ - t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ - cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - cof3 = spu_msub(t0, t12r, cof3); /* AFO EBK ING MJC - cof3 */ - cof3 = spu_rlqwbyte(cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ - t1r = spu_rlqwbyte(t1, 8); /* B F J N */ - t2r = spu_rlqwbyte(t2, 8); /* K O C G */ - t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ - t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ - cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - cof2 = spu_mul(t0, t1r3); /* AFP EBL INH MJD */ - t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ - cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - cof2 = spu_msub(t0, t1r3r, cof2); /* ANH EJD IFP MBL - cof2 */ - cof2 = spu_rlqwbyte(cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ - t01 = spu_mul(t0, t1); /* AJ EN IB MF */ - t01 = spu_shuffle(t01, t01, _VECTORMATH_SHUF_YXWZ); /* EN AJ MF IB */ - cof2 = spu_madd(t3, t01, cof2); /* LEN PAJ DMF HIB + cof2 */ - cof3 = spu_msub(t2r, t01, cof3); /* KEN OAJ CMF GIB - cof3 */ - t01r = spu_rlqwbyte(t01, 8); /* MF IB EN AJ */ - cof2 = spu_msub(t3, t01r, cof2); /* LMF PIB DEN HAJ - cof2 */ - cof3 = spu_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ - t03 = spu_mul(t0, t3); /* AL EP ID MH */ - t03 = spu_shuffle(t03, t03, _VECTORMATH_SHUF_YXWZ); /* EP AL MH ID */ - cof1 = spu_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ - cof2 = spu_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ - t03r = spu_rlqwbyte(t03, 8); /* MH ID EP AL */ - cof1 = spu_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ - cof2 = spu_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ - t02 = spu_mul(t0, t2r); /* AK EO IC MG */ - t02 = spu_shuffle(t02, t02, _VECTORMATH_SHUF_YXWZ); /* E0 AK MG IC */ - cof1 = spu_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ - cof3 = spu_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ - t02r = spu_rlqwbyte(t02, 8); /* MG IC EO AK */ - cof1 = spu_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ - cof3 = spu_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ - /* Compute the determinant of the matrix - * - * det = sum_across(t0 * cof0); - * - * We perform a sum across the entire vector so that - * we don't have to splat the result when multiplying the - * cofactors by the inverse of the determinant. - */ - det = spu_mul(t0, cof0); - det1 = spu_rlqwbyte(det, 4); - det2 = spu_rlqwbyte(det, 8); - det3 = spu_rlqwbyte(det, 12); - det = spu_add(det, det1); - det2 = spu_add(det2, det3); - det = spu_add(det, det2); - /* Compute the reciprocal of the determinant. - */ - invdet = recipf4(det); - /* Multiply the cofactors by the reciprocal of the determinant. - */ - result->col0.vec128 = spu_mul(cof0, invdet); - result->col1.vec128 = spu_mul(cof1, invdet); - result->col2.vec128 = spu_mul(cof2, invdet); - result->col3.vec128 = spu_mul(cof3, invdet); -} - -static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - VmathTransform3 affineMat, tmpT3_0; - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; - vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); - vmathT3SetCol0( &affineMat, &tmpV3_0 ); - vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); - vmathT3SetCol1( &affineMat, &tmpV3_1 ); - vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); - vmathT3SetCol2( &affineMat, &tmpV3_2 ); - vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); - vmathT3SetCol3( &affineMat, &tmpV3_3 ); - vmathT3Inverse( &tmpT3_0, &affineMat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - VmathTransform3 affineMat, tmpT3_0; - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; - vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); - vmathT3SetCol0( &affineMat, &tmpV3_0 ); - vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); - vmathT3SetCol1( &affineMat, &tmpV3_1 ); - vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); - vmathT3SetCol2( &affineMat, &tmpV3_2 ); - vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); - vmathT3SetCol3( &affineMat, &tmpV3_3 ); - vmathT3OrthoInverse( &tmpT3_0, &affineMat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline float vmathM4Determinant( const VmathMatrix4 *mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 in0, in1, in2, in3; - vec_float4 tmp0, tmp1, tmp2, tmp3; - vec_float4 cof0; - vec_float4 t0, t1, t2, t3; - vec_float4 t12, t23; - vec_float4 t1r, t2r; - vec_float4 t12r, t23r; - vec_float4 t1r3, t1r3r; - in0 = mat->col0.vec128; - in1 = mat->col1.vec128; - in2 = mat->col2.vec128; - in3 = mat->col3.vec128; - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ - tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ - tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ - tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ - t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ - t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ - t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ - t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = spu_mul(t2, t3); /* CL GP KD OH */ - t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ - cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ - t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ - cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ - - t12 = spu_mul(t1, t2); /* JC NG BK FO */ - t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ - cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ - cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - t1r = spu_rlqwbyte(t1, 8); /* B F J N */ - t2r = spu_rlqwbyte(t2, 8); /* K O C G */ - t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ - t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ - cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ - cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - return spu_extract( _vmathVfDot4(t0,cof0), 0 ); -} - -static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4Add( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4Add( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4Add( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4Add( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4Sub( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4Sub( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4Sub( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4Sub( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4Neg( &result->col0, &mat->col0 ); - vmathV4Neg( &result->col1, &mat->col1 ); - vmathV4Neg( &result->col2, &mat->col2 ); - vmathV4Neg( &result->col3, &mat->col3 ); -} - -static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ) -{ - vmathV4AbsPerElem( &result->col0, &mat->col0 ); - vmathV4AbsPerElem( &result->col1, &mat->col1 ); - vmathV4AbsPerElem( &result->col2, &mat->col2 ); - vmathV4AbsPerElem( &result->col3, &mat->col3 ); -} - -static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ) -{ - vmathV4ScalarMul( &result->col0, &mat->col0, scalar ); - vmathV4ScalarMul( &result->col1, &mat->col1, scalar ); - vmathV4ScalarMul( &result->col2, &mat->col2, scalar ); - vmathV4ScalarMul( &result->col3, &mat->col3, scalar ); -} - -static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz, wwww; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); - wwww = spu_shuffle( vec->vec128, vec->vec128, shuffle_wwww ); - tmp0 = spu_mul( mat->col0.vec128, xxxx ); - tmp1 = spu_mul( mat->col1.vec128, yyyy ); - tmp0 = spu_madd( mat->col2.vec128, zzzz, tmp0 ); - tmp1 = spu_madd( mat->col3.vec128, wwww, tmp1 ); - res = spu_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); - res = spu_mul( mat->col0.vec128, xxxx ); - res = spu_madd( mat->col1.vec128, yyyy, res ); - res = spu_madd( mat->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_zzzz ); - tmp0 = spu_mul( mat->col0.vec128, xxxx ); - tmp1 = spu_mul( mat->col1.vec128, yyyy ); - tmp0 = spu_madd( mat->col2.vec128, zzzz, tmp0 ); - tmp1 = spu_add( mat->col3.vec128, tmp1 ); - res = spu_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - VmathMatrix4 tmpResult; - vmathM4MulV4( &tmpResult.col0, mat0, &mat1->col0 ); - vmathM4MulV4( &tmpResult.col1, mat0, &mat1->col1 ); - vmathM4MulV4( &tmpResult.col2, mat0, &mat1->col2 ); - vmathM4MulV4( &tmpResult.col3, mat0, &mat1->col3 ); - vmathM4Copy( result, &tmpResult ); -} - -static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm1 ) -{ - VmathMatrix4 tmpResult; - VmathPoint3 tmpP3_0; - vmathM4MulV3( &tmpResult.col0, mat, &tfrm1->col0 ); - vmathM4MulV3( &tmpResult.col1, mat, &tfrm1->col1 ); - vmathM4MulV3( &tmpResult.col2, mat, &tfrm1->col2 ); - vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); - vmathM4MulP3( &tmpResult.col3, mat, &tmpP3_0 ); - vmathM4Copy( result, &tmpResult ); -} - -static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) -{ - vmathV4MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); - vmathV4MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); - vmathV4MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); - vmathV4MulPerElem( &result->col3, &mat0->col3, &mat1->col3 ); -} - -static inline void vmathM4MakeIdentity( VmathMatrix4 *result ) -{ - vmathV4MakeXAxis( &result->col0 ); - vmathV4MakeYAxis( &result->col1 ); - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ) -{ - vmathV4SetXYZ( &result->col0, &mat3->col0 ); - vmathV4SetXYZ( &result->col1, &mat3->col1 ); - vmathV4SetXYZ( &result->col2, &mat3->col2 ); -} - -static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ) -{ - vmathV4GetXYZ( &result->col0, &mat->col0 ); - vmathV4GetXYZ( &result->col1, &mat->col1 ); - vmathV4GetXYZ( &result->col2, &mat->col2 ); -} - -static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) -{ - vmathV4SetXYZ( &result->col3, translateVec ); -} - -static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ) -{ - vmathV4GetXYZ( result, &mat->col3 ); -} - -static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - vmathV4MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV4MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ->vec128; - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - result->col0.vec128 = spu_mul( Z0, Y0 ); - result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); - result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - axis = unitVec->vec128; - sincosf4( spu_splats( radians ), &s, &c ); - xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); - yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); - zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); - oneMinusC = spu_sub( spu_splats(1.0f), c ); - axisS = spu_mul( axis, s ); - negAxisS = negatef4( axisS ); - tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); - tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); - tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); - tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); - tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); - tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); - zeroW = (vec_float4)spu_maskb(0x000f); - axis = spu_andc( axis, zeroW ); - result->col0.vec128 = spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ); - result->col1.vec128 = spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ); - result->col2.vec128 = spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ) -{ - VmathTransform3 tmpT3_0; - vmathT3MakeRotationQ( &tmpT3_0, unitQuat ); - vmathM4MakeFromT3( result, &tmpT3_0 ); -} - -static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); - result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); - result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); - vmathV4MakeWAxis( &result->col3 ); -} - -static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ) -{ - vmathV4ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); - vmathV4ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); - vmathV4ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); - vmathV4Copy( &result->col3, &mat->col3 ); -} - -static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ) -{ - VmathVector4 scale4; - vmathV4MakeFromV3Scalar( &scale4, scaleVec, 1.0f ); - vmathV4MulPerElem( &result->col0, &mat->col0, &scale4 ); - vmathV4MulPerElem( &result->col1, &mat->col1, &scale4 ); - vmathV4MulPerElem( &result->col2, &mat->col2, &scale4 ); - vmathV4MulPerElem( &result->col3, &mat->col3, &scale4 ); -} - -static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) -{ - vmathV4MakeXAxis( &result->col0 ); - vmathV4MakeYAxis( &result->col1 ); - vmathV4MakeZAxis( &result->col2 ); - vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); -} - -static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ) -{ - VmathMatrix4 m4EyeFrame; - VmathVector3 v3X, v3Y, v3Z, tmpV3_0, tmpV3_1; - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; - vmathV3Normalize( &v3Y, upVec ); - vmathP3Sub( &tmpV3_0, eyePos, lookAtPos ); - vmathV3Normalize( &v3Z, &tmpV3_0 ); - vmathV3Cross( &tmpV3_1, &v3Y, &v3Z ); - vmathV3Normalize( &v3X, &tmpV3_1 ); - vmathV3Cross( &v3Y, &v3Z, &v3X ); - vmathV4MakeFromV3( &tmpV4_0, &v3X ); - vmathV4MakeFromV3( &tmpV4_1, &v3Y ); - vmathV4MakeFromV3( &tmpV4_2, &v3Z ); - vmathV4MakeFromP3( &tmpV4_3, eyePos ); - vmathM4MakeFromCols( &m4EyeFrame, &tmpV4_0, &tmpV4_1, &tmpV4_2, &tmpV4_3 ); - vmathM4OrthoInverse( result, &m4EyeFrame ); -} - -static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ) -{ - float f, rangeInv; - vec_float4 zero, col0, col1, col2, col3; - f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); - rangeInv = 1.0f / ( zNear - zFar ); - zero = spu_splats(0.0f); - col0 = zero; - col1 = zero; - col2 = zero; - col3 = zero; - col0 = spu_insert( f / aspect, col0, 0 ); - col1 = spu_insert( f, col1, 1 ); - col2 = spu_insert( ( zNear + zFar ) * rangeInv, col2, 2 ); - col2 = spu_insert( -1.0f, col2, 3 ); - col3 = spu_insert( zNear * zFar * rangeInv * 2.0f, col3, 2 ); - result->col0.vec128 = col0; - result->col1.vec128 = col1; - result->col2.vec128 = col2; - result->col3.vec128 = col3; -} - -static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff; - vec_float4 diagonal, column, near2; - vec_float4 zero = spu_splats(0.0f); - lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); - lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); - diff = spu_sub( rtn, lbf ); - sum = spu_add( rtn, lbf ); - inv_diff = recipf4( diff ); - near2 = spu_splats( zNear ); - near2 = spu_add( near2, near2 ); - diagonal = spu_mul( near2, inv_diff ); - column = spu_mul( sum, inv_diff ); - result->col0.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ); - result->col1.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ); - result->col2.vec128 = spu_sel( column, spu_splats(-1.0f), (vec_uint4)spu_maskb(0x000f) ); - result->col3.vec128 = spu_sel( zero, spu_mul( diagonal, spu_splats(zFar) ), (vec_uint4)spu_maskb(0x00f0) ); -} - -static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff, neg_inv_diff; - vec_float4 diagonal, column; - vec_float4 zero = spu_splats(0.0f); - lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); - lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); - diff = spu_sub( rtn, lbf ); - sum = spu_add( rtn, lbf ); - inv_diff = recipf4( diff ); - neg_inv_diff = negatef4( inv_diff ); - diagonal = spu_add( inv_diff, inv_diff ); - column = spu_mul( sum, spu_sel( neg_inv_diff, inv_diff, (vec_uint4)spu_maskb(0x00f0) ) ); - result->col0.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ); - result->col1.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ); - result->col2.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x00f0) ); - result->col3.vec128 = spu_sel( column, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); -} - -static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ) -{ - vmathV4Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); - vmathV4Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); - vmathV4Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); - vmathV4Select( &result->col3, &mat0->col3, &mat1->col3, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathM4Print( const VmathMatrix4 *mat ) -{ - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; - vmathM4GetRow( &tmpV4_0, mat, 0 ); - vmathV4Print( &tmpV4_0 ); - vmathM4GetRow( &tmpV4_1, mat, 1 ); - vmathV4Print( &tmpV4_1 ); - vmathM4GetRow( &tmpV4_2, mat, 2 ); - vmathV4Print( &tmpV4_2 ); - vmathM4GetRow( &tmpV4_3, mat, 3 ); - vmathV4Print( &tmpV4_3 ); -} - -static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ) -{ - printf("%s:\n", name); - vmathM4Print( mat ); -} - -#endif - -static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( &result->col0, &tfrm->col0 ); - vmathV3Copy( &result->col1, &tfrm->col1 ); - vmathV3Copy( &result->col2, &tfrm->col2 ); - vmathV3Copy( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ) -{ - vmathV3MakeFromScalar( &result->col0, scalar ); - vmathV3MakeFromScalar( &result->col1, scalar ); - vmathV3MakeFromScalar( &result->col2, scalar ); - vmathV3MakeFromScalar( &result->col3, scalar ); -} - -static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2, const VmathVector3 *_col3 ) -{ - vmathV3Copy( &result->col0, _col0 ); - vmathV3Copy( &result->col1, _col1 ); - vmathV3Copy( &result->col2, _col2 ); - vmathV3Copy( &result->col3, _col3 ); -} - -static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ) -{ - vmathT3SetUpper3x3( result, tfrm ); - vmathT3SetTranslation( result, translateVec ); -} - -static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) -{ - VmathMatrix3 tmpM3_0; - vmathM3MakeFromQ( &tmpM3_0, unitQuat ); - vmathT3SetUpper3x3( result, &tmpM3_0 ); - vmathT3SetTranslation( result, translateVec ); -} - -static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *_col0 ) -{ - vmathV3Copy( &result->col0, _col0 ); -} - -static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *_col1 ) -{ - vmathV3Copy( &result->col1, _col1 ); -} - -static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *_col2 ) -{ - vmathV3Copy( &result->col2, _col2 ); -} - -static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *_col3 ) -{ - vmathV3Copy( &result->col3, _col3 ); -} - -static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ) -{ - vmathV3Copy( (&result->col0 + col), vec ); -} - -static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ) -{ - vmathV3SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); - vmathV3SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); - vmathV3SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); - vmathV3SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); -} - -static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ) -{ - VmathVector3 tmpV3_0; - vmathT3GetCol( &tmpV3_0, result, col ); - vmathV3SetElem( &tmpV3_0, row, val ); - vmathT3SetCol( result, col, &tmpV3_0 ); -} - -static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ) -{ - VmathVector3 tmpV3_0; - vmathT3GetCol( &tmpV3_0, tfrm, col ); - return vmathV3GetElem( &tmpV3_0, row ); -} - -static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col0 ); -} - -static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col1 ); -} - -static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col2 ); -} - -static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col3 ); -} - -static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ) -{ - vmathV3Copy( result, (&tfrm->col0 + col) ); -} - -static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ) -{ - vmathV4MakeFromElems( result, vmathV3GetElem( &tfrm->col0, row ), vmathV3GetElem( &tfrm->col1, row ), vmathV3GetElem( &tfrm->col2, row ), vmathV3GetElem( &tfrm->col3, row ) ); -} - -static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp2 = _vmathVfCross( tfrm->col0.vec128, tfrm->col1.vec128 ); - tmp0 = _vmathVfCross( tfrm->col1.vec128, tfrm->col2.vec128 ); - tmp1 = _vmathVfCross( tfrm->col2.vec128, tfrm->col0.vec128 ); - inv3 = negatef4( tfrm->col3.vec128 ); - dot = _vmathVfDot3( tmp2, tfrm->col2.vec128 ); - dot = spu_shuffle( dot, dot, shuffle_xxxx ); - invdet = recipf4( dot ); - tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); - tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); - inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); - xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); - inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); - zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); - inv3 = spu_mul( inv0, xxxx ); - inv3 = spu_madd( inv1, yyyy, inv3 ); - inv3 = spu_madd( inv2, zzzz, inv3 ); - inv0 = spu_mul( inv0, invdet ); - inv1 = spu_mul( inv1, invdet ); - inv2 = spu_mul( inv2, invdet ); - inv3 = spu_mul( inv3, invdet ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; - result->col3.vec128 = inv3; -} - -static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp0 = spu_shuffle( tfrm->col0.vec128, tfrm->col2.vec128, _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( tfrm->col0.vec128, tfrm->col2.vec128, _VECTORMATH_SHUF_ZCWD ); - inv3 = negatef4( tfrm->col3.vec128 ); - inv0 = spu_shuffle( tmp0, tfrm->col1.vec128, _VECTORMATH_SHUF_XAYB ); - xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); - inv1 = spu_shuffle( tmp0, tfrm->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp1, tfrm->col1.vec128, _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); - zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); - inv3 = spu_mul( inv0, xxxx ); - inv3 = spu_madd( inv1, yyyy, inv3 ); - inv3 = spu_madd( inv2, zzzz, inv3 ); - result->col0.vec128 = inv0; - result->col1.vec128 = inv1; - result->col2.vec128 = inv2; - result->col3.vec128 = inv3; -} - -static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3AbsPerElem( &result->col0, &tfrm->col0 ); - vmathV3AbsPerElem( &result->col1, &tfrm->col1 ); - vmathV3AbsPerElem( &result->col2, &tfrm->col2 ); - vmathV3AbsPerElem( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ) -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); - res = spu_mul( tfrm->col0.vec128, xxxx ); - res = spu_madd( tfrm->col1.vec128, yyyy, res ); - res = spu_madd( tfrm->col2.vec128, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ) -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_xxxx ); - yyyy = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_yyyy ); - zzzz = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_zzzz ); - tmp0 = spu_mul( tfrm->col0.vec128, xxxx ); - tmp1 = spu_mul( tfrm->col1.vec128, yyyy ); - tmp0 = spu_madd( tfrm->col2.vec128, zzzz, tmp0 ); - tmp1 = spu_add( tfrm->col3.vec128, tmp1 ); - res = spu_add( tmp0, tmp1 ); - result->vec128 = res; -} - -static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) -{ - VmathTransform3 tmpResult; - VmathPoint3 tmpP3_0, tmpP3_1; - vmathT3MulV3( &tmpResult.col0, tfrm0, &tfrm1->col0 ); - vmathT3MulV3( &tmpResult.col1, tfrm0, &tfrm1->col1 ); - vmathT3MulV3( &tmpResult.col2, tfrm0, &tfrm1->col2 ); - vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); - vmathT3MulP3( &tmpP3_1, tfrm0, &tmpP3_0 ); - vmathV3MakeFromP3( &tmpResult.col3, &tmpP3_1 ); - vmathT3Copy( result, &tmpResult ); -} - -static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) -{ - vmathV3MulPerElem( &result->col0, &tfrm0->col0, &tfrm1->col0 ); - vmathV3MulPerElem( &result->col1, &tfrm0->col1, &tfrm1->col1 ); - vmathV3MulPerElem( &result->col2, &tfrm0->col2, &tfrm1->col2 ); - vmathV3MulPerElem( &result->col3, &tfrm0->col3, &tfrm1->col3 ); -} - -static inline void vmathT3MakeIdentity( VmathTransform3 *result ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *tfrm ) -{ - vmathV3Copy( &result->col0, &tfrm->col0 ); - vmathV3Copy( &result->col1, &tfrm->col1 ); - vmathV3Copy( &result->col2, &tfrm->col2 ); -} - -static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ) -{ - vmathM3MakeFromCols( result, &tfrm->col0, &tfrm->col1, &tfrm->col2 ); -} - -static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) -{ - vmathV3Copy( &result->col3, translateVec ); -} - -static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ) -{ - vmathV3Copy( result, &tfrm->col3 ); -} - -static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - vmathV3MakeXAxis( &result->col0 ); - result->col1.vec128 = res1; - result->col2.vec128 = res2; - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - result->col0.vec128 = res0; - vmathV3MakeYAxis( &result->col1 ); - result->col2.vec128 = res2; - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - vmathV3MakeZAxis( &result->col2 ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ->vec128; - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - result->col0.vec128 = spu_mul( Z0, Y0 ); - result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); - result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ) -{ - VmathMatrix3 tmpM3_0; - VmathVector3 tmpV3_0; - vmathM3MakeRotationAxis( &tmpM3_0, radians, unitVec ); - vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); - vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); -} - -static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ) -{ - VmathMatrix3 tmpM3_0; - VmathVector3 tmpV3_0; - vmathM3MakeFromQ( &tmpM3_0, unitQuat ); - vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); - vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); -} - -static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); - result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); - result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); - vmathV3MakeFromScalar( &result->col3, 0.0f ); -} - -static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ) -{ - vmathV3ScalarMul( &result->col0, &tfrm->col0, vmathV3GetX( scaleVec ) ); - vmathV3ScalarMul( &result->col1, &tfrm->col1, vmathV3GetY( scaleVec ) ); - vmathV3ScalarMul( &result->col2, &tfrm->col2, vmathV3GetZ( scaleVec ) ); - vmathV3Copy( &result->col3, &tfrm->col3 ); -} - -static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ) -{ - vmathV3MulPerElem( &result->col0, &tfrm->col0, scaleVec ); - vmathV3MulPerElem( &result->col1, &tfrm->col1, scaleVec ); - vmathV3MulPerElem( &result->col2, &tfrm->col2, scaleVec ); - vmathV3MulPerElem( &result->col3, &tfrm->col3, scaleVec ); -} - -static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) -{ - vmathV3MakeXAxis( &result->col0 ); - vmathV3MakeYAxis( &result->col1 ); - vmathV3MakeZAxis( &result->col2 ); - vmathV3Copy( &result->col3, translateVec ); -} - -static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ) -{ - vmathV3Select( &result->col0, &tfrm0->col0, &tfrm1->col0, select1 ); - vmathV3Select( &result->col1, &tfrm0->col1, &tfrm1->col1, select1 ); - vmathV3Select( &result->col2, &tfrm0->col2, &tfrm1->col2, select1 ); - vmathV3Select( &result->col3, &tfrm0->col3, &tfrm1->col3, select1 ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathT3Print( const VmathTransform3 *tfrm ) -{ - VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2; - vmathT3GetRow( &tmpV4_0, tfrm, 0 ); - vmathV4Print( &tmpV4_0 ); - vmathT3GetRow( &tmpV4_1, tfrm, 1 ); - vmathV4Print( &tmpV4_1 ); - vmathT3GetRow( &tmpV4_2, tfrm, 2 ); - vmathV4Print( &tmpV4_2 ); -} - -static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ) -{ - printf("%s:\n", name); - vmathT3Print( tfrm ); -} - -#endif - -static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *tfrm ) -{ - vec_float4 res; - vec_float4 col0, col1, col2; - vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; - vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; - vec_float4 radicand, invSqrt, scale; - vec_float4 res0, res1, res2, res3; - vec_float4 xx, yy, zz; - vec_uint4 select_x = (vec_uint4)spu_maskb( 0xf000 ); - vec_uint4 select_y = (vec_uint4)spu_maskb( 0x0f00 ); - vec_uint4 select_z = (vec_uint4)spu_maskb( 0x00f0 ); - vec_uint4 select_w = (vec_uint4)spu_maskb( 0x000f ); - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((unsigned int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((unsigned int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((unsigned int)0x08090a0b); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((unsigned int)0x0c0d0e0f); - - col0 = tfrm->col0.vec128; - col1 = tfrm->col1.vec128; - col2 = tfrm->col2.vec128; - - /* four cases: */ - /* trace > 0 */ - /* else */ - /* xx largest diagonal element */ - /* yy largest diagonal element */ - /* zz largest diagonal element */ - - /* compute quaternion for each case */ - - xx_yy = spu_sel( col0, col1, select_y ); - xx_yy_zz_xx = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_XYCX ); - yy_zz_xx_yy = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_YCXY ); - zz_xx_yy_zz = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_CXYC ); - - diagSum = spu_add( spu_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - diagDiff = spu_sub( spu_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - radicand = spu_add( spu_sel( diagDiff, diagSum, select_w ), spu_splats(1.0f) ); - invSqrt = rsqrtf4( radicand ); - - zy_xz_yx = spu_sel( col0, col1, select_z ); - zy_xz_yx = spu_shuffle( zy_xz_yx, col2, _VECTORMATH_SHUF_ZAY0 ); - yz_zx_xy = spu_sel( col0, col1, select_x ); - yz_zx_xy = spu_shuffle( yz_zx_xy, col2, _VECTORMATH_SHUF_BZX0 ); - - sum = spu_add( zy_xz_yx, yz_zx_xy ); - diff = spu_sub( zy_xz_yx, yz_zx_xy ); - - scale = spu_mul( invSqrt, spu_splats(0.5f) ); - res0 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_0ZYA ); - res1 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_Z0XB ); - res2 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_YX0C ); - res3 = diff; - res0 = spu_sel( res0, radicand, select_x ); - res1 = spu_sel( res1, radicand, select_y ); - res2 = spu_sel( res2, radicand, select_z ); - res3 = spu_sel( res3, radicand, select_w ); - res0 = spu_mul( res0, spu_shuffle( scale, scale, shuffle_xxxx ) ); - res1 = spu_mul( res1, spu_shuffle( scale, scale, shuffle_yyyy ) ); - res2 = spu_mul( res2, spu_shuffle( scale, scale, shuffle_zzzz ) ); - res3 = spu_mul( res3, spu_shuffle( scale, scale, shuffle_wwww ) ); - - /* determine case and select answer */ - - xx = spu_shuffle( col0, col0, shuffle_xxxx ); - yy = spu_shuffle( col1, col1, shuffle_yyyy ); - zz = spu_shuffle( col2, col2, shuffle_zzzz ); - res = spu_sel( res0, res1, spu_cmpgt( yy, xx ) ); - res = spu_sel( res, res2, spu_and( spu_cmpgt( zz, xx ), spu_cmpgt( zz, yy ) ) ); - res = spu_sel( res, res3, spu_cmpgt( spu_shuffle( diagSum, diagSum, shuffle_xxxx ), spu_splats(0.0f) ) ); - result->vec128 = res; -} - -static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *tfrm0, const VmathVector3 *tfrm1 ) -{ - vmathV3ScalarMul( &result->col0, tfrm0, vmathV3GetX( tfrm1 ) ); - vmathV3ScalarMul( &result->col1, tfrm0, vmathV3GetY( tfrm1 ) ); - vmathV3ScalarMul( &result->col2, tfrm0, vmathV3GetZ( tfrm1 ) ); -} - -static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *tfrm0, const VmathVector4 *tfrm1 ) -{ - vmathV4ScalarMul( &result->col0, tfrm0, vmathV4GetX( tfrm1 ) ); - vmathV4ScalarMul( &result->col1, tfrm0, vmathV4GetY( tfrm1 ) ); - vmathV4ScalarMul( &result->col2, tfrm0, vmathV4GetZ( tfrm1 ) ); - vmathV4ScalarMul( &result->col3, tfrm0, vmathV4GetW( tfrm1 ) ); -} - -static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) -{ - vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); - xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); - mcol0 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_XAYB ); - mcol1 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); - mcol2 = spu_shuffle( tmp1, mat->col1.vec128, _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); - res = spu_mul( mcol0, xxxx ); - zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); - res = spu_madd( mcol1, yyyy, res ); - res = spu_madd( mcol2, zzzz, res ); - result->vec128 = res; -} - -static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ) -{ - vec_float4 neg, res0, res1, res2; - neg = negatef4( vec->vec128 ); - res0 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_0ZB0 ); - res1 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_C0X0 ); - res2 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_YA00 ); - result->col0.vec128 = res0; - result->col1.vec128 = res1; - result->col2.vec128 = res2; -} - -static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) -{ - VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; - vmathV3Cross( &tmpV3_0, vec, &mat->col0 ); - vmathV3Cross( &tmpV3_1, vec, &mat->col1 ); - vmathV3Cross( &tmpV3_2, vec, &mat->col2 ); - vmathM3MakeFromCols( result, &tmpV3_0, &tmpV3_1, &tmpV3_2 ); -} - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_MAT_AOS_C_H +#define _VECTORMATH_MAT_AOS_C_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Constants + * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + */ +#define _VECTORMATH_SHUF_XAYB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_ZCWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_ZBW0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XCY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_0ZB0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_C0X0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_YA00 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_Z }) +#define _VECTORMATH_SHUF_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X }) +#define _VECTORMATH_SHUF_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y }) +#define _VECTORMATH_SHUF_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_ZAY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_BZX0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_0ZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A }) +#define _VECTORMATH_SHUF_Z0XB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_YX0C ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_CZD0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_D, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_BBY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_PI_OVER_2 1.570796327f + +/*----------------------------------------------------------------------------- + * Definitions + */ +static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( &result->col0, &mat->col0 ); + vmathV3Copy( &result->col1, &mat->col1 ); + vmathV3Copy( &result->col2, &mat->col2 ); +} + +static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ) +{ + vmathV3MakeFromScalar( &result->col0, scalar ); + vmathV3MakeFromScalar( &result->col1, scalar ); + vmathV3MakeFromScalar( &result->col2, scalar ); +} + +static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) +{ + vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + vec_uint4 select_x = (vec_uint4)spu_maskb(0xf000); + vec_uint4 select_z = (vec_uint4)spu_maskb(0x00f0); + xyzw_2 = spu_add( unitQuat->vec128, unitQuat->vec128 ); + wwww = spu_shuffle( unitQuat->vec128, unitQuat->vec128, shuffle_wwww ); + yzxw = spu_shuffle( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_SHUF_YZXW ); + zxyw = spu_shuffle( unitQuat->vec128, unitQuat->vec128, _VECTORMATH_SHUF_ZXYW ); + yzxw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_YZXW ); + zxyw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_ZXYW ); + tmp0 = spu_mul( yzxw_2, wwww ); + tmp1 = spu_nmsub( yzxw, yzxw_2, spu_splats(1.0f) ); + tmp2 = spu_mul( yzxw, xyzw_2 ); + tmp0 = spu_madd( zxyw, xyzw_2, tmp0 ); + tmp1 = spu_nmsub( zxyw, zxyw_2, tmp1 ); + tmp2 = spu_nmsub( zxyw_2, wwww, tmp2 ); + tmp3 = spu_sel( tmp0, tmp1, select_x ); + tmp4 = spu_sel( tmp1, tmp2, select_x ); + tmp5 = spu_sel( tmp2, tmp0, select_x ); + result->col0.vec128 = spu_sel( tmp3, tmp2, select_z ); + result->col1.vec128 = spu_sel( tmp4, tmp0, select_z ); + result->col2.vec128 = spu_sel( tmp5, tmp1, select_z ); +} + +static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col0, _col0 ); + vmathV3Copy( &result->col1, _col1 ); + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *_col0 ) +{ + vmathV3Copy( &result->col0, _col0 ); +} + +static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *_col1 ) +{ + vmathV3Copy( &result->col1, _col1 ); +} + +static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ) +{ + vmathV3Copy( (&result->col0 + col), vec ); +} + +static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ) +{ + vmathV3SetElem( &result->col0, row, vmathV3GetElem( vec, 0 ) ); + vmathV3SetElem( &result->col1, row, vmathV3GetElem( vec, 1 ) ); + vmathV3SetElem( &result->col2, row, vmathV3GetElem( vec, 2 ) ); +} + +static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ) +{ + VmathVector3 tmpV3_0; + vmathM3GetCol( &tmpV3_0, result, col ); + vmathV3SetElem( &tmpV3_0, row, val ); + vmathM3SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ) +{ + VmathVector3 tmpV3_0; + vmathM3GetCol( &tmpV3_0, mat, col ); + return vmathV3GetElem( &tmpV3_0, row ); +} + +static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col0 ); +} + +static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col1 ); +} + +static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Copy( result, &mat->col2 ); +} + +static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ) +{ + vmathV3Copy( result, (&mat->col0 + col) ); +} + +static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ) +{ + vmathV3MakeFromElems( result, vmathV3GetElem( &mat->col0, row ), vmathV3GetElem( &mat->col1, row ), vmathV3GetElem( &mat->col2, row ) ); +} + +static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, res0, res1, res2; + tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); + res0 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_XAYB ); + res1 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); + res2 = spu_shuffle( tmp1, mat->col1.vec128, _VECTORMATH_SHUF_XCY0 ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; + tmp2 = _vmathVfCross( mat->col0.vec128, mat->col1.vec128 ); + tmp0 = _vmathVfCross( mat->col1.vec128, mat->col2.vec128 ); + tmp1 = _vmathVfCross( mat->col2.vec128, mat->col0.vec128 ); + dot = _vmathVfDot3( tmp2, mat->col2.vec128 ); + dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); + invdet = recipf4( dot ); + tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); + tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); + inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); + inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); + inv0 = spu_mul( inv0, invdet ); + inv1 = spu_mul( inv1, invdet ); + inv2 = spu_mul( inv2, invdet ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; +} + +static inline float vmathM3Determinant( const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0; + vmathV3Cross( &tmpV3_0, &mat->col0, &mat->col1 ); + return vmathV3Dot( &mat->col2, &tmpV3_0 ); +} + +static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3Add( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3Add( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3Add( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3Sub( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3Sub( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3Sub( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3Neg( &result->col0, &mat->col0 ); + vmathV3Neg( &result->col1, &mat->col1 ); + vmathV3Neg( &result->col2, &mat->col2 ); +} + +static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ) +{ + vmathV3AbsPerElem( &result->col0, &mat->col0 ); + vmathV3AbsPerElem( &result->col1, &mat->col1 ); + vmathV3AbsPerElem( &result->col2, &mat->col2 ); +} + +static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ) +{ + vmathV3ScalarMul( &result->col0, &mat->col0, scalar ); + vmathV3ScalarMul( &result->col1, &mat->col1, scalar ); + vmathV3ScalarMul( &result->col2, &mat->col2, scalar ); +} + +static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); + res = spu_mul( mat->col0.vec128, xxxx ); + res = spu_madd( mat->col1.vec128, yyyy, res ); + res = spu_madd( mat->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + VmathMatrix3 tmpResult; + vmathM3MulV3( &tmpResult.col0, mat0, &mat1->col0 ); + vmathM3MulV3( &tmpResult.col1, mat0, &mat1->col1 ); + vmathM3MulV3( &tmpResult.col2, mat0, &mat1->col2 ); + vmathM3Copy( result, &tmpResult ); +} + +static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ) +{ + vmathV3MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV3MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV3MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); +} + +static inline void vmathM3MakeIdentity( VmathMatrix3 *result ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); +} + +static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + vmathV3MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV3MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; +} + +static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV3MakeZAxis( &result->col2 ); +} + +static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ->vec128; + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + result->col0.vec128 = spu_mul( Z0, Y0 ); + result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); + result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); +} + +static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + axis = unitVec->vec128; + sincosf4( spu_splats( radians ), &s, &c ); + xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); + yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); + zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); + oneMinusC = spu_sub( spu_splats(1.0f), c ); + axisS = spu_mul( axis, s ); + negAxisS = negatef4( axisS ); + tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); + tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); + tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); + tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); + tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); + tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); + result->col0.vec128 = spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ); + result->col1.vec128 = spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ); + result->col2.vec128 = spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ); +} + +static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ) +{ + vmathM3MakeFromQ( result, unitQuat ); +} + +static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); + result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); + result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); +} + +static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ) +{ + vmathV3ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); + vmathV3ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); + vmathV3ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); +} + +static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ) +{ + vmathV3MulPerElem( &result->col0, &mat->col0, scaleVec ); + vmathV3MulPerElem( &result->col1, &mat->col1, scaleVec ); + vmathV3MulPerElem( &result->col2, &mat->col2, scaleVec ); +} + +static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ) +{ + vmathV3Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); + vmathV3Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); + vmathV3Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathM3Print( const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; + vmathM3GetRow( &tmpV3_0, mat, 0 ); + vmathV3Print( &tmpV3_0 ); + vmathM3GetRow( &tmpV3_1, mat, 1 ); + vmathV3Print( &tmpV3_1 ); + vmathM3GetRow( &tmpV3_2, mat, 2 ); + vmathV3Print( &tmpV3_2 ); +} + +static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ) +{ + printf("%s:\n", name); + vmathM3Print( mat ); +} + +#endif + +static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( &result->col0, &mat->col0 ); + vmathV4Copy( &result->col1, &mat->col1 ); + vmathV4Copy( &result->col2, &mat->col2 ); + vmathV4Copy( &result->col3, &mat->col3 ); +} + +static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ) +{ + vmathV4MakeFromScalar( &result->col0, scalar ); + vmathV4MakeFromScalar( &result->col1, scalar ); + vmathV4MakeFromScalar( &result->col2, scalar ); + vmathV4MakeFromScalar( &result->col3, scalar ); +} + +static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ) +{ + vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, &mat->col3, 1.0f ); +} + +static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *_col0, const VmathVector4 *_col1, const VmathVector4 *_col2, const VmathVector4 *_col3 ) +{ + vmathV4Copy( &result->col0, _col0 ); + vmathV4Copy( &result->col1, _col1 ); + vmathV4Copy( &result->col2, _col2 ); + vmathV4Copy( &result->col3, _col3 ); +} + +static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ) +{ + vmathV4MakeFromV3Scalar( &result->col0, &mat->col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat->col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat->col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) +{ + VmathMatrix3 mat; + vmathM3MakeFromQ( &mat, unitQuat ); + vmathV4MakeFromV3Scalar( &result->col0, &mat.col0, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col1, &mat.col1, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col2, &mat.col2, 0.0f ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *_col0 ) +{ + vmathV4Copy( &result->col0, _col0 ); +} + +static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *_col1 ) +{ + vmathV4Copy( &result->col1, _col1 ); +} + +static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *_col2 ) +{ + vmathV4Copy( &result->col2, _col2 ); +} + +static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *_col3 ) +{ + vmathV4Copy( &result->col3, _col3 ); +} + +static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ) +{ + vmathV4Copy( (&result->col0 + col), vec ); +} + +static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ) +{ + vmathV4SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); + vmathV4SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); + vmathV4SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); + vmathV4SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); +} + +static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ) +{ + VmathVector4 tmpV3_0; + vmathM4GetCol( &tmpV3_0, result, col ); + vmathV4SetElem( &tmpV3_0, row, val ); + vmathM4SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ) +{ + VmathVector4 tmpV4_0; + vmathM4GetCol( &tmpV4_0, mat, col ); + return vmathV4GetElem( &tmpV4_0, row ); +} + +static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col0 ); +} + +static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col1 ); +} + +static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col2 ); +} + +static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Copy( result, &mat->col3 ); +} + +static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ) +{ + vmathV4Copy( result, (&mat->col0 + col) ); +} + +static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ) +{ + vmathV4MakeFromElems( result, vmathV4GetElem( &mat->col0, row ), vmathV4GetElem( &mat->col1, row ), vmathV4GetElem( &mat->col2, row ), vmathV4GetElem( &mat->col3, row ) ); +} + +static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; + tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat->col1.vec128, mat->col3.vec128, _VECTORMATH_SHUF_XAYB ); + tmp2 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); + tmp3 = spu_shuffle( mat->col1.vec128, mat->col3.vec128, _VECTORMATH_SHUF_ZCWD ); + res0 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_XAYB ); + res1 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_ZCWD ); + res2 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_XAYB ); + res3 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_ZCWD ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; + result->col3.vec128 = res3; +} + +static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 in0, in1, in2, in3; + vec_float4 tmp0, tmp1, tmp2, tmp3; + vec_float4 cof0, cof1, cof2, cof3; + vec_float4 t0, t1, t2, t3; + vec_float4 t01, t02, t03, t12, t23; + vec_float4 t1r, t2r; + vec_float4 t01r, t02r, t03r, t12r, t23r; + vec_float4 t1r3, t1r3r; + vec_float4 det, det1, det2, det3, invdet; + in0 = mat->col0.vec128; + in1 = mat->col1.vec128; + in2 = mat->col2.vec128; + in3 = mat->col3.vec128; + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ + tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ + tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ + tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ + t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ + t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ + t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ + t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = spu_mul(t2, t3); /* CL GP KD OH */ + t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ + cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ + cof1 = spu_mul(t0, t23); /* AGP ECL IOH MKD */ + t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ + cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ + cof1 = spu_msub(t0, t23r, cof1); /* AOH EKD IGP MCL - cof1 */ + cof1 = spu_rlqwbyte(cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ + + t12 = spu_mul(t1, t2); /* JC NG BK FO */ + t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ + cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + cof3 = spu_mul(t0, t12); /* ANG EJC IFO MBK */ + t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ + cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + cof3 = spu_msub(t0, t12r, cof3); /* AFO EBK ING MJC - cof3 */ + cof3 = spu_rlqwbyte(cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ + t1r = spu_rlqwbyte(t1, 8); /* B F J N */ + t2r = spu_rlqwbyte(t2, 8); /* K O C G */ + t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ + t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ + cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + cof2 = spu_mul(t0, t1r3); /* AFP EBL INH MJD */ + t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ + cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + cof2 = spu_msub(t0, t1r3r, cof2); /* ANH EJD IFP MBL - cof2 */ + cof2 = spu_rlqwbyte(cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ + t01 = spu_mul(t0, t1); /* AJ EN IB MF */ + t01 = spu_shuffle(t01, t01, _VECTORMATH_SHUF_YXWZ); /* EN AJ MF IB */ + cof2 = spu_madd(t3, t01, cof2); /* LEN PAJ DMF HIB + cof2 */ + cof3 = spu_msub(t2r, t01, cof3); /* KEN OAJ CMF GIB - cof3 */ + t01r = spu_rlqwbyte(t01, 8); /* MF IB EN AJ */ + cof2 = spu_msub(t3, t01r, cof2); /* LMF PIB DEN HAJ - cof2 */ + cof3 = spu_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ + t03 = spu_mul(t0, t3); /* AL EP ID MH */ + t03 = spu_shuffle(t03, t03, _VECTORMATH_SHUF_YXWZ); /* EP AL MH ID */ + cof1 = spu_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ + cof2 = spu_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ + t03r = spu_rlqwbyte(t03, 8); /* MH ID EP AL */ + cof1 = spu_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ + cof2 = spu_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ + t02 = spu_mul(t0, t2r); /* AK EO IC MG */ + t02 = spu_shuffle(t02, t02, _VECTORMATH_SHUF_YXWZ); /* E0 AK MG IC */ + cof1 = spu_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ + cof3 = spu_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ + t02r = spu_rlqwbyte(t02, 8); /* MG IC EO AK */ + cof1 = spu_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ + cof3 = spu_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ + /* Compute the determinant of the matrix + * + * det = sum_across(t0 * cof0); + * + * We perform a sum across the entire vector so that + * we don't have to splat the result when multiplying the + * cofactors by the inverse of the determinant. + */ + det = spu_mul(t0, cof0); + det1 = spu_rlqwbyte(det, 4); + det2 = spu_rlqwbyte(det, 8); + det3 = spu_rlqwbyte(det, 12); + det = spu_add(det, det1); + det2 = spu_add(det2, det3); + det = spu_add(det, det2); + /* Compute the reciprocal of the determinant. + */ + invdet = recipf4(det); + /* Multiply the cofactors by the reciprocal of the determinant. + */ + result->col0.vec128 = spu_mul(cof0, invdet); + result->col1.vec128 = spu_mul(cof1, invdet); + result->col2.vec128 = spu_mul(cof2, invdet); + result->col3.vec128 = spu_mul(cof3, invdet); +} + +static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + VmathTransform3 affineMat, tmpT3_0; + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; + vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); + vmathT3SetCol0( &affineMat, &tmpV3_0 ); + vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); + vmathT3SetCol1( &affineMat, &tmpV3_1 ); + vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); + vmathT3SetCol2( &affineMat, &tmpV3_2 ); + vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); + vmathT3SetCol3( &affineMat, &tmpV3_3 ); + vmathT3Inverse( &tmpT3_0, &affineMat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + VmathTransform3 affineMat, tmpT3_0; + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2, tmpV3_3; + vmathV4GetXYZ( &tmpV3_0, &mat->col0 ); + vmathT3SetCol0( &affineMat, &tmpV3_0 ); + vmathV4GetXYZ( &tmpV3_1, &mat->col1 ); + vmathT3SetCol1( &affineMat, &tmpV3_1 ); + vmathV4GetXYZ( &tmpV3_2, &mat->col2 ); + vmathT3SetCol2( &affineMat, &tmpV3_2 ); + vmathV4GetXYZ( &tmpV3_3, &mat->col3 ); + vmathT3SetCol3( &affineMat, &tmpV3_3 ); + vmathT3OrthoInverse( &tmpT3_0, &affineMat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline float vmathM4Determinant( const VmathMatrix4 *mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 in0, in1, in2, in3; + vec_float4 tmp0, tmp1, tmp2, tmp3; + vec_float4 cof0; + vec_float4 t0, t1, t2, t3; + vec_float4 t12, t23; + vec_float4 t1r, t2r; + vec_float4 t12r, t23r; + vec_float4 t1r3, t1r3r; + in0 = mat->col0.vec128; + in1 = mat->col1.vec128; + in2 = mat->col2.vec128; + in3 = mat->col3.vec128; + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ + tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ + tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ + tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ + t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ + t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ + t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ + t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = spu_mul(t2, t3); /* CL GP KD OH */ + t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ + cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ + t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ + cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ + + t12 = spu_mul(t1, t2); /* JC NG BK FO */ + t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ + cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ + cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + t1r = spu_rlqwbyte(t1, 8); /* B F J N */ + t2r = spu_rlqwbyte(t2, 8); /* K O C G */ + t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ + t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ + cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ + cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + return spu_extract( _vmathVfDot4(t0,cof0), 0 ); +} + +static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4Add( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4Add( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4Add( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4Add( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4Sub( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4Sub( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4Sub( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4Sub( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4Neg( &result->col0, &mat->col0 ); + vmathV4Neg( &result->col1, &mat->col1 ); + vmathV4Neg( &result->col2, &mat->col2 ); + vmathV4Neg( &result->col3, &mat->col3 ); +} + +static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ) +{ + vmathV4AbsPerElem( &result->col0, &mat->col0 ); + vmathV4AbsPerElem( &result->col1, &mat->col1 ); + vmathV4AbsPerElem( &result->col2, &mat->col2 ); + vmathV4AbsPerElem( &result->col3, &mat->col3 ); +} + +static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ) +{ + vmathV4ScalarMul( &result->col0, &mat->col0, scalar ); + vmathV4ScalarMul( &result->col1, &mat->col1, scalar ); + vmathV4ScalarMul( &result->col2, &mat->col2, scalar ); + vmathV4ScalarMul( &result->col3, &mat->col3, scalar ); +} + +static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz, wwww; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); + wwww = spu_shuffle( vec->vec128, vec->vec128, shuffle_wwww ); + tmp0 = spu_mul( mat->col0.vec128, xxxx ); + tmp1 = spu_mul( mat->col1.vec128, yyyy ); + tmp0 = spu_madd( mat->col2.vec128, zzzz, tmp0 ); + tmp1 = spu_madd( mat->col3.vec128, wwww, tmp1 ); + res = spu_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); + res = spu_mul( mat->col0.vec128, xxxx ); + res = spu_madd( mat->col1.vec128, yyyy, res ); + res = spu_madd( mat->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_zzzz ); + tmp0 = spu_mul( mat->col0.vec128, xxxx ); + tmp1 = spu_mul( mat->col1.vec128, yyyy ); + tmp0 = spu_madd( mat->col2.vec128, zzzz, tmp0 ); + tmp1 = spu_add( mat->col3.vec128, tmp1 ); + res = spu_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + VmathMatrix4 tmpResult; + vmathM4MulV4( &tmpResult.col0, mat0, &mat1->col0 ); + vmathM4MulV4( &tmpResult.col1, mat0, &mat1->col1 ); + vmathM4MulV4( &tmpResult.col2, mat0, &mat1->col2 ); + vmathM4MulV4( &tmpResult.col3, mat0, &mat1->col3 ); + vmathM4Copy( result, &tmpResult ); +} + +static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm1 ) +{ + VmathMatrix4 tmpResult; + VmathPoint3 tmpP3_0; + vmathM4MulV3( &tmpResult.col0, mat, &tfrm1->col0 ); + vmathM4MulV3( &tmpResult.col1, mat, &tfrm1->col1 ); + vmathM4MulV3( &tmpResult.col2, mat, &tfrm1->col2 ); + vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); + vmathM4MulP3( &tmpResult.col3, mat, &tmpP3_0 ); + vmathM4Copy( result, &tmpResult ); +} + +static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ) +{ + vmathV4MulPerElem( &result->col0, &mat0->col0, &mat1->col0 ); + vmathV4MulPerElem( &result->col1, &mat0->col1, &mat1->col1 ); + vmathV4MulPerElem( &result->col2, &mat0->col2, &mat1->col2 ); + vmathV4MulPerElem( &result->col3, &mat0->col3, &mat1->col3 ); +} + +static inline void vmathM4MakeIdentity( VmathMatrix4 *result ) +{ + vmathV4MakeXAxis( &result->col0 ); + vmathV4MakeYAxis( &result->col1 ); + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ) +{ + vmathV4SetXYZ( &result->col0, &mat3->col0 ); + vmathV4SetXYZ( &result->col1, &mat3->col1 ); + vmathV4SetXYZ( &result->col2, &mat3->col2 ); +} + +static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ) +{ + vmathV4GetXYZ( &result->col0, &mat->col0 ); + vmathV4GetXYZ( &result->col1, &mat->col1 ); + vmathV4GetXYZ( &result->col2, &mat->col2 ); +} + +static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) +{ + vmathV4SetXYZ( &result->col3, translateVec ); +} + +static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ) +{ + vmathV4GetXYZ( result, &mat->col3 ); +} + +static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + vmathV4MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV4MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ->vec128; + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + result->col0.vec128 = spu_mul( Z0, Y0 ); + result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); + result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + axis = unitVec->vec128; + sincosf4( spu_splats( radians ), &s, &c ); + xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); + yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); + zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); + oneMinusC = spu_sub( spu_splats(1.0f), c ); + axisS = spu_mul( axis, s ); + negAxisS = negatef4( axisS ); + tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); + tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); + tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); + tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); + tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); + tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); + zeroW = (vec_float4)spu_maskb(0x000f); + axis = spu_andc( axis, zeroW ); + result->col0.vec128 = spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ); + result->col1.vec128 = spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ); + result->col2.vec128 = spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ) +{ + VmathTransform3 tmpT3_0; + vmathT3MakeRotationQ( &tmpT3_0, unitQuat ); + vmathM4MakeFromT3( result, &tmpT3_0 ); +} + +static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); + result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); + result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); + vmathV4MakeWAxis( &result->col3 ); +} + +static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ) +{ + vmathV4ScalarMul( &result->col0, &mat->col0, vmathV3GetX( scaleVec ) ); + vmathV4ScalarMul( &result->col1, &mat->col1, vmathV3GetY( scaleVec ) ); + vmathV4ScalarMul( &result->col2, &mat->col2, vmathV3GetZ( scaleVec ) ); + vmathV4Copy( &result->col3, &mat->col3 ); +} + +static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ) +{ + VmathVector4 scale4; + vmathV4MakeFromV3Scalar( &scale4, scaleVec, 1.0f ); + vmathV4MulPerElem( &result->col0, &mat->col0, &scale4 ); + vmathV4MulPerElem( &result->col1, &mat->col1, &scale4 ); + vmathV4MulPerElem( &result->col2, &mat->col2, &scale4 ); + vmathV4MulPerElem( &result->col3, &mat->col3, &scale4 ); +} + +static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ) +{ + vmathV4MakeXAxis( &result->col0 ); + vmathV4MakeYAxis( &result->col1 ); + vmathV4MakeZAxis( &result->col2 ); + vmathV4MakeFromV3Scalar( &result->col3, translateVec, 1.0f ); +} + +static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ) +{ + VmathMatrix4 m4EyeFrame; + VmathVector3 v3X, v3Y, v3Z, tmpV3_0, tmpV3_1; + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; + vmathV3Normalize( &v3Y, upVec ); + vmathP3Sub( &tmpV3_0, eyePos, lookAtPos ); + vmathV3Normalize( &v3Z, &tmpV3_0 ); + vmathV3Cross( &tmpV3_1, &v3Y, &v3Z ); + vmathV3Normalize( &v3X, &tmpV3_1 ); + vmathV3Cross( &v3Y, &v3Z, &v3X ); + vmathV4MakeFromV3( &tmpV4_0, &v3X ); + vmathV4MakeFromV3( &tmpV4_1, &v3Y ); + vmathV4MakeFromV3( &tmpV4_2, &v3Z ); + vmathV4MakeFromP3( &tmpV4_3, eyePos ); + vmathM4MakeFromCols( &m4EyeFrame, &tmpV4_0, &tmpV4_1, &tmpV4_2, &tmpV4_3 ); + vmathM4OrthoInverse( result, &m4EyeFrame ); +} + +static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ) +{ + float f, rangeInv; + vec_float4 zero, col0, col1, col2, col3; + f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); + rangeInv = 1.0f / ( zNear - zFar ); + zero = spu_splats(0.0f); + col0 = zero; + col1 = zero; + col2 = zero; + col3 = zero; + col0 = spu_insert( f / aspect, col0, 0 ); + col1 = spu_insert( f, col1, 1 ); + col2 = spu_insert( ( zNear + zFar ) * rangeInv, col2, 2 ); + col2 = spu_insert( -1.0f, col2, 3 ); + col3 = spu_insert( zNear * zFar * rangeInv * 2.0f, col3, 2 ); + result->col0.vec128 = col0; + result->col1.vec128 = col1; + result->col2.vec128 = col2; + result->col3.vec128 = col3; +} + +static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff; + vec_float4 diagonal, column, near2; + vec_float4 zero = spu_splats(0.0f); + lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); + lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); + diff = spu_sub( rtn, lbf ); + sum = spu_add( rtn, lbf ); + inv_diff = recipf4( diff ); + near2 = spu_splats( zNear ); + near2 = spu_add( near2, near2 ); + diagonal = spu_mul( near2, inv_diff ); + column = spu_mul( sum, inv_diff ); + result->col0.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ); + result->col1.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ); + result->col2.vec128 = spu_sel( column, spu_splats(-1.0f), (vec_uint4)spu_maskb(0x000f) ); + result->col3.vec128 = spu_sel( zero, spu_mul( diagonal, spu_splats(zFar) ), (vec_uint4)spu_maskb(0x00f0) ); +} + +static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff, neg_inv_diff; + vec_float4 diagonal, column; + vec_float4 zero = spu_splats(0.0f); + lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); + lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); + diff = spu_sub( rtn, lbf ); + sum = spu_add( rtn, lbf ); + inv_diff = recipf4( diff ); + neg_inv_diff = negatef4( inv_diff ); + diagonal = spu_add( inv_diff, inv_diff ); + column = spu_mul( sum, spu_sel( neg_inv_diff, inv_diff, (vec_uint4)spu_maskb(0x00f0) ) ); + result->col0.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ); + result->col1.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ); + result->col2.vec128 = spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x00f0) ); + result->col3.vec128 = spu_sel( column, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); +} + +static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ) +{ + vmathV4Select( &result->col0, &mat0->col0, &mat1->col0, select1 ); + vmathV4Select( &result->col1, &mat0->col1, &mat1->col1, select1 ); + vmathV4Select( &result->col2, &mat0->col2, &mat1->col2, select1 ); + vmathV4Select( &result->col3, &mat0->col3, &mat1->col3, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathM4Print( const VmathMatrix4 *mat ) +{ + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2, tmpV4_3; + vmathM4GetRow( &tmpV4_0, mat, 0 ); + vmathV4Print( &tmpV4_0 ); + vmathM4GetRow( &tmpV4_1, mat, 1 ); + vmathV4Print( &tmpV4_1 ); + vmathM4GetRow( &tmpV4_2, mat, 2 ); + vmathV4Print( &tmpV4_2 ); + vmathM4GetRow( &tmpV4_3, mat, 3 ); + vmathV4Print( &tmpV4_3 ); +} + +static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ) +{ + printf("%s:\n", name); + vmathM4Print( mat ); +} + +#endif + +static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( &result->col0, &tfrm->col0 ); + vmathV3Copy( &result->col1, &tfrm->col1 ); + vmathV3Copy( &result->col2, &tfrm->col2 ); + vmathV3Copy( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ) +{ + vmathV3MakeFromScalar( &result->col0, scalar ); + vmathV3MakeFromScalar( &result->col1, scalar ); + vmathV3MakeFromScalar( &result->col2, scalar ); + vmathV3MakeFromScalar( &result->col3, scalar ); +} + +static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *_col0, const VmathVector3 *_col1, const VmathVector3 *_col2, const VmathVector3 *_col3 ) +{ + vmathV3Copy( &result->col0, _col0 ); + vmathV3Copy( &result->col1, _col1 ); + vmathV3Copy( &result->col2, _col2 ); + vmathV3Copy( &result->col3, _col3 ); +} + +static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ) +{ + vmathT3SetUpper3x3( result, tfrm ); + vmathT3SetTranslation( result, translateVec ); +} + +static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ) +{ + VmathMatrix3 tmpM3_0; + vmathM3MakeFromQ( &tmpM3_0, unitQuat ); + vmathT3SetUpper3x3( result, &tmpM3_0 ); + vmathT3SetTranslation( result, translateVec ); +} + +static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *_col0 ) +{ + vmathV3Copy( &result->col0, _col0 ); +} + +static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *_col1 ) +{ + vmathV3Copy( &result->col1, _col1 ); +} + +static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *_col2 ) +{ + vmathV3Copy( &result->col2, _col2 ); +} + +static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *_col3 ) +{ + vmathV3Copy( &result->col3, _col3 ); +} + +static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ) +{ + vmathV3Copy( (&result->col0 + col), vec ); +} + +static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ) +{ + vmathV3SetElem( &result->col0, row, vmathV4GetElem( vec, 0 ) ); + vmathV3SetElem( &result->col1, row, vmathV4GetElem( vec, 1 ) ); + vmathV3SetElem( &result->col2, row, vmathV4GetElem( vec, 2 ) ); + vmathV3SetElem( &result->col3, row, vmathV4GetElem( vec, 3 ) ); +} + +static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ) +{ + VmathVector3 tmpV3_0; + vmathT3GetCol( &tmpV3_0, result, col ); + vmathV3SetElem( &tmpV3_0, row, val ); + vmathT3SetCol( result, col, &tmpV3_0 ); +} + +static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ) +{ + VmathVector3 tmpV3_0; + vmathT3GetCol( &tmpV3_0, tfrm, col ); + return vmathV3GetElem( &tmpV3_0, row ); +} + +static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col0 ); +} + +static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col1 ); +} + +static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col2 ); +} + +static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col3 ); +} + +static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ) +{ + vmathV3Copy( result, (&tfrm->col0 + col) ); +} + +static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ) +{ + vmathV4MakeFromElems( result, vmathV3GetElem( &tfrm->col0, row ), vmathV3GetElem( &tfrm->col1, row ), vmathV3GetElem( &tfrm->col2, row ), vmathV3GetElem( &tfrm->col3, row ) ); +} + +static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp2 = _vmathVfCross( tfrm->col0.vec128, tfrm->col1.vec128 ); + tmp0 = _vmathVfCross( tfrm->col1.vec128, tfrm->col2.vec128 ); + tmp1 = _vmathVfCross( tfrm->col2.vec128, tfrm->col0.vec128 ); + inv3 = negatef4( tfrm->col3.vec128 ); + dot = _vmathVfDot3( tmp2, tfrm->col2.vec128 ); + dot = spu_shuffle( dot, dot, shuffle_xxxx ); + invdet = recipf4( dot ); + tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); + tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); + inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); + xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); + inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); + zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); + inv3 = spu_mul( inv0, xxxx ); + inv3 = spu_madd( inv1, yyyy, inv3 ); + inv3 = spu_madd( inv2, zzzz, inv3 ); + inv0 = spu_mul( inv0, invdet ); + inv1 = spu_mul( inv1, invdet ); + inv2 = spu_mul( inv2, invdet ); + inv3 = spu_mul( inv3, invdet ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; + result->col3.vec128 = inv3; +} + +static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp0 = spu_shuffle( tfrm->col0.vec128, tfrm->col2.vec128, _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( tfrm->col0.vec128, tfrm->col2.vec128, _VECTORMATH_SHUF_ZCWD ); + inv3 = negatef4( tfrm->col3.vec128 ); + inv0 = spu_shuffle( tmp0, tfrm->col1.vec128, _VECTORMATH_SHUF_XAYB ); + xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); + inv1 = spu_shuffle( tmp0, tfrm->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp1, tfrm->col1.vec128, _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); + zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); + inv3 = spu_mul( inv0, xxxx ); + inv3 = spu_madd( inv1, yyyy, inv3 ); + inv3 = spu_madd( inv2, zzzz, inv3 ); + result->col0.vec128 = inv0; + result->col1.vec128 = inv1; + result->col2.vec128 = inv2; + result->col3.vec128 = inv3; +} + +static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3AbsPerElem( &result->col0, &tfrm->col0 ); + vmathV3AbsPerElem( &result->col1, &tfrm->col1 ); + vmathV3AbsPerElem( &result->col2, &tfrm->col2 ); + vmathV3AbsPerElem( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ) +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); + res = spu_mul( tfrm->col0.vec128, xxxx ); + res = spu_madd( tfrm->col1.vec128, yyyy, res ); + res = spu_madd( tfrm->col2.vec128, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ) +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_xxxx ); + yyyy = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_yyyy ); + zzzz = spu_shuffle( pnt->vec128, pnt->vec128, shuffle_zzzz ); + tmp0 = spu_mul( tfrm->col0.vec128, xxxx ); + tmp1 = spu_mul( tfrm->col1.vec128, yyyy ); + tmp0 = spu_madd( tfrm->col2.vec128, zzzz, tmp0 ); + tmp1 = spu_add( tfrm->col3.vec128, tmp1 ); + res = spu_add( tmp0, tmp1 ); + result->vec128 = res; +} + +static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) +{ + VmathTransform3 tmpResult; + VmathPoint3 tmpP3_0, tmpP3_1; + vmathT3MulV3( &tmpResult.col0, tfrm0, &tfrm1->col0 ); + vmathT3MulV3( &tmpResult.col1, tfrm0, &tfrm1->col1 ); + vmathT3MulV3( &tmpResult.col2, tfrm0, &tfrm1->col2 ); + vmathP3MakeFromV3( &tmpP3_0, &tfrm1->col3 ); + vmathT3MulP3( &tmpP3_1, tfrm0, &tmpP3_0 ); + vmathV3MakeFromP3( &tmpResult.col3, &tmpP3_1 ); + vmathT3Copy( result, &tmpResult ); +} + +static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ) +{ + vmathV3MulPerElem( &result->col0, &tfrm0->col0, &tfrm1->col0 ); + vmathV3MulPerElem( &result->col1, &tfrm0->col1, &tfrm1->col1 ); + vmathV3MulPerElem( &result->col2, &tfrm0->col2, &tfrm1->col2 ); + vmathV3MulPerElem( &result->col3, &tfrm0->col3, &tfrm1->col3 ); +} + +static inline void vmathT3MakeIdentity( VmathTransform3 *result ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *tfrm ) +{ + vmathV3Copy( &result->col0, &tfrm->col0 ); + vmathV3Copy( &result->col1, &tfrm->col1 ); + vmathV3Copy( &result->col2, &tfrm->col2 ); +} + +static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ) +{ + vmathM3MakeFromCols( result, &tfrm->col0, &tfrm->col1, &tfrm->col2 ); +} + +static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) +{ + vmathV3Copy( &result->col3, translateVec ); +} + +static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ) +{ + vmathV3Copy( result, &tfrm->col3 ); +} + +static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + vmathV3MakeXAxis( &result->col0 ); + result->col1.vec128 = res1; + result->col2.vec128 = res2; + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + result->col0.vec128 = res0; + vmathV3MakeYAxis( &result->col1 ); + result->col2.vec128 = res2; + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + vmathV3MakeZAxis( &result->col2 ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ->vec128; + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + result->col0.vec128 = spu_mul( Z0, Y0 ); + result->col1.vec128 = spu_madd( Z1, X1, spu_mul( tmp, X0 ) ); + result->col2.vec128 = spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ) +{ + VmathMatrix3 tmpM3_0; + VmathVector3 tmpV3_0; + vmathM3MakeRotationAxis( &tmpM3_0, radians, unitVec ); + vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); + vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); +} + +static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ) +{ + VmathMatrix3 tmpM3_0; + VmathVector3 tmpV3_0; + vmathM3MakeFromQ( &tmpM3_0, unitQuat ); + vmathV3MakeFromScalar( &tmpV3_0, 0.0f ); + vmathT3MakeFromM3V3( result, &tmpM3_0, &tmpV3_0 ); +} + +static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + result->col0.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0xf000) ); + result->col1.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x0f00) ); + result->col2.vec128 = spu_sel( zero, scaleVec->vec128, (vec_uint4)spu_maskb(0x00f0) ); + vmathV3MakeFromScalar( &result->col3, 0.0f ); +} + +static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ) +{ + vmathV3ScalarMul( &result->col0, &tfrm->col0, vmathV3GetX( scaleVec ) ); + vmathV3ScalarMul( &result->col1, &tfrm->col1, vmathV3GetY( scaleVec ) ); + vmathV3ScalarMul( &result->col2, &tfrm->col2, vmathV3GetZ( scaleVec ) ); + vmathV3Copy( &result->col3, &tfrm->col3 ); +} + +static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ) +{ + vmathV3MulPerElem( &result->col0, &tfrm->col0, scaleVec ); + vmathV3MulPerElem( &result->col1, &tfrm->col1, scaleVec ); + vmathV3MulPerElem( &result->col2, &tfrm->col2, scaleVec ); + vmathV3MulPerElem( &result->col3, &tfrm->col3, scaleVec ); +} + +static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ) +{ + vmathV3MakeXAxis( &result->col0 ); + vmathV3MakeYAxis( &result->col1 ); + vmathV3MakeZAxis( &result->col2 ); + vmathV3Copy( &result->col3, translateVec ); +} + +static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ) +{ + vmathV3Select( &result->col0, &tfrm0->col0, &tfrm1->col0, select1 ); + vmathV3Select( &result->col1, &tfrm0->col1, &tfrm1->col1, select1 ); + vmathV3Select( &result->col2, &tfrm0->col2, &tfrm1->col2, select1 ); + vmathV3Select( &result->col3, &tfrm0->col3, &tfrm1->col3, select1 ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathT3Print( const VmathTransform3 *tfrm ) +{ + VmathVector4 tmpV4_0, tmpV4_1, tmpV4_2; + vmathT3GetRow( &tmpV4_0, tfrm, 0 ); + vmathV4Print( &tmpV4_0 ); + vmathT3GetRow( &tmpV4_1, tfrm, 1 ); + vmathV4Print( &tmpV4_1 ); + vmathT3GetRow( &tmpV4_2, tfrm, 2 ); + vmathV4Print( &tmpV4_2 ); +} + +static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ) +{ + printf("%s:\n", name); + vmathT3Print( tfrm ); +} + +#endif + +static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *tfrm ) +{ + vec_float4 res; + vec_float4 col0, col1, col2; + vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; + vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; + vec_float4 radicand, invSqrt, scale; + vec_float4 res0, res1, res2, res3; + vec_float4 xx, yy, zz; + vec_uint4 select_x = (vec_uint4)spu_maskb( 0xf000 ); + vec_uint4 select_y = (vec_uint4)spu_maskb( 0x0f00 ); + vec_uint4 select_z = (vec_uint4)spu_maskb( 0x00f0 ); + vec_uint4 select_w = (vec_uint4)spu_maskb( 0x000f ); + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((unsigned int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((unsigned int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((unsigned int)0x08090a0b); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((unsigned int)0x0c0d0e0f); + + col0 = tfrm->col0.vec128; + col1 = tfrm->col1.vec128; + col2 = tfrm->col2.vec128; + + /* four cases: */ + /* trace > 0 */ + /* else */ + /* xx largest diagonal element */ + /* yy largest diagonal element */ + /* zz largest diagonal element */ + + /* compute quaternion for each case */ + + xx_yy = spu_sel( col0, col1, select_y ); + xx_yy_zz_xx = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_XYCX ); + yy_zz_xx_yy = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_YCXY ); + zz_xx_yy_zz = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_CXYC ); + + diagSum = spu_add( spu_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + diagDiff = spu_sub( spu_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + radicand = spu_add( spu_sel( diagDiff, diagSum, select_w ), spu_splats(1.0f) ); + invSqrt = rsqrtf4( radicand ); + + zy_xz_yx = spu_sel( col0, col1, select_z ); + zy_xz_yx = spu_shuffle( zy_xz_yx, col2, _VECTORMATH_SHUF_ZAY0 ); + yz_zx_xy = spu_sel( col0, col1, select_x ); + yz_zx_xy = spu_shuffle( yz_zx_xy, col2, _VECTORMATH_SHUF_BZX0 ); + + sum = spu_add( zy_xz_yx, yz_zx_xy ); + diff = spu_sub( zy_xz_yx, yz_zx_xy ); + + scale = spu_mul( invSqrt, spu_splats(0.5f) ); + res0 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_0ZYA ); + res1 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_Z0XB ); + res2 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_YX0C ); + res3 = diff; + res0 = spu_sel( res0, radicand, select_x ); + res1 = spu_sel( res1, radicand, select_y ); + res2 = spu_sel( res2, radicand, select_z ); + res3 = spu_sel( res3, radicand, select_w ); + res0 = spu_mul( res0, spu_shuffle( scale, scale, shuffle_xxxx ) ); + res1 = spu_mul( res1, spu_shuffle( scale, scale, shuffle_yyyy ) ); + res2 = spu_mul( res2, spu_shuffle( scale, scale, shuffle_zzzz ) ); + res3 = spu_mul( res3, spu_shuffle( scale, scale, shuffle_wwww ) ); + + /* determine case and select answer */ + + xx = spu_shuffle( col0, col0, shuffle_xxxx ); + yy = spu_shuffle( col1, col1, shuffle_yyyy ); + zz = spu_shuffle( col2, col2, shuffle_zzzz ); + res = spu_sel( res0, res1, spu_cmpgt( yy, xx ) ); + res = spu_sel( res, res2, spu_and( spu_cmpgt( zz, xx ), spu_cmpgt( zz, yy ) ) ); + res = spu_sel( res, res3, spu_cmpgt( spu_shuffle( diagSum, diagSum, shuffle_xxxx ), spu_splats(0.0f) ) ); + result->vec128 = res; +} + +static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *tfrm0, const VmathVector3 *tfrm1 ) +{ + vmathV3ScalarMul( &result->col0, tfrm0, vmathV3GetX( tfrm1 ) ); + vmathV3ScalarMul( &result->col1, tfrm0, vmathV3GetY( tfrm1 ) ); + vmathV3ScalarMul( &result->col2, tfrm0, vmathV3GetZ( tfrm1 ) ); +} + +static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *tfrm0, const VmathVector4 *tfrm1 ) +{ + vmathV4ScalarMul( &result->col0, tfrm0, vmathV4GetX( tfrm1 ) ); + vmathV4ScalarMul( &result->col1, tfrm0, vmathV4GetY( tfrm1 ) ); + vmathV4ScalarMul( &result->col2, tfrm0, vmathV4GetZ( tfrm1 ) ); + vmathV4ScalarMul( &result->col3, tfrm0, vmathV4GetW( tfrm1 ) ); +} + +static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) +{ + vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp0 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat->col0.vec128, mat->col2.vec128, _VECTORMATH_SHUF_ZCWD ); + xxxx = spu_shuffle( vec->vec128, vec->vec128, shuffle_xxxx ); + mcol0 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_XAYB ); + mcol1 = spu_shuffle( tmp0, mat->col1.vec128, _VECTORMATH_SHUF_ZBW0 ); + mcol2 = spu_shuffle( tmp1, mat->col1.vec128, _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( vec->vec128, vec->vec128, shuffle_yyyy ); + res = spu_mul( mcol0, xxxx ); + zzzz = spu_shuffle( vec->vec128, vec->vec128, shuffle_zzzz ); + res = spu_madd( mcol1, yyyy, res ); + res = spu_madd( mcol2, zzzz, res ); + result->vec128 = res; +} + +static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ) +{ + vec_float4 neg, res0, res1, res2; + neg = negatef4( vec->vec128 ); + res0 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_0ZB0 ); + res1 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_C0X0 ); + res2 = spu_shuffle( vec->vec128, neg, _VECTORMATH_SHUF_YA00 ); + result->col0.vec128 = res0; + result->col1.vec128 = res1; + result->col2.vec128 = res2; +} + +static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ) +{ + VmathVector3 tmpV3_0, tmpV3_1, tmpV3_2; + vmathV3Cross( &tmpV3_0, vec, &mat->col0 ); + vmathV3Cross( &tmpV3_1, vec, &mat->col1 ); + vmathV3Cross( &tmpV3_2, vec, &mat->col2 ); + vmathM3MakeFromCols( result, &tmpV3_0, &tmpV3_1, &tmpV3_2 ); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/spu/c/quat_aos.h b/common/vectormath/spu/c/quat_aos.h index 0f25d654..b20109b1 100644 --- a/common/vectormath/spu/c/quat_aos.h +++ b/common/vectormath/spu/c/quat_aos.h @@ -1,371 +1,371 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_QUAT_AOS_C_H -#define _VECTORMATH_QUAT_AOS_C_H -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Definitions - */ -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -#endif - -static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathQMakeFromElems( VmathQuat *result, float _x, float _y, float _z, float _w ) -{ - result->vec128 = (vec_float4){ _x, _y, _z, _w }; -} - -static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float _w ) -{ - result->vec128 = spu_shuffle( xyz->vec128, spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); -} - -static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ) -{ - result->vec128 = spu_splats( scalar ); -} - -static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathQMakeIdentity( VmathQuat *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0001; -} - -static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - VmathQuat tmpQ_0, tmpQ_1; - vmathQSub( &tmpQ_0, quat1, quat0 ); - vmathQScalarMul( &tmpQ_1, &tmpQ_0, t ); - vmathQAdd( result, quat0, &tmpQ_1 ); -} - -static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ) -{ - VmathQuat start; - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot4( unitQuat0->vec128, unitQuat1->vec128 ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(0.0f), cosAngle ); - cosAngle = spu_sel( cosAngle, negatef4( cosAngle ), selectMask ); - start.vec128 = spu_sel( unitQuat0->vec128, negatef4( unitQuat0->vec128 ), selectMask ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - result->vec128 = spu_madd( start.vec128, scale0, spu_mul( unitQuat1->vec128, scale1 ) ); -} - -static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ) -{ - VmathQuat tmp0, tmp1; - vmathQSlerp( &tmp0, t, unitQuat0, unitQuat3 ); - vmathQSlerp( &tmp1, t, unitQuat1, unitQuat2 ); - vmathQSlerp( result, ( ( 2.0f * t ) * ( 1.0f - t ) ), &tmp0, &tmp1 ); -} - -static inline vec_float4 vmathQGet128( const VmathQuat *quat ) -{ - return quat->vec128; -} - -static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ) -{ - result->vec128 = spu_sel( vec->vec128, result->vec128, (vec_uint4)spu_maskb(0x000f) ); -} - -static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathQSetX( VmathQuat *result, float _x ) -{ - result->vec128 = spu_insert( _x, result->vec128, 0 ); -} - -static inline float vmathQGetX( const VmathQuat *quat ) -{ - return spu_extract( quat->vec128, 0 ); -} - -static inline void vmathQSetY( VmathQuat *result, float _y ) -{ - result->vec128 = spu_insert( _y, result->vec128, 1 ); -} - -static inline float vmathQGetY( const VmathQuat *quat ) -{ - return spu_extract( quat->vec128, 1 ); -} - -static inline void vmathQSetZ( VmathQuat *result, float _z ) -{ - result->vec128 = spu_insert( _z, result->vec128, 2 ); -} - -static inline float vmathQGetZ( const VmathQuat *quat ) -{ - return spu_extract( quat->vec128, 2 ); -} - -static inline void vmathQSetW( VmathQuat *result, float _w ) -{ - result->vec128 = spu_insert( _w, result->vec128, 3 ); -} - -static inline float vmathQGetW( const VmathQuat *quat ) -{ - return spu_extract( quat->vec128, 3 ); -} - -static inline void vmathQSetElem( VmathQuat *result, int idx, float value ) -{ - result->vec128 = spu_insert( value, result->vec128, idx ); -} - -static inline float vmathQGetElem( const VmathQuat *quat, int idx ) -{ - return spu_extract( quat->vec128, idx ); -} - -static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - result->vec128 = spu_add( quat0->vec128, quat1->vec128 ); -} - -static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - result->vec128 = spu_sub( quat0->vec128, quat1->vec128 ); -} - -static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ) -{ - result->vec128 = spu_mul( quat->vec128, spu_splats(scalar) ); -} - -static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ) -{ - result->vec128 = divf4( quat->vec128, spu_splats(scalar) ); -} - -static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = negatef4( quat->vec128 ); -} - -static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - return spu_extract( _vmathVfDot4( quat0->vec128, quat1->vec128 ), 0 ); -} - -static inline float vmathQNorm( const VmathQuat *quat ) -{ - return spu_extract( _vmathVfDot4( quat->vec128, quat->vec128 ), 0 ); -} - -static inline float vmathQLength( const VmathQuat *quat ) -{ - return sqrtf( vmathQNorm( quat ) ); -} - -static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ) -{ - vec_float4 dot = _vmathVfDot4( quat->vec128, quat->vec128 ); - result->vec128 = spu_mul( quat->vec128, rsqrtf4( dot ) ); -} - -static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) -{ - VmathVector3 crossVec, tmpV3_0; - vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; - cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = spu_shuffle( cosAngle, cosAngle, (vec_uchar16)spu_splats(0x00010203) ); - cosAngleX2Plus2 = spu_madd( cosAngle, spu_splats(2.0f), spu_splats(2.0f) ); - recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); - cosHalfAngleX2 = spu_mul( recipCosHalfAngleX2, cosAngleX2Plus2 ); - vmathV3Cross( &tmpV3_0, unitVec0, unitVec1 ); - crossVec = tmpV3_0; - res = spu_mul( crossVec.vec128, recipCosHalfAngleX2 ); - res = spu_sel( res, spu_mul( cosHalfAngleX2, spu_splats(0.5f) ), (vec_uint4)spu_maskb(0x000f) ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_mul( unitVec->vec128, s ), c, (vec_uint4)spu_maskb(0x000f) ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationX( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0xf000) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationY( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x0f00) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - result->vec128 = res; -} - -static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x00f0) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - result->vec128 = res; -} - -static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) -{ - vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; - vec_float4 product, l_wxyz, r_wxyz, xy, qw; - ldata = quat0->vec128; - rdata = quat1->vec128; - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - tmp0 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_YZXW ); - qv = spu_mul( spu_shuffle( ldata, ldata, shuffle_wwww ), rdata ); - qv = spu_madd( spu_shuffle( rdata, rdata, shuffle_wwww ), ldata, qv ); - qv = spu_madd( tmp0, tmp1, qv ); - qv = spu_nmsub( tmp2, tmp3, qv ); - product = spu_mul( ldata, rdata ); - l_wxyz = spu_rlqwbyte( ldata, 12 ); - r_wxyz = spu_rlqwbyte( rdata, 12 ); - qw = spu_nmsub( l_wxyz, r_wxyz, product ); - xy = spu_madd( l_wxyz, r_wxyz, product ); - qw = spu_sub( qw, spu_rlqwbyte( xy, 8 ) ); - result->vec128 = spu_sel( qv, qw, (vec_uint4)spu_maskb( 0x000f ) ); -} - -static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *quat, const VmathVector3 *vec ) -{ - vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; - qdata = quat->vec128; - vdata = vec->vec128; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - tmp0 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_YZXW ); - wwww = spu_shuffle( qdata, qdata, shuffle_wwww ); - qv = spu_mul( wwww, vdata ); - qv = spu_madd( tmp0, tmp1, qv ); - qv = spu_nmsub( tmp2, tmp3, qv ); - product = spu_mul( qdata, vdata ); - qw = spu_madd( spu_rlqwbyte( qdata, 4 ), spu_rlqwbyte( vdata, 4 ), product ); - qw = spu_add( spu_rlqwbyte( product, 8 ), qw ); - tmp1 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_YZXW ); - res = spu_mul( spu_shuffle( qw, qw, shuffle_xxxx ), qdata ); - res = spu_madd( wwww, qv, res ); - res = spu_madd( tmp0, tmp1, res ); - res = spu_nmsub( tmp2, tmp3, res ); - result->vec128 = res; -} - -static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ) -{ - result->vec128 = spu_xor( quat->vec128, ((vec_float4)(vec_int4){0x80000000,0x80000000,0x80000000,0}) ); -} - -static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ) -{ - result->vec128 = spu_sel( quat0->vec128, quat1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathQPrint( const VmathQuat *quat ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat->vec128; - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -static inline void vmathQPrints( const VmathQuat *quat, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat->vec128; - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_QUAT_AOS_C_H +#define _VECTORMATH_QUAT_AOS_C_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Definitions + */ +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +#endif + +static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathQMakeFromElems( VmathQuat *result, float _x, float _y, float _z, float _w ) +{ + result->vec128 = (vec_float4){ _x, _y, _z, _w }; +} + +static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float _w ) +{ + result->vec128 = spu_shuffle( xyz->vec128, spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); +} + +static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ) +{ + result->vec128 = spu_splats( scalar ); +} + +static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathQMakeIdentity( VmathQuat *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0001; +} + +static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + VmathQuat tmpQ_0, tmpQ_1; + vmathQSub( &tmpQ_0, quat1, quat0 ); + vmathQScalarMul( &tmpQ_1, &tmpQ_0, t ); + vmathQAdd( result, quat0, &tmpQ_1 ); +} + +static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ) +{ + VmathQuat start; + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot4( unitQuat0->vec128, unitQuat1->vec128 ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(0.0f), cosAngle ); + cosAngle = spu_sel( cosAngle, negatef4( cosAngle ), selectMask ); + start.vec128 = spu_sel( unitQuat0->vec128, negatef4( unitQuat0->vec128 ), selectMask ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + result->vec128 = spu_madd( start.vec128, scale0, spu_mul( unitQuat1->vec128, scale1 ) ); +} + +static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ) +{ + VmathQuat tmp0, tmp1; + vmathQSlerp( &tmp0, t, unitQuat0, unitQuat3 ); + vmathQSlerp( &tmp1, t, unitQuat1, unitQuat2 ); + vmathQSlerp( result, ( ( 2.0f * t ) * ( 1.0f - t ) ), &tmp0, &tmp1 ); +} + +static inline vec_float4 vmathQGet128( const VmathQuat *quat ) +{ + return quat->vec128; +} + +static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ) +{ + result->vec128 = spu_sel( vec->vec128, result->vec128, (vec_uint4)spu_maskb(0x000f) ); +} + +static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathQSetX( VmathQuat *result, float _x ) +{ + result->vec128 = spu_insert( _x, result->vec128, 0 ); +} + +static inline float vmathQGetX( const VmathQuat *quat ) +{ + return spu_extract( quat->vec128, 0 ); +} + +static inline void vmathQSetY( VmathQuat *result, float _y ) +{ + result->vec128 = spu_insert( _y, result->vec128, 1 ); +} + +static inline float vmathQGetY( const VmathQuat *quat ) +{ + return spu_extract( quat->vec128, 1 ); +} + +static inline void vmathQSetZ( VmathQuat *result, float _z ) +{ + result->vec128 = spu_insert( _z, result->vec128, 2 ); +} + +static inline float vmathQGetZ( const VmathQuat *quat ) +{ + return spu_extract( quat->vec128, 2 ); +} + +static inline void vmathQSetW( VmathQuat *result, float _w ) +{ + result->vec128 = spu_insert( _w, result->vec128, 3 ); +} + +static inline float vmathQGetW( const VmathQuat *quat ) +{ + return spu_extract( quat->vec128, 3 ); +} + +static inline void vmathQSetElem( VmathQuat *result, int idx, float value ) +{ + result->vec128 = spu_insert( value, result->vec128, idx ); +} + +static inline float vmathQGetElem( const VmathQuat *quat, int idx ) +{ + return spu_extract( quat->vec128, idx ); +} + +static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + result->vec128 = spu_add( quat0->vec128, quat1->vec128 ); +} + +static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + result->vec128 = spu_sub( quat0->vec128, quat1->vec128 ); +} + +static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ) +{ + result->vec128 = spu_mul( quat->vec128, spu_splats(scalar) ); +} + +static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ) +{ + result->vec128 = divf4( quat->vec128, spu_splats(scalar) ); +} + +static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = negatef4( quat->vec128 ); +} + +static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + return spu_extract( _vmathVfDot4( quat0->vec128, quat1->vec128 ), 0 ); +} + +static inline float vmathQNorm( const VmathQuat *quat ) +{ + return spu_extract( _vmathVfDot4( quat->vec128, quat->vec128 ), 0 ); +} + +static inline float vmathQLength( const VmathQuat *quat ) +{ + return sqrtf( vmathQNorm( quat ) ); +} + +static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ) +{ + vec_float4 dot = _vmathVfDot4( quat->vec128, quat->vec128 ); + result->vec128 = spu_mul( quat->vec128, rsqrtf4( dot ) ); +} + +static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) +{ + VmathVector3 crossVec, tmpV3_0; + vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; + cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = spu_shuffle( cosAngle, cosAngle, (vec_uchar16)spu_splats(0x00010203) ); + cosAngleX2Plus2 = spu_madd( cosAngle, spu_splats(2.0f), spu_splats(2.0f) ); + recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); + cosHalfAngleX2 = spu_mul( recipCosHalfAngleX2, cosAngleX2Plus2 ); + vmathV3Cross( &tmpV3_0, unitVec0, unitVec1 ); + crossVec = tmpV3_0; + res = spu_mul( crossVec.vec128, recipCosHalfAngleX2 ); + res = spu_sel( res, spu_mul( cosHalfAngleX2, spu_splats(0.5f) ), (vec_uint4)spu_maskb(0x000f) ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_mul( unitVec->vec128, s ), c, (vec_uint4)spu_maskb(0x000f) ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationX( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0xf000) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationY( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x0f00) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + result->vec128 = res; +} + +static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x00f0) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + result->vec128 = res; +} + +static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ) +{ + vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; + vec_float4 product, l_wxyz, r_wxyz, xy, qw; + ldata = quat0->vec128; + rdata = quat1->vec128; + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + tmp0 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_YZXW ); + qv = spu_mul( spu_shuffle( ldata, ldata, shuffle_wwww ), rdata ); + qv = spu_madd( spu_shuffle( rdata, rdata, shuffle_wwww ), ldata, qv ); + qv = spu_madd( tmp0, tmp1, qv ); + qv = spu_nmsub( tmp2, tmp3, qv ); + product = spu_mul( ldata, rdata ); + l_wxyz = spu_rlqwbyte( ldata, 12 ); + r_wxyz = spu_rlqwbyte( rdata, 12 ); + qw = spu_nmsub( l_wxyz, r_wxyz, product ); + xy = spu_madd( l_wxyz, r_wxyz, product ); + qw = spu_sub( qw, spu_rlqwbyte( xy, 8 ) ); + result->vec128 = spu_sel( qv, qw, (vec_uint4)spu_maskb( 0x000f ) ); +} + +static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *quat, const VmathVector3 *vec ) +{ + vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; + qdata = quat->vec128; + vdata = vec->vec128; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + tmp0 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_YZXW ); + wwww = spu_shuffle( qdata, qdata, shuffle_wwww ); + qv = spu_mul( wwww, vdata ); + qv = spu_madd( tmp0, tmp1, qv ); + qv = spu_nmsub( tmp2, tmp3, qv ); + product = spu_mul( qdata, vdata ); + qw = spu_madd( spu_rlqwbyte( qdata, 4 ), spu_rlqwbyte( vdata, 4 ), product ); + qw = spu_add( spu_rlqwbyte( product, 8 ), qw ); + tmp1 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_YZXW ); + res = spu_mul( spu_shuffle( qw, qw, shuffle_xxxx ), qdata ); + res = spu_madd( wwww, qv, res ); + res = spu_madd( tmp0, tmp1, res ); + res = spu_nmsub( tmp2, tmp3, res ); + result->vec128 = res; +} + +static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ) +{ + result->vec128 = spu_xor( quat->vec128, ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ); +} + +static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ) +{ + result->vec128 = spu_sel( quat0->vec128, quat1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathQPrint( const VmathQuat *quat ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat->vec128; + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +static inline void vmathQPrints( const VmathQuat *quat, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat->vec128; + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/spu/c/vec_aos.h b/common/vectormath/spu/c/vec_aos.h index 715f27df..332e0db9 100644 --- a/common/vectormath/spu/c/vec_aos.h +++ b/common/vectormath/spu/c/vec_aos.h @@ -1,1029 +1,1029 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VEC_AOS_C_H -#define _VECTORMATH_VEC_AOS_C_H -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/*----------------------------------------------------------------------------- - * Constants - * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - */ -#define _VECTORMATH_SHUF_X 0x00010203 -#define _VECTORMATH_SHUF_Y 0x04050607 -#define _VECTORMATH_SHUF_Z 0x08090a0b -#define _VECTORMATH_SHUF_W 0x0c0d0e0f -#define _VECTORMATH_SHUF_A 0x10111213 -#define _VECTORMATH_SHUF_B 0x14151617 -#define _VECTORMATH_SHUF_C 0x18191a1b -#define _VECTORMATH_SHUF_D 0x1c1d1e1f -#define _VECTORMATH_SHUF_0 0x80808080 -#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } -#define _VECTORMATH_SHUF_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_W } -#define _VECTORMATH_SHUF_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W } -#define _VECTORMATH_SHUF_WABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } -#define _VECTORMATH_SHUF_ZWAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } -#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } -#define _VECTORMATH_SHUF_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } -#define _VECTORMATH_SHUF_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } -#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } -#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } -#define _VECTORMATH_SLERP_TOL 0.999f - -/*----------------------------------------------------------------------------- - * Definitions - */ -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = spu_mul( vec0, vec1 ); - result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); - return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); -} - -static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = spu_mul( vec0, vec1 ); - result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); - return spu_add( spu_rlqwbyte( result, 8 ), result ); -} - -static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, result; - tmp0 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_YZXW ); - result = spu_mul( tmp0, tmp1 ); - result = spu_nmsub( tmp2, tmp3, result ); - return result; -} - -static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) -{ - vec_int4 bexp; - vec_uint4 mant, sign, hfloat; - vec_uint4 notZero, isInf; - const vec_uint4 hfloatInf = spu_splats(0x00007c00u); - const vec_uint4 mergeMant = spu_splats(0x000003ffu); - const vec_uint4 mergeSign = spu_splats(0x00008000u); - - sign = spu_rlmask((vec_uint4)v, -16); - mant = spu_rlmask((vec_uint4)v, -13); - bexp = spu_and(spu_rlmask((vec_int4)v, -23), 0xff); - - notZero = spu_cmpgt(bexp, 112); - isInf = spu_cmpgt(bexp, 142); - - bexp = spu_add(bexp, -112); - bexp = spu_sl(bexp, 10); - - hfloat = spu_sel((vec_uint4)bexp, mant, mergeMant); - hfloat = spu_sel(spu_splats(0u), hfloat, notZero); - hfloat = spu_sel(hfloat, hfloatInf, isInf); - hfloat = spu_sel(hfloat, sign, mergeSign); - - return hfloat; -} - -static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) -{ - vec_uint4 hfloat_u, hfloat_v; - const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; - hfloat_u = _vmathVfToHalfFloatsUnpacked(u); - hfloat_v = _vmathVfToHalfFloatsUnpacked(v); - return (vec_ushort8)spu_shuffle(hfloat_u, hfloat_v, pack); -} - -#endif - -static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV3MakeFromElems( VmathVector3 *result, float _x, float _y, float _z ) -{ - result->vec128 = (vec_float4){ _x, _y, _z, 0.0f }; -} - -static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = pnt->vec128; -} - -static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ) -{ - result->vec128 = spu_splats( scalar ); -} - -static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathV3MakeXAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_1000; -} - -static inline void vmathV3MakeYAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0100; -} - -static inline void vmathV3MakeZAxis( VmathVector3 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0010; -} - -static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - VmathVector3 tmpV3_0, tmpV3_1; - vmathV3Sub( &tmpV3_0, vec1, vec0 ); - vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); - vmathV3Add( result, vec0, &tmpV3_1 ); -} - -static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - result->vec128 = spu_madd( unitVec0->vec128, scale0, spu_mul( unitVec1->vec128, scale1 ) ); -} - -static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ) -{ - return vec->vec128; -} - -static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); - dstVec = spu_sel(vec->vec128, dstVec, mask); - *quad = dstVec; -} - -static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); - xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); - xyz3 = spu_rlqwbyte( zxyz, 4 ); - vec0->vec128 = xyzx; - vec1->vec128 = xyz1; - vec2->vec128 = xyz2; - vec3->vec128 = xyz3; -} - -static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = spu_shuffle( vec0->vec128, vec1->vec128, _VECTORMATH_SHUF_XYZA ); - yzxy = spu_shuffle( vec1->vec128, vec2->vec128, _VECTORMATH_SHUF_YZAB ); - zxyz = spu_shuffle( vec2->vec128, vec3->vec128, _VECTORMATH_SHUF_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - vmathV3StoreXYZArray( vec0, vec1, vec2, vec3, xyz0 ); - vmathV3StoreXYZArray( vec4, vec5, vec6, vec7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -static inline void vmathV3SetX( VmathVector3 *result, float _x ) -{ - result->vec128 = spu_insert( _x, result->vec128, 0 ); -} - -static inline float vmathV3GetX( const VmathVector3 *vec ) -{ - return spu_extract( vec->vec128, 0 ); -} - -static inline void vmathV3SetY( VmathVector3 *result, float _y ) -{ - result->vec128 = spu_insert( _y, result->vec128, 1 ); -} - -static inline float vmathV3GetY( const VmathVector3 *vec ) -{ - return spu_extract( vec->vec128, 1 ); -} - -static inline void vmathV3SetZ( VmathVector3 *result, float _z ) -{ - result->vec128 = spu_insert( _z, result->vec128, 2 ); -} - -static inline float vmathV3GetZ( const VmathVector3 *vec ) -{ - return spu_extract( vec->vec128, 2 ); -} - -static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ) -{ - result->vec128 = spu_insert( value, result->vec128, idx ); -} - -static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ) -{ - return spu_extract( vec->vec128, idx ); -} - -static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = spu_add( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = spu_sub( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt1 ) -{ - result->vec128 = spu_add( vec->vec128, pnt1->vec128 ); -} - -static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ) -{ - result->vec128 = spu_mul( vec->vec128, spu_splats(scalar) ); -} - -static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ) -{ - result->vec128 = divf4( vec->vec128, spu_splats(scalar) ); -} - -static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = negatef4( vec->vec128 ); -} - -static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = spu_mul( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = divf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = recipf4( vec->vec128 ); -} - -static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = sqrtf4( vec->vec128 ); -} - -static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = rsqrtf4( vec->vec128 ); -} - -static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ) -{ - result->vec128 = fabsf4( vec->vec128 ); -} - -static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV3MaxElem( const VmathVector3 *vec ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); - result = fmaxf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV3MinElem( const VmathVector3 *vec ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); - result = fminf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline float vmathV3Sum( const VmathVector3 *vec ) -{ - return - spu_extract( vec->vec128, 0 ) + - spu_extract( vec->vec128, 1 ) + - spu_extract( vec->vec128, 2 ); -} - -static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - return spu_extract( _vmathVfDot3( vec0->vec128, vec1->vec128 ), 0 ); -} - -static inline float vmathV3LengthSqr( const VmathVector3 *vec ) -{ - return spu_extract( _vmathVfDot3( vec->vec128, vec->vec128 ), 0 ); -} - -static inline float vmathV3Length( const VmathVector3 *vec ) -{ - return sqrtf( vmathV3LengthSqr( vec ) ); -} - -static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ) -{ - vec_float4 dot = _vmathVfDot3( vec->vec128, vec->vec128 ); - dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); - result->vec128 = spu_mul( vec->vec128, rsqrtf4( dot ) ); -} - -static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) -{ - result->vec128 = _vmathVfCross( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ) -{ - result->vec128 = spu_sel( vec0->vec128, vec1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathV3Print( const VmathVector3 *vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV4MakeFromElems( VmathVector4 *result, float _x, float _y, float _z, float _w ) -{ - result->vec128 = (vec_float4){ _x, _y, _z, _w }; -} - -static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float _w ) -{ - result->vec128 = spu_shuffle( xyz->vec128, spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); -} - -static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ) -{ - result->vec128 = spu_sel( vec->vec128, spu_splats(0.0f), (vec_uint4)spu_maskb(0x000f) ); -} - -static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = spu_sel( pnt->vec128, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); -} - -static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ) -{ - result->vec128 = quat->vec128; -} - -static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ) -{ - result->vec128 = spu_splats( scalar ); -} - -static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathV4MakeXAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_1000; -} - -static inline void vmathV4MakeYAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0100; -} - -static inline void vmathV4MakeZAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0010; -} - -static inline void vmathV4MakeWAxis( VmathVector4 *result ) -{ - result->vec128 = _VECTORMATH_UNIT_0001; -} - -static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - VmathVector4 tmpV4_0, tmpV4_1; - vmathV4Sub( &tmpV4_0, vec1, vec0 ); - vmathV4ScalarMul( &tmpV4_1, &tmpV4_0, t ); - vmathV4Add( result, vec0, &tmpV4_1 ); -} - -static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot4( unitVec0->vec128, unitVec1->vec128 ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - result->vec128 = spu_madd( unitVec0->vec128, scale0, spu_mul( unitVec1->vec128, scale1 ) ); -} - -static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ) -{ - return vec->vec128; -} - -static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ) -{ - twoQuads[0] = _vmath2VfToHalfFloats(vec0->vec128, vec1->vec128); - twoQuads[1] = _vmath2VfToHalfFloats(vec2->vec128, vec3->vec128); -} - -static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ) -{ - result->vec128 = spu_sel( vec->vec128, result->vec128, (vec_uint4)spu_maskb(0x000f) ); -} - -static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathV4SetX( VmathVector4 *result, float _x ) -{ - result->vec128 = spu_insert( _x, result->vec128, 0 ); -} - -static inline float vmathV4GetX( const VmathVector4 *vec ) -{ - return spu_extract( vec->vec128, 0 ); -} - -static inline void vmathV4SetY( VmathVector4 *result, float _y ) -{ - result->vec128 = spu_insert( _y, result->vec128, 1 ); -} - -static inline float vmathV4GetY( const VmathVector4 *vec ) -{ - return spu_extract( vec->vec128, 1 ); -} - -static inline void vmathV4SetZ( VmathVector4 *result, float _z ) -{ - result->vec128 = spu_insert( _z, result->vec128, 2 ); -} - -static inline float vmathV4GetZ( const VmathVector4 *vec ) -{ - return spu_extract( vec->vec128, 2 ); -} - -static inline void vmathV4SetW( VmathVector4 *result, float _w ) -{ - result->vec128 = spu_insert( _w, result->vec128, 3 ); -} - -static inline float vmathV4GetW( const VmathVector4 *vec ) -{ - return spu_extract( vec->vec128, 3 ); -} - -static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ) -{ - result->vec128 = spu_insert( value, result->vec128, idx ); -} - -static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ) -{ - return spu_extract( vec->vec128, idx ); -} - -static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = spu_add( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = spu_sub( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ) -{ - result->vec128 = spu_mul( vec->vec128, spu_splats(scalar) ); -} - -static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ) -{ - result->vec128 = divf4( vec->vec128, spu_splats(scalar) ); -} - -static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = negatef4( vec->vec128 ); -} - -static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = spu_mul( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = divf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = recipf4( vec->vec128 ); -} - -static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = sqrtf4( vec->vec128 ); -} - -static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = rsqrtf4( vec->vec128 ); -} - -static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ) -{ - result->vec128 = fabsf4( vec->vec128 ); -} - -static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); -} - -static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV4MaxElem( const VmathVector4 *vec ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); - result = fmaxf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); - result = fmaxf4( spu_promote( spu_extract( vec->vec128, 3 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); -} - -static inline float vmathV4MinElem( const VmathVector4 *vec ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); - result = fminf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); - result = fminf4( spu_promote( spu_extract( vec->vec128, 3 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline float vmathV4Sum( const VmathVector4 *vec ) -{ - return - spu_extract( vec->vec128, 0 ) + - spu_extract( vec->vec128, 1 ) + - spu_extract( vec->vec128, 2 ) + - spu_extract( vec->vec128, 3 ); -} - -static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ) -{ - return spu_extract( _vmathVfDot4( vec0->vec128, vec1->vec128 ), 0 ); -} - -static inline float vmathV4LengthSqr( const VmathVector4 *vec ) -{ - return spu_extract( _vmathVfDot4( vec->vec128, vec->vec128 ), 0 ); -} - -static inline float vmathV4Length( const VmathVector4 *vec ) -{ - return sqrtf( vmathV4LengthSqr( vec ) ); -} - -static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ) -{ - vec_float4 dot = _vmathVfDot4( vec->vec128, vec->vec128 ); - result->vec128 = spu_mul( vec->vec128, rsqrtf4( dot ) ); -} - -static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ) -{ - result->vec128 = spu_sel( vec0->vec128, vec1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathV4Print( const VmathVector4 *vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec->vec128; - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = pnt->vec128; -} - -static inline void vmathP3MakeFromElems( VmathPoint3 *result, float _x, float _y, float _z ) -{ - result->vec128 = (vec_float4){ _x, _y, _z, 0.0f }; -} - -static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ) -{ - result->vec128 = vec->vec128; -} - -static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ) -{ - result->vec128 = spu_splats( scalar ); -} - -static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ) -{ - result->vec128 = vf4; -} - -static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0, tmpV3_1; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); - vmathP3AddV3( result, pnt0, &tmpV3_1 ); -} - -static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ) -{ - return pnt->vec128; -} - -static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); - dstVec = spu_sel(pnt->vec128, dstVec, mask); - *quad = dstVec; -} - -static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); - xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); - xyz3 = spu_rlqwbyte( zxyz, 4 ); - pnt0->vec128 = xyzx; - pnt1->vec128 = xyz1; - pnt2->vec128 = xyz2; - pnt3->vec128 = xyz3; -} - -static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = spu_shuffle( pnt0->vec128, pnt1->vec128, _VECTORMATH_SHUF_XYZA ); - yzxy = spu_shuffle( pnt1->vec128, pnt2->vec128, _VECTORMATH_SHUF_YZAB ); - zxyz = spu_shuffle( pnt2->vec128, pnt3->vec128, _VECTORMATH_SHUF_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - vmathP3StoreXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); - vmathP3StoreXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -static inline void vmathP3SetX( VmathPoint3 *result, float _x ) -{ - result->vec128 = spu_insert( _x, result->vec128, 0 ); -} - -static inline float vmathP3GetX( const VmathPoint3 *pnt ) -{ - return spu_extract( pnt->vec128, 0 ); -} - -static inline void vmathP3SetY( VmathPoint3 *result, float _y ) -{ - result->vec128 = spu_insert( _y, result->vec128, 1 ); -} - -static inline float vmathP3GetY( const VmathPoint3 *pnt ) -{ - return spu_extract( pnt->vec128, 1 ); -} - -static inline void vmathP3SetZ( VmathPoint3 *result, float _z ) -{ - result->vec128 = spu_insert( _z, result->vec128, 2 ); -} - -static inline float vmathP3GetZ( const VmathPoint3 *pnt ) -{ - return spu_extract( pnt->vec128, 2 ); -} - -static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ) -{ - result->vec128 = spu_insert( value, result->vec128, idx ); -} - -static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ) -{ - return spu_extract( pnt->vec128, idx ); -} - -static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = spu_sub( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) -{ - result->vec128 = spu_add( pnt->vec128, vec1->vec128 ); -} - -static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) -{ - result->vec128 = spu_sub( pnt->vec128, vec1->vec128 ); -} - -static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = spu_mul( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = divf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = recipf4( pnt->vec128 ); -} - -static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = sqrtf4( pnt->vec128 ); -} - -static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = rsqrtf4( pnt->vec128 ); -} - -static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) -{ - result->vec128 = fabsf4( pnt->vec128 ); -} - -static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = copysignf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = fmaxf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline float vmathP3MaxElem( const VmathPoint3 *pnt ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( pnt->vec128, 1 ), 0 ), pnt->vec128 ); - result = fmaxf4( spu_promote( spu_extract( pnt->vec128, 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - result->vec128 = fminf4( pnt0->vec128, pnt1->vec128 ); -} - -static inline float vmathP3MinElem( const VmathPoint3 *pnt ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( pnt->vec128, 1 ), 0 ), pnt->vec128 ); - result = fminf4( spu_promote( spu_extract( pnt->vec128, 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -static inline float vmathP3Sum( const VmathPoint3 *pnt ) -{ - return - spu_extract( pnt->vec128, 0 ) + - spu_extract( pnt->vec128, 1 ) + - spu_extract( pnt->vec128, 2 ); -} - -static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ) -{ - VmathPoint3 tmpP3_0; - vmathP3MakeFromScalar( &tmpP3_0, scaleVal ); - vmathP3MulPerElem( result, pnt, &tmpP3_0 ); -} - -static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ) -{ - VmathPoint3 tmpP3_0; - vmathP3MakeFromV3( &tmpP3_0, scaleVec ); - vmathP3MulPerElem( result, pnt, &tmpP3_0 ); -} - -static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ) -{ - return spu_extract( _vmathVfDot3( pnt->vec128, unitVec->vec128 ), 0 ); -} - -static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ) -{ - VmathVector3 tmpV3_0; - vmathV3MakeFromP3( &tmpV3_0, pnt ); - return vmathV3LengthSqr( &tmpV3_0 ); -} - -static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ) -{ - VmathVector3 tmpV3_0; - vmathV3MakeFromP3( &tmpV3_0, pnt ); - return vmathV3Length( &tmpV3_0 ); -} - -static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - return vmathV3LengthSqr( &tmpV3_0 ); -} - -static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) -{ - VmathVector3 tmpV3_0; - vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); - return vmathV3Length( &tmpV3_0 ); -} - -static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ) -{ - result->vec128 = spu_sel( pnt0->vec128, pnt1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -static inline void vmathP3Print( const VmathPoint3 *pnt ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt->vec128; - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt->vec128; - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VEC_AOS_C_H +#define _VECTORMATH_VEC_AOS_C_H +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*----------------------------------------------------------------------------- + * Constants + * for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + */ +#define _VECTORMATH_SHUF_X 0x00010203 +#define _VECTORMATH_SHUF_Y 0x04050607 +#define _VECTORMATH_SHUF_Z 0x08090a0b +#define _VECTORMATH_SHUF_W 0x0c0d0e0f +#define _VECTORMATH_SHUF_A 0x10111213 +#define _VECTORMATH_SHUF_B 0x14151617 +#define _VECTORMATH_SHUF_C 0x18191a1b +#define _VECTORMATH_SHUF_D 0x1c1d1e1f +#define _VECTORMATH_SHUF_0 0x80808080 +#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } +#define _VECTORMATH_SHUF_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_W } +#define _VECTORMATH_SHUF_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W } +#define _VECTORMATH_SHUF_WABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } +#define _VECTORMATH_SHUF_ZWAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } +#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } +#define _VECTORMATH_SHUF_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } +#define _VECTORMATH_SHUF_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } +#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } +#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } +#define _VECTORMATH_SLERP_TOL 0.999f + +/*----------------------------------------------------------------------------- + * Definitions + */ +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = spu_mul( vec0, vec1 ); + result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); + return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); +} + +static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = spu_mul( vec0, vec1 ); + result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); + return spu_add( spu_rlqwbyte( result, 8 ), result ); +} + +static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, result; + tmp0 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_YZXW ); + result = spu_mul( tmp0, tmp1 ); + result = spu_nmsub( tmp2, tmp3, result ); + return result; +} + +static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) +{ + vec_int4 bexp; + vec_uint4 mant, sign, hfloat; + vec_uint4 notZero, isInf; + const vec_uint4 hfloatInf = spu_splats(0x00007c00u); + const vec_uint4 mergeMant = spu_splats(0x000003ffu); + const vec_uint4 mergeSign = spu_splats(0x00008000u); + + sign = spu_rlmask((vec_uint4)v, -16); + mant = spu_rlmask((vec_uint4)v, -13); + bexp = spu_and(spu_rlmask((vec_int4)v, -23), 0xff); + + notZero = spu_cmpgt(bexp, 112); + isInf = spu_cmpgt(bexp, 142); + + bexp = spu_add(bexp, -112); + bexp = spu_sl(bexp, 10); + + hfloat = spu_sel((vec_uint4)bexp, mant, mergeMant); + hfloat = spu_sel(spu_splats(0u), hfloat, notZero); + hfloat = spu_sel(hfloat, hfloatInf, isInf); + hfloat = spu_sel(hfloat, sign, mergeSign); + + return hfloat; +} + +static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) +{ + vec_uint4 hfloat_u, hfloat_v; + const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; + hfloat_u = _vmathVfToHalfFloatsUnpacked(u); + hfloat_v = _vmathVfToHalfFloatsUnpacked(v); + return (vec_ushort8)spu_shuffle(hfloat_u, hfloat_v, pack); +} + +#endif + +static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV3MakeFromElems( VmathVector3 *result, float _x, float _y, float _z ) +{ + result->vec128 = (vec_float4){ _x, _y, _z, 0.0f }; +} + +static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = pnt->vec128; +} + +static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ) +{ + result->vec128 = spu_splats( scalar ); +} + +static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathV3MakeXAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_1000; +} + +static inline void vmathV3MakeYAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0100; +} + +static inline void vmathV3MakeZAxis( VmathVector3 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0010; +} + +static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + VmathVector3 tmpV3_0, tmpV3_1; + vmathV3Sub( &tmpV3_0, vec1, vec0 ); + vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); + vmathV3Add( result, vec0, &tmpV3_1 ); +} + +static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot3( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + result->vec128 = spu_madd( unitVec0->vec128, scale0, spu_mul( unitVec1->vec128, scale1 ) ); +} + +static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ) +{ + return vec->vec128; +} + +static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); + dstVec = spu_sel(vec->vec128, dstVec, mask); + *quad = dstVec; +} + +static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); + xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); + xyz3 = spu_rlqwbyte( zxyz, 4 ); + vec0->vec128 = xyzx; + vec1->vec128 = xyz1; + vec2->vec128 = xyz2; + vec3->vec128 = xyz3; +} + +static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = spu_shuffle( vec0->vec128, vec1->vec128, _VECTORMATH_SHUF_XYZA ); + yzxy = spu_shuffle( vec1->vec128, vec2->vec128, _VECTORMATH_SHUF_YZAB ); + zxyz = spu_shuffle( vec2->vec128, vec3->vec128, _VECTORMATH_SHUF_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + vmathV3StoreXYZArray( vec0, vec1, vec2, vec3, xyz0 ); + vmathV3StoreXYZArray( vec4, vec5, vec6, vec7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +static inline void vmathV3SetX( VmathVector3 *result, float _x ) +{ + result->vec128 = spu_insert( _x, result->vec128, 0 ); +} + +static inline float vmathV3GetX( const VmathVector3 *vec ) +{ + return spu_extract( vec->vec128, 0 ); +} + +static inline void vmathV3SetY( VmathVector3 *result, float _y ) +{ + result->vec128 = spu_insert( _y, result->vec128, 1 ); +} + +static inline float vmathV3GetY( const VmathVector3 *vec ) +{ + return spu_extract( vec->vec128, 1 ); +} + +static inline void vmathV3SetZ( VmathVector3 *result, float _z ) +{ + result->vec128 = spu_insert( _z, result->vec128, 2 ); +} + +static inline float vmathV3GetZ( const VmathVector3 *vec ) +{ + return spu_extract( vec->vec128, 2 ); +} + +static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ) +{ + result->vec128 = spu_insert( value, result->vec128, idx ); +} + +static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ) +{ + return spu_extract( vec->vec128, idx ); +} + +static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = spu_add( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = spu_sub( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt1 ) +{ + result->vec128 = spu_add( vec->vec128, pnt1->vec128 ); +} + +static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ) +{ + result->vec128 = spu_mul( vec->vec128, spu_splats(scalar) ); +} + +static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ) +{ + result->vec128 = divf4( vec->vec128, spu_splats(scalar) ); +} + +static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = negatef4( vec->vec128 ); +} + +static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = spu_mul( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = divf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = recipf4( vec->vec128 ); +} + +static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = sqrtf4( vec->vec128 ); +} + +static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = rsqrtf4( vec->vec128 ); +} + +static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ) +{ + result->vec128 = fabsf4( vec->vec128 ); +} + +static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV3MaxElem( const VmathVector3 *vec ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); + result = fmaxf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV3MinElem( const VmathVector3 *vec ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); + result = fminf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline float vmathV3Sum( const VmathVector3 *vec ) +{ + return + spu_extract( vec->vec128, 0 ) + + spu_extract( vec->vec128, 1 ) + + spu_extract( vec->vec128, 2 ); +} + +static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + return spu_extract( _vmathVfDot3( vec0->vec128, vec1->vec128 ), 0 ); +} + +static inline float vmathV3LengthSqr( const VmathVector3 *vec ) +{ + return spu_extract( _vmathVfDot3( vec->vec128, vec->vec128 ), 0 ); +} + +static inline float vmathV3Length( const VmathVector3 *vec ) +{ + return sqrtf( vmathV3LengthSqr( vec ) ); +} + +static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ) +{ + vec_float4 dot = _vmathVfDot3( vec->vec128, vec->vec128 ); + dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); + result->vec128 = spu_mul( vec->vec128, rsqrtf4( dot ) ); +} + +static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ) +{ + result->vec128 = _vmathVfCross( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ) +{ + result->vec128 = spu_sel( vec0->vec128, vec1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathV3Print( const VmathVector3 *vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV4MakeFromElems( VmathVector4 *result, float _x, float _y, float _z, float _w ) +{ + result->vec128 = (vec_float4){ _x, _y, _z, _w }; +} + +static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float _w ) +{ + result->vec128 = spu_shuffle( xyz->vec128, spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); +} + +static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ) +{ + result->vec128 = spu_sel( vec->vec128, spu_splats(0.0f), (vec_uint4)spu_maskb(0x000f) ); +} + +static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = spu_sel( pnt->vec128, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); +} + +static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ) +{ + result->vec128 = quat->vec128; +} + +static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ) +{ + result->vec128 = spu_splats( scalar ); +} + +static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathV4MakeXAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_1000; +} + +static inline void vmathV4MakeYAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0100; +} + +static inline void vmathV4MakeZAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0010; +} + +static inline void vmathV4MakeWAxis( VmathVector4 *result ) +{ + result->vec128 = _VECTORMATH_UNIT_0001; +} + +static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + VmathVector4 tmpV4_0, tmpV4_1; + vmathV4Sub( &tmpV4_0, vec1, vec0 ); + vmathV4ScalarMul( &tmpV4_1, &tmpV4_0, t ); + vmathV4Add( result, vec0, &tmpV4_1 ); +} + +static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot4( unitVec0->vec128, unitVec1->vec128 ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + result->vec128 = spu_madd( unitVec0->vec128, scale0, spu_mul( unitVec1->vec128, scale1 ) ); +} + +static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ) +{ + return vec->vec128; +} + +static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ) +{ + twoQuads[0] = _vmath2VfToHalfFloats(vec0->vec128, vec1->vec128); + twoQuads[1] = _vmath2VfToHalfFloats(vec2->vec128, vec3->vec128); +} + +static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ) +{ + result->vec128 = spu_sel( vec->vec128, result->vec128, (vec_uint4)spu_maskb(0x000f) ); +} + +static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathV4SetX( VmathVector4 *result, float _x ) +{ + result->vec128 = spu_insert( _x, result->vec128, 0 ); +} + +static inline float vmathV4GetX( const VmathVector4 *vec ) +{ + return spu_extract( vec->vec128, 0 ); +} + +static inline void vmathV4SetY( VmathVector4 *result, float _y ) +{ + result->vec128 = spu_insert( _y, result->vec128, 1 ); +} + +static inline float vmathV4GetY( const VmathVector4 *vec ) +{ + return spu_extract( vec->vec128, 1 ); +} + +static inline void vmathV4SetZ( VmathVector4 *result, float _z ) +{ + result->vec128 = spu_insert( _z, result->vec128, 2 ); +} + +static inline float vmathV4GetZ( const VmathVector4 *vec ) +{ + return spu_extract( vec->vec128, 2 ); +} + +static inline void vmathV4SetW( VmathVector4 *result, float _w ) +{ + result->vec128 = spu_insert( _w, result->vec128, 3 ); +} + +static inline float vmathV4GetW( const VmathVector4 *vec ) +{ + return spu_extract( vec->vec128, 3 ); +} + +static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ) +{ + result->vec128 = spu_insert( value, result->vec128, idx ); +} + +static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ) +{ + return spu_extract( vec->vec128, idx ); +} + +static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = spu_add( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = spu_sub( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ) +{ + result->vec128 = spu_mul( vec->vec128, spu_splats(scalar) ); +} + +static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ) +{ + result->vec128 = divf4( vec->vec128, spu_splats(scalar) ); +} + +static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = negatef4( vec->vec128 ); +} + +static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = spu_mul( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = divf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = recipf4( vec->vec128 ); +} + +static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = sqrtf4( vec->vec128 ); +} + +static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = rsqrtf4( vec->vec128 ); +} + +static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ) +{ + result->vec128 = fabsf4( vec->vec128 ); +} + +static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = copysignf4( vec0->vec128, vec1->vec128 ); +} + +static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = fmaxf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV4MaxElem( const VmathVector4 *vec ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); + result = fmaxf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); + result = fmaxf4( spu_promote( spu_extract( vec->vec128, 3 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + result->vec128 = fminf4( vec0->vec128, vec1->vec128 ); +} + +static inline float vmathV4MinElem( const VmathVector4 *vec ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( vec->vec128, 1 ), 0 ), vec->vec128 ); + result = fminf4( spu_promote( spu_extract( vec->vec128, 2 ), 0 ), result ); + result = fminf4( spu_promote( spu_extract( vec->vec128, 3 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline float vmathV4Sum( const VmathVector4 *vec ) +{ + return + spu_extract( vec->vec128, 0 ) + + spu_extract( vec->vec128, 1 ) + + spu_extract( vec->vec128, 2 ) + + spu_extract( vec->vec128, 3 ); +} + +static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ) +{ + return spu_extract( _vmathVfDot4( vec0->vec128, vec1->vec128 ), 0 ); +} + +static inline float vmathV4LengthSqr( const VmathVector4 *vec ) +{ + return spu_extract( _vmathVfDot4( vec->vec128, vec->vec128 ), 0 ); +} + +static inline float vmathV4Length( const VmathVector4 *vec ) +{ + return sqrtf( vmathV4LengthSqr( vec ) ); +} + +static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ) +{ + vec_float4 dot = _vmathVfDot4( vec->vec128, vec->vec128 ); + result->vec128 = spu_mul( vec->vec128, rsqrtf4( dot ) ); +} + +static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ) +{ + result->vec128 = spu_sel( vec0->vec128, vec1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathV4Print( const VmathVector4 *vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec->vec128; + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = pnt->vec128; +} + +static inline void vmathP3MakeFromElems( VmathPoint3 *result, float _x, float _y, float _z ) +{ + result->vec128 = (vec_float4){ _x, _y, _z, 0.0f }; +} + +static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ) +{ + result->vec128 = vec->vec128; +} + +static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ) +{ + result->vec128 = spu_splats( scalar ); +} + +static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ) +{ + result->vec128 = vf4; +} + +static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0, tmpV3_1; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + vmathV3ScalarMul( &tmpV3_1, &tmpV3_0, t ); + vmathP3AddV3( result, pnt0, &tmpV3_1 ); +} + +static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ) +{ + return pnt->vec128; +} + +static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); + dstVec = spu_sel(pnt->vec128, dstVec, mask); + *quad = dstVec; +} + +static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); + xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); + xyz3 = spu_rlqwbyte( zxyz, 4 ); + pnt0->vec128 = xyzx; + pnt1->vec128 = xyz1; + pnt2->vec128 = xyz2; + pnt3->vec128 = xyz3; +} + +static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = spu_shuffle( pnt0->vec128, pnt1->vec128, _VECTORMATH_SHUF_XYZA ); + yzxy = spu_shuffle( pnt1->vec128, pnt2->vec128, _VECTORMATH_SHUF_YZAB ); + zxyz = spu_shuffle( pnt2->vec128, pnt3->vec128, _VECTORMATH_SHUF_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + vmathP3StoreXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); + vmathP3StoreXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +static inline void vmathP3SetX( VmathPoint3 *result, float _x ) +{ + result->vec128 = spu_insert( _x, result->vec128, 0 ); +} + +static inline float vmathP3GetX( const VmathPoint3 *pnt ) +{ + return spu_extract( pnt->vec128, 0 ); +} + +static inline void vmathP3SetY( VmathPoint3 *result, float _y ) +{ + result->vec128 = spu_insert( _y, result->vec128, 1 ); +} + +static inline float vmathP3GetY( const VmathPoint3 *pnt ) +{ + return spu_extract( pnt->vec128, 1 ); +} + +static inline void vmathP3SetZ( VmathPoint3 *result, float _z ) +{ + result->vec128 = spu_insert( _z, result->vec128, 2 ); +} + +static inline float vmathP3GetZ( const VmathPoint3 *pnt ) +{ + return spu_extract( pnt->vec128, 2 ); +} + +static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ) +{ + result->vec128 = spu_insert( value, result->vec128, idx ); +} + +static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ) +{ + return spu_extract( pnt->vec128, idx ); +} + +static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = spu_sub( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) +{ + result->vec128 = spu_add( pnt->vec128, vec1->vec128 ); +} + +static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec1 ) +{ + result->vec128 = spu_sub( pnt->vec128, vec1->vec128 ); +} + +static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = spu_mul( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = divf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = recipf4( pnt->vec128 ); +} + +static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = sqrtf4( pnt->vec128 ); +} + +static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = rsqrtf4( pnt->vec128 ); +} + +static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ) +{ + result->vec128 = fabsf4( pnt->vec128 ); +} + +static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = copysignf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = fmaxf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline float vmathP3MaxElem( const VmathPoint3 *pnt ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( pnt->vec128, 1 ), 0 ), pnt->vec128 ); + result = fmaxf4( spu_promote( spu_extract( pnt->vec128, 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + result->vec128 = fminf4( pnt0->vec128, pnt1->vec128 ); +} + +static inline float vmathP3MinElem( const VmathPoint3 *pnt ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( pnt->vec128, 1 ), 0 ), pnt->vec128 ); + result = fminf4( spu_promote( spu_extract( pnt->vec128, 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +static inline float vmathP3Sum( const VmathPoint3 *pnt ) +{ + return + spu_extract( pnt->vec128, 0 ) + + spu_extract( pnt->vec128, 1 ) + + spu_extract( pnt->vec128, 2 ); +} + +static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ) +{ + VmathPoint3 tmpP3_0; + vmathP3MakeFromScalar( &tmpP3_0, scaleVal ); + vmathP3MulPerElem( result, pnt, &tmpP3_0 ); +} + +static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ) +{ + VmathPoint3 tmpP3_0; + vmathP3MakeFromV3( &tmpP3_0, scaleVec ); + vmathP3MulPerElem( result, pnt, &tmpP3_0 ); +} + +static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ) +{ + return spu_extract( _vmathVfDot3( pnt->vec128, unitVec->vec128 ), 0 ); +} + +static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ) +{ + VmathVector3 tmpV3_0; + vmathV3MakeFromP3( &tmpV3_0, pnt ); + return vmathV3LengthSqr( &tmpV3_0 ); +} + +static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ) +{ + VmathVector3 tmpV3_0; + vmathV3MakeFromP3( &tmpV3_0, pnt ); + return vmathV3Length( &tmpV3_0 ); +} + +static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + return vmathV3LengthSqr( &tmpV3_0 ); +} + +static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ) +{ + VmathVector3 tmpV3_0; + vmathP3Sub( &tmpV3_0, pnt1, pnt0 ); + return vmathV3Length( &tmpV3_0 ); +} + +static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ) +{ + result->vec128 = spu_sel( pnt0->vec128, pnt1->vec128, spu_splats( (unsigned int)-(select1 > 0) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +static inline void vmathP3Print( const VmathPoint3 *pnt ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt->vec128; + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt->vec128; + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif diff --git a/common/vectormath/spu/c/vectormath_aos.h b/common/vectormath/spu/c/vectormath_aos.h index 3bd4e0fe..5fa9950e 100644 --- a/common/vectormath/spu/c/vectormath_aos.h +++ b/common/vectormath/spu/c/vectormath_aos.h @@ -1,1951 +1,1951 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_AOS_C_SPU_H -#define _VECTORMATH_AOS_C_SPU_H - -#include -#include -#include - -#ifdef _VECTORMATH_DEBUG -#endif - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef _VECTORMATH_AOS_C_TYPES_H -#define _VECTORMATH_AOS_C_TYPES_H - -/* A 3-D vector in array-of-structures format - */ -typedef struct _VmathVector3 -{ - vec_float4 vec128; -} VmathVector3; - -/* A 4-D vector in array-of-structures format - */ -typedef struct _VmathVector4 -{ - vec_float4 vec128; -} VmathVector4; - -/* A 3-D point in array-of-structures format - */ -typedef struct _VmathPoint3 -{ - vec_float4 vec128; -} VmathPoint3; - -/* A quaternion in array-of-structures format - */ -typedef struct _VmathQuat -{ - vec_float4 vec128; -} VmathQuat; - -/* A 3x3 matrix in array-of-structures format - */ -typedef struct _VmathMatrix3 -{ - VmathVector3 col0; - VmathVector3 col1; - VmathVector3 col2; -} VmathMatrix3; - -/* A 4x4 matrix in array-of-structures format - */ -typedef struct _VmathMatrix4 -{ - VmathVector4 col0; - VmathVector4 col1; - VmathVector4 col2; - VmathVector4 col3; -} VmathMatrix4; - -/* A 3x4 transformation matrix in array-of-structures format - */ -typedef struct _VmathTransform3 -{ - VmathVector3 col0; - VmathVector3 col1; - VmathVector3 col2; - VmathVector3 col3; -} VmathTransform3; - -#endif - -/* - * Copy a 3-D vector - */ -static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Construct a 3-D vector from x, y, and z elements - */ -static inline void vmathV3MakeFromElems( VmathVector3 *result, float x, float y, float z ); - -/* - * Copy elements from a 3-D point into a 3-D vector - */ -static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ); - -/* - * Set all elements of a 3-D vector to the same scalar value - */ -static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ); - -/* - * Set vector float data in a 3-D vector - */ -static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 3-D vector - */ -static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ); - -/* - * Set the x element of a 3-D vector - */ -static inline void vmathV3SetX( VmathVector3 *result, float x ); - -/* - * Set the y element of a 3-D vector - */ -static inline void vmathV3SetY( VmathVector3 *result, float y ); - -/* - * Set the z element of a 3-D vector - */ -static inline void vmathV3SetZ( VmathVector3 *result, float z ); - -/* - * Get the x element of a 3-D vector - */ -static inline float vmathV3GetX( const VmathVector3 *vec ); - -/* - * Get the y element of a 3-D vector - */ -static inline float vmathV3GetY( const VmathVector3 *vec ); - -/* - * Get the z element of a 3-D vector - */ -static inline float vmathV3GetZ( const VmathVector3 *vec ); - -/* - * Set an x, y, or z element of a 3-D vector by index - */ -static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ); - -/* - * Get an x, y, or z element of a 3-D vector by index - */ -static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ); - -/* - * Add two 3-D vectors - */ -static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Subtract a 3-D vector from another 3-D vector - */ -static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Add a 3-D vector to a 3-D point - */ -static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt ); - -/* - * Multiply a 3-D vector by a scalar - */ -static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ); - -/* - * Divide a 3-D vector by a scalar - */ -static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ); - -/* - * Negate all elements of a 3-D vector - */ -static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Construct x axis - */ -static inline void vmathV3MakeXAxis( VmathVector3 *result ); - -/* - * Construct y axis - */ -static inline void vmathV3MakeYAxis( VmathVector3 *result ); - -/* - * Construct z axis - */ -static inline void vmathV3MakeZAxis( VmathVector3 *result ); - -/* - * Multiply two 3-D vectors per element - */ -static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Divide two 3-D vectors per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Compute the reciprocal of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the square root of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the reciprocal square root of a 3-D vector per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute the absolute value of a 3-D vector per element - */ -static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Copy sign from one 3-D vector to another, per element - */ -static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Maximum of two 3-D vectors per element - */ -static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Minimum of two 3-D vectors per element - */ -static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Maximum element of a 3-D vector - */ -static inline float vmathV3MaxElem( const VmathVector3 *vec ); - -/* - * Minimum element of a 3-D vector - */ -static inline float vmathV3MinElem( const VmathVector3 *vec ); - -/* - * Compute the sum of all elements of a 3-D vector - */ -static inline float vmathV3Sum( const VmathVector3 *vec ); - -/* - * Compute the dot product of two 3-D vectors - */ -static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Compute the square of the length of a 3-D vector - */ -static inline float vmathV3LengthSqr( const VmathVector3 *vec ); - -/* - * Compute the length of a 3-D vector - */ -static inline float vmathV3Length( const VmathVector3 *vec ); - -/* - * Normalize a 3-D vector - * NOTE: - * The result is unpredictable when all elements of vec are at or near zero. - */ -static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ); - -/* - * Compute cross product of two 3-D vectors - */ -static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Outer product of two 3-D vectors - */ -static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Pre-multiply a row vector by a 3x3 matrix - * NOTE: - * Slower than column post-multiply. - */ -static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); - -/* - * Cross-product matrix of a 3-D vector - */ -static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ); - -/* - * Create cross-product matrix and multiply - * NOTE: - * Faster than separately creating a cross-product matrix and multiplying. - */ -static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); - -/* - * Linear interpolation between two 3-D vectors - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ); - -/* - * Spherical linear interpolation between two 3-D vectors - * NOTE: - * The result is unpredictable if the vectors point in opposite directions. - * Does not clamp t between 0 and 1. - */ -static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); - -/* - * Conditionally select between two 3-D vectors - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ); - -/* - * Store x, y, and z elements of a 3-D vector in the first three words of a quadword. - * The value of the fourth word (the word with the highest address) remains unchanged - */ -static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ); - -/* - * Load four three-float 3-D vectors, stored in three quadwords - */ -static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ); - -/* - * Store four 3-D vectors in three quadwords - */ -static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ); - -/* - * Store eight 3-D vectors as half-floats - */ -static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3-D vector - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV3Print( const VmathVector3 *vec ); - -/* - * Print a 3-D vector and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ); - -#endif - -/* - * Copy a 4-D vector - */ -static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Construct a 4-D vector from x, y, z, and w elements - */ -static inline void vmathV4MakeFromElems( VmathVector4 *result, float x, float y, float z, float w ); - -/* - * Construct a 4-D vector from a 3-D vector and a scalar - */ -static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float w ); - -/* - * Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 - */ -static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ); - -/* - * Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 - */ -static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ); - -/* - * Copy elements from a quaternion into a 4-D vector - */ -static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ); - -/* - * Set all elements of a 4-D vector to the same scalar value - */ -static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ); - -/* - * Set vector float data in a 4-D vector - */ -static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 4-D vector - */ -static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ); - -/* - * Set the x, y, and z elements of a 4-D vector - * NOTE: - * This function does not change the w element. - */ -static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ); - -/* - * Get the x, y, and z elements of a 4-D vector - */ -static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ); - -/* - * Set the x element of a 4-D vector - */ -static inline void vmathV4SetX( VmathVector4 *result, float x ); - -/* - * Set the y element of a 4-D vector - */ -static inline void vmathV4SetY( VmathVector4 *result, float y ); - -/* - * Set the z element of a 4-D vector - */ -static inline void vmathV4SetZ( VmathVector4 *result, float z ); - -/* - * Set the w element of a 4-D vector - */ -static inline void vmathV4SetW( VmathVector4 *result, float w ); - -/* - * Get the x element of a 4-D vector - */ -static inline float vmathV4GetX( const VmathVector4 *vec ); - -/* - * Get the y element of a 4-D vector - */ -static inline float vmathV4GetY( const VmathVector4 *vec ); - -/* - * Get the z element of a 4-D vector - */ -static inline float vmathV4GetZ( const VmathVector4 *vec ); - -/* - * Get the w element of a 4-D vector - */ -static inline float vmathV4GetW( const VmathVector4 *vec ); - -/* - * Set an x, y, z, or w element of a 4-D vector by index - */ -static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ); - -/* - * Get an x, y, z, or w element of a 4-D vector by index - */ -static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ); - -/* - * Add two 4-D vectors - */ -static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Subtract a 4-D vector from another 4-D vector - */ -static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Multiply a 4-D vector by a scalar - */ -static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ); - -/* - * Divide a 4-D vector by a scalar - */ -static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ); - -/* - * Negate all elements of a 4-D vector - */ -static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Construct x axis - */ -static inline void vmathV4MakeXAxis( VmathVector4 *result ); - -/* - * Construct y axis - */ -static inline void vmathV4MakeYAxis( VmathVector4 *result ); - -/* - * Construct z axis - */ -static inline void vmathV4MakeZAxis( VmathVector4 *result ); - -/* - * Construct w axis - */ -static inline void vmathV4MakeWAxis( VmathVector4 *result ); - -/* - * Multiply two 4-D vectors per element - */ -static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Divide two 4-D vectors per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Compute the reciprocal of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the square root of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the reciprocal square root of a 4-D vector per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Compute the absolute value of a 4-D vector per element - */ -static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Copy sign from one 4-D vector to another, per element - */ -static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Maximum of two 4-D vectors per element - */ -static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Minimum of two 4-D vectors per element - */ -static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Maximum element of a 4-D vector - */ -static inline float vmathV4MaxElem( const VmathVector4 *vec ); - -/* - * Minimum element of a 4-D vector - */ -static inline float vmathV4MinElem( const VmathVector4 *vec ); - -/* - * Compute the sum of all elements of a 4-D vector - */ -static inline float vmathV4Sum( const VmathVector4 *vec ); - -/* - * Compute the dot product of two 4-D vectors - */ -static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Compute the square of the length of a 4-D vector - */ -static inline float vmathV4LengthSqr( const VmathVector4 *vec ); - -/* - * Compute the length of a 4-D vector - */ -static inline float vmathV4Length( const VmathVector4 *vec ); - -/* - * Normalize a 4-D vector - * NOTE: - * The result is unpredictable when all elements of vec are at or near zero. - */ -static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ); - -/* - * Outer product of two 4-D vectors - */ -static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Linear interpolation between two 4-D vectors - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ); - -/* - * Spherical linear interpolation between two 4-D vectors - * NOTE: - * The result is unpredictable if the vectors point in opposite directions. - * Does not clamp t between 0 and 1. - */ -static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ); - -/* - * Conditionally select between two 4-D vectors - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ); - -/* - * Store four 4-D vectors as half-floats - */ -static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 4-D vector - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV4Print( const VmathVector4 *vec ); - -/* - * Print a 4-D vector and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ); - -#endif - -/* - * Copy a 3-D point - */ -static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Construct a 3-D point from x, y, and z elements - */ -static inline void vmathP3MakeFromElems( VmathPoint3 *result, float x, float y, float z ); - -/* - * Copy elements from a 3-D vector into a 3-D point - */ -static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ); - -/* - * Set all elements of a 3-D point to the same scalar value - */ -static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ); - -/* - * Set vector float data in a 3-D point - */ -static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ); - -/* - * Get vector float data from a 3-D point - */ -static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ); - -/* - * Set the x element of a 3-D point - */ -static inline void vmathP3SetX( VmathPoint3 *result, float x ); - -/* - * Set the y element of a 3-D point - */ -static inline void vmathP3SetY( VmathPoint3 *result, float y ); - -/* - * Set the z element of a 3-D point - */ -static inline void vmathP3SetZ( VmathPoint3 *result, float z ); - -/* - * Get the x element of a 3-D point - */ -static inline float vmathP3GetX( const VmathPoint3 *pnt ); - -/* - * Get the y element of a 3-D point - */ -static inline float vmathP3GetY( const VmathPoint3 *pnt ); - -/* - * Get the z element of a 3-D point - */ -static inline float vmathP3GetZ( const VmathPoint3 *pnt ); - -/* - * Set an x, y, or z element of a 3-D point by index - */ -static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ); - -/* - * Get an x, y, or z element of a 3-D point by index - */ -static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ); - -/* - * Subtract a 3-D point from another 3-D point - */ -static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Add a 3-D point to a 3-D vector - */ -static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); - -/* - * Subtract a 3-D vector from a 3-D point - */ -static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); - -/* - * Multiply two 3-D points per element - */ -static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Divide two 3-D points per element - * NOTE: - * Floating-point behavior matches standard library function divf4. - */ -static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Compute the reciprocal of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function recipf4. - */ -static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the square root of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function sqrtf4. - */ -static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the reciprocal square root of a 3-D point per element - * NOTE: - * Floating-point behavior matches standard library function rsqrtf4. - */ -static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Compute the absolute value of a 3-D point per element - */ -static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); - -/* - * Copy sign from one 3-D point to another, per element - */ -static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Maximum of two 3-D points per element - */ -static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Minimum of two 3-D points per element - */ -static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Maximum element of a 3-D point - */ -static inline float vmathP3MaxElem( const VmathPoint3 *pnt ); - -/* - * Minimum element of a 3-D point - */ -static inline float vmathP3MinElem( const VmathPoint3 *pnt ); - -/* - * Compute the sum of all elements of a 3-D point - */ -static inline float vmathP3Sum( const VmathPoint3 *pnt ); - -/* - * Apply uniform scale to a 3-D point - */ -static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ); - -/* - * Apply non-uniform scale to a 3-D point - */ -static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ); - -/* - * Scalar projection of a 3-D point on a unit-length 3-D vector - */ -static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ); - -/* - * Compute the square of the distance of a 3-D point from the coordinate-system origin - */ -static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ); - -/* - * Compute the distance of a 3-D point from the coordinate-system origin - */ -static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ); - -/* - * Compute the square of the distance between two 3-D points - */ -static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Compute the distance between two 3-D points - */ -static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Linear interpolation between two 3-D points - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); - -/* - * Conditionally select between two 3-D points - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ); - -/* - * Store x, y, and z elements of a 3-D point in the first three words of a quadword. - * The value of the fourth word (the word with the highest address) remains unchanged - */ -static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ); - -/* - * Load four three-float 3-D points, stored in three quadwords - */ -static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ); - -/* - * Store four 3-D points in three quadwords - */ -static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ); - -/* - * Store eight 3-D points as half-floats - */ -static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3-D point - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathP3Print( const VmathPoint3 *pnt ); - -/* - * Print a 3-D point and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ); - -#endif - -/* - * Copy a quaternion - */ -static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ); - -/* - * Construct a quaternion from x, y, z, and w elements - */ -static inline void vmathQMakeFromElems( VmathQuat *result, float x, float y, float z, float w ); - -/* - * Construct a quaternion from a 3-D vector and a scalar - */ -static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float w ); - -/* - * Copy elements from a 4-D vector into a quaternion - */ -static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ); - -/* - * Convert a rotation matrix to a unit-length quaternion - */ -static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *rotMat ); - -/* - * Set all elements of a quaternion to the same scalar value - */ -static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ); - -/* - * Set vector float data in a quaternion - */ -static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ); - -/* - * Get vector float data from a quaternion - */ -static inline vec_float4 vmathQGet128( const VmathQuat *quat ); - -/* - * Set the x, y, and z elements of a quaternion - * NOTE: - * This function does not change the w element. - */ -static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ); - -/* - * Get the x, y, and z elements of a quaternion - */ -static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ); - -/* - * Set the x element of a quaternion - */ -static inline void vmathQSetX( VmathQuat *result, float x ); - -/* - * Set the y element of a quaternion - */ -static inline void vmathQSetY( VmathQuat *result, float y ); - -/* - * Set the z element of a quaternion - */ -static inline void vmathQSetZ( VmathQuat *result, float z ); - -/* - * Set the w element of a quaternion - */ -static inline void vmathQSetW( VmathQuat *result, float w ); - -/* - * Get the x element of a quaternion - */ -static inline float vmathQGetX( const VmathQuat *quat ); - -/* - * Get the y element of a quaternion - */ -static inline float vmathQGetY( const VmathQuat *quat ); - -/* - * Get the z element of a quaternion - */ -static inline float vmathQGetZ( const VmathQuat *quat ); - -/* - * Get the w element of a quaternion - */ -static inline float vmathQGetW( const VmathQuat *quat ); - -/* - * Set an x, y, z, or w element of a quaternion by index - */ -static inline void vmathQSetElem( VmathQuat *result, int idx, float value ); - -/* - * Get an x, y, z, or w element of a quaternion by index - */ -static inline float vmathQGetElem( const VmathQuat *quat, int idx ); - -/* - * Add two quaternions - */ -static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Subtract a quaternion from another quaternion - */ -static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Multiply two quaternions - */ -static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Multiply a quaternion by a scalar - */ -static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ); - -/* - * Divide a quaternion by a scalar - */ -static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ); - -/* - * Negate all elements of a quaternion - */ -static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ); - -/* - * Construct an identity quaternion - */ -static inline void vmathQMakeIdentity( VmathQuat *result ); - -/* - * Construct a quaternion to rotate between two unit-length 3-D vectors - * NOTE: - * The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. - */ -static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); - -/* - * Construct a quaternion to rotate around a unit-length 3-D vector - */ -static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a quaternion to rotate around the x axis - */ -static inline void vmathQMakeRotationX( VmathQuat *result, float radians ); - -/* - * Construct a quaternion to rotate around the y axis - */ -static inline void vmathQMakeRotationY( VmathQuat *result, float radians ); - -/* - * Construct a quaternion to rotate around the z axis - */ -static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ); - -/* - * Compute the conjugate of a quaternion - */ -static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ); - -/* - * Use a unit-length quaternion to rotate a 3-D vector - */ -static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *unitQuat, const VmathVector3 *vec ); - -/* - * Compute the dot product of two quaternions - */ -static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Compute the norm of a quaternion - */ -static inline float vmathQNorm( const VmathQuat *quat ); - -/* - * Compute the length of a quaternion - */ -static inline float vmathQLength( const VmathQuat *quat ); - -/* - * Normalize a quaternion - * NOTE: - * The result is unpredictable when all elements of quat are at or near zero. - */ -static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ); - -/* - * Linear interpolation between two quaternions - * NOTE: - * Does not clamp t between 0 and 1. - */ -static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ); - -/* - * Spherical linear interpolation between two quaternions - * NOTE: - * Interpolates along the shortest path between orientations. - * Does not clamp t between 0 and 1. - */ -static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ); - -/* - * Spherical quadrangle interpolation - */ -static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ); - -/* - * Conditionally select between two quaternions - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a quaternion - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathQPrint( const VmathQuat *quat ); - -/* - * Print a quaternion and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathQPrints( const VmathQuat *quat, const char *name ); - -#endif - -/* - * Copy a 3x3 matrix - */ -static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Construct a 3x3 matrix containing the specified columns - */ -static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2 ); - -/* - * Construct a 3x3 rotation matrix from a unit-length quaternion - */ -static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); - -/* - * Set all elements of a 3x3 matrix to the same scalar value - */ -static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ); - -/* - * Set column 0 of a 3x3 matrix - */ -static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *col0 ); - -/* - * Set column 1 of a 3x3 matrix - */ -static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *col1 ); - -/* - * Set column 2 of a 3x3 matrix - */ -static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *col2 ); - -/* - * Get column 0 of a 3x3 matrix - */ -static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Get column 1 of a 3x3 matrix - */ -static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Get column 2 of a 3x3 matrix - */ -static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ); - -/* - * Set the column of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ); - -/* - * Set the row of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ); - -/* - * Get the column of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ); - -/* - * Get the row of a 3x3 matrix referred to by the specified index - */ -static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ); - -/* - * Set the element of a 3x3 matrix referred to by column and row indices - */ -static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ); - -/* - * Get the element of a 3x3 matrix referred to by column and row indices - */ -static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ); - -/* - * Add two 3x3 matrices - */ -static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Subtract a 3x3 matrix from another 3x3 matrix - */ -static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Negate all elements of a 3x3 matrix - */ -static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Multiply a 3x3 matrix by a scalar - */ -static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ); - -/* - * Multiply a 3x3 matrix by a 3-D vector - */ -static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ); - -/* - * Multiply two 3x3 matrices - */ -static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Construct an identity 3x3 matrix - */ -static inline void vmathM3MakeIdentity( VmathMatrix3 *result ); - -/* - * Construct a 3x3 matrix to rotate around the x axis - */ -static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the y axis - */ -static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the z axis - */ -static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ); - -/* - * Construct a 3x3 matrix to rotate around the x, y, and z axes - */ -static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 3x3 matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 3x3 matrix to perform scaling - */ -static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ); - -/* - * Append (post-multiply) a scale transformation to a 3x3 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 3x3 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ); - -/* - * Multiply two 3x3 matrices per element - */ -static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); - -/* - * Compute the absolute value of a 3x3 matrix per element - */ -static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Transpose of a 3x3 matrix - */ -static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Compute the inverse of a 3x3 matrix - * NOTE: - * Result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ); - -/* - * Determinant of a 3x3 matrix - */ -static inline float vmathM3Determinant( const VmathMatrix3 *mat ); - -/* - * Conditionally select between two 3x3 matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3x3 matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM3Print( const VmathMatrix3 *mat ); - -/* - * Print a 3x3 matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ); - -#endif - -/* - * Copy a 4x4 matrix - */ -static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Construct a 4x4 matrix containing the specified columns - */ -static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *col0, const VmathVector4 *col1, const VmathVector4 *col2, const VmathVector4 *col3 ); - -/* - * Construct a 4x4 matrix from a 3x4 transformation matrix - */ -static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ); - -/* - * Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector - */ -static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ); - -/* - * Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector - */ -static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); - -/* - * Set all elements of a 4x4 matrix to the same scalar value - */ -static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ); - -/* - * Set the upper-left 3x3 submatrix - * NOTE: - * This function does not change the bottom row elements. - */ -static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ); - -/* - * Get the upper-left 3x3 submatrix of a 4x4 matrix - */ -static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ); - -/* - * Set translation component - * NOTE: - * This function does not change the bottom row elements. - */ -static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); - -/* - * Get the translation component of a 4x4 matrix - */ -static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ); - -/* - * Set column 0 of a 4x4 matrix - */ -static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *col0 ); - -/* - * Set column 1 of a 4x4 matrix - */ -static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *col1 ); - -/* - * Set column 2 of a 4x4 matrix - */ -static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *col2 ); - -/* - * Set column 3 of a 4x4 matrix - */ -static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *col3 ); - -/* - * Get column 0 of a 4x4 matrix - */ -static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 1 of a 4x4 matrix - */ -static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 2 of a 4x4 matrix - */ -static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Get column 3 of a 4x4 matrix - */ -static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ); - -/* - * Set the column of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ); - -/* - * Set the row of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ); - -/* - * Get the column of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ); - -/* - * Get the row of a 4x4 matrix referred to by the specified index - */ -static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ); - -/* - * Set the element of a 4x4 matrix referred to by column and row indices - */ -static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ); - -/* - * Get the element of a 4x4 matrix referred to by column and row indices - */ -static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ); - -/* - * Add two 4x4 matrices - */ -static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Subtract a 4x4 matrix from another 4x4 matrix - */ -static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Negate all elements of a 4x4 matrix - */ -static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Multiply a 4x4 matrix by a scalar - */ -static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ); - -/* - * Multiply a 4x4 matrix by a 4-D vector - */ -static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ); - -/* - * Multiply a 4x4 matrix by a 3-D vector - */ -static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ); - -/* - * Multiply a 4x4 matrix by a 3-D point - */ -static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ); - -/* - * Multiply two 4x4 matrices - */ -static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Multiply a 4x4 matrix by a 3x4 transformation matrix - */ -static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm ); - -/* - * Construct an identity 4x4 matrix - */ -static inline void vmathM4MakeIdentity( VmathMatrix4 *result ); - -/* - * Construct a 4x4 matrix to rotate around the x axis - */ -static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the y axis - */ -static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the z axis - */ -static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ); - -/* - * Construct a 4x4 matrix to rotate around the x, y, and z axes - */ -static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 4x4 matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 4x4 matrix to perform scaling - */ -static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ); - -/* - * Construct a 4x4 matrix to perform translation - */ -static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); - -/* - * Construct viewing matrix based on eye position, position looked at, and up direction - */ -static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ); - -/* - * Construct a perspective projection matrix - */ -static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ); - -/* - * Construct a perspective projection matrix based on frustum - */ -static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); - -/* - * Construct an orthographic projection matrix - */ -static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); - -/* - * Append (post-multiply) a scale transformation to a 4x4 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 4x4 matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ); - -/* - * Multiply two 4x4 matrices per element - */ -static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); - -/* - * Compute the absolute value of a 4x4 matrix per element - */ -static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Transpose of a 4x4 matrix - */ -static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix - * NOTE: - * Result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. - */ -static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. - */ -static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); - -/* - * Determinant of a 4x4 matrix - */ -static inline float vmathM4Determinant( const VmathMatrix4 *mat ); - -/* - * Conditionally select between two 4x4 matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 4x4 matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM4Print( const VmathMatrix4 *mat ); - -/* - * Print a 4x4 matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ); - -#endif - -/* - * Copy a 3x4 transformation matrix - */ -static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Construct a 3x4 transformation matrix containing the specified columns - */ -static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2, const VmathVector3 *col3 ); - -/* - * Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector - */ -static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ); - -/* - * Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector - */ -static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); - -/* - * Set all elements of a 3x4 transformation matrix to the same scalar value - */ -static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ); - -/* - * Set the upper-left 3x3 submatrix - */ -static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *mat3 ); - -/* - * Get the upper-left 3x3 submatrix of a 3x4 transformation matrix - */ -static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ); - -/* - * Set translation component - */ -static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); - -/* - * Get the translation component of a 3x4 transformation matrix - */ -static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Set column 0 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *col0 ); - -/* - * Set column 1 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *col1 ); - -/* - * Set column 2 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *col2 ); - -/* - * Set column 3 of a 3x4 transformation matrix - */ -static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *col3 ); - -/* - * Get column 0 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 1 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 2 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Get column 3 of a 3x4 transformation matrix - */ -static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ); - -/* - * Set the column of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ); - -/* - * Set the row of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ); - -/* - * Get the column of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ); - -/* - * Get the row of a 3x4 transformation matrix referred to by the specified index - */ -static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ); - -/* - * Set the element of a 3x4 transformation matrix referred to by column and row indices - */ -static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ); - -/* - * Get the element of a 3x4 transformation matrix referred to by column and row indices - */ -static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ); - -/* - * Multiply a 3x4 transformation matrix by a 3-D vector - */ -static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ); - -/* - * Multiply a 3x4 transformation matrix by a 3-D point - */ -static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ); - -/* - * Multiply two 3x4 transformation matrices - */ -static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); - -/* - * Construct an identity 3x4 transformation matrix - */ -static inline void vmathT3MakeIdentity( VmathTransform3 *result ); - -/* - * Construct a 3x4 transformation matrix to rotate around the x axis - */ -static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the y axis - */ -static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the z axis - */ -static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ); - -/* - * Construct a 3x4 transformation matrix to rotate around the x, y, and z axes - */ -static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ); - -/* - * Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector - */ -static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ); - -/* - * Construct a rotation matrix from a unit-length quaternion - */ -static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ); - -/* - * Construct a 3x4 transformation matrix to perform scaling - */ -static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ); - -/* - * Construct a 3x4 transformation matrix to perform translation - */ -static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); - -/* - * Append (post-multiply) a scale transformation to a 3x4 transformation matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ); - -/* - * Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix - * NOTE: - * Faster than creating and multiplying a scale transformation matrix. - */ -static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ); - -/* - * Multiply two 3x4 transformation matrices per element - */ -static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); - -/* - * Compute the absolute value of a 3x4 transformation matrix per element - */ -static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Inverse of a 3x4 transformation matrix - * NOTE: - * Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. - */ -static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix - * NOTE: - * This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. - */ -static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); - -/* - * Conditionally select between two 3x4 transformation matrices - * NOTE: - * This function uses a conditional select instruction to avoid a branch. - */ -static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ); - -#ifdef _VECTORMATH_DEBUG - -/* - * Print a 3x4 transformation matrix - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathT3Print( const VmathTransform3 *tfrm ); - -/* - * Print a 3x4 transformation matrix and an associated string identifier - * NOTE: - * Function is only defined when _VECTORMATH_DEBUG is defined. - */ -static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ); - -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#include "vec_aos.h" -#include "quat_aos.h" -#include "mat_aos.h" - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_AOS_C_SPU_H +#define _VECTORMATH_AOS_C_SPU_H + +#include +#include +#include + +#ifdef _VECTORMATH_DEBUG +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef _VECTORMATH_AOS_C_TYPES_H +#define _VECTORMATH_AOS_C_TYPES_H + +/* A 3-D vector in array-of-structures format + */ +typedef struct _VmathVector3 +{ + vec_float4 vec128; +} VmathVector3; + +/* A 4-D vector in array-of-structures format + */ +typedef struct _VmathVector4 +{ + vec_float4 vec128; +} VmathVector4; + +/* A 3-D point in array-of-structures format + */ +typedef struct _VmathPoint3 +{ + vec_float4 vec128; +} VmathPoint3; + +/* A quaternion in array-of-structures format + */ +typedef struct _VmathQuat +{ + vec_float4 vec128; +} VmathQuat; + +/* A 3x3 matrix in array-of-structures format + */ +typedef struct _VmathMatrix3 +{ + VmathVector3 col0; + VmathVector3 col1; + VmathVector3 col2; +} VmathMatrix3; + +/* A 4x4 matrix in array-of-structures format + */ +typedef struct _VmathMatrix4 +{ + VmathVector4 col0; + VmathVector4 col1; + VmathVector4 col2; + VmathVector4 col3; +} VmathMatrix4; + +/* A 3x4 transformation matrix in array-of-structures format + */ +typedef struct _VmathTransform3 +{ + VmathVector3 col0; + VmathVector3 col1; + VmathVector3 col2; + VmathVector3 col3; +} VmathTransform3; + +#endif + +/* + * Copy a 3-D vector + */ +static inline void vmathV3Copy( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Construct a 3-D vector from x, y, and z elements + */ +static inline void vmathV3MakeFromElems( VmathVector3 *result, float x, float y, float z ); + +/* + * Copy elements from a 3-D point into a 3-D vector + */ +static inline void vmathV3MakeFromP3( VmathVector3 *result, const VmathPoint3 *pnt ); + +/* + * Set all elements of a 3-D vector to the same scalar value + */ +static inline void vmathV3MakeFromScalar( VmathVector3 *result, float scalar ); + +/* + * Set vector float data in a 3-D vector + */ +static inline void vmathV3MakeFrom128( VmathVector3 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 3-D vector + */ +static inline vec_float4 vmathV3Get128( const VmathVector3 *vec ); + +/* + * Set the x element of a 3-D vector + */ +static inline void vmathV3SetX( VmathVector3 *result, float x ); + +/* + * Set the y element of a 3-D vector + */ +static inline void vmathV3SetY( VmathVector3 *result, float y ); + +/* + * Set the z element of a 3-D vector + */ +static inline void vmathV3SetZ( VmathVector3 *result, float z ); + +/* + * Get the x element of a 3-D vector + */ +static inline float vmathV3GetX( const VmathVector3 *vec ); + +/* + * Get the y element of a 3-D vector + */ +static inline float vmathV3GetY( const VmathVector3 *vec ); + +/* + * Get the z element of a 3-D vector + */ +static inline float vmathV3GetZ( const VmathVector3 *vec ); + +/* + * Set an x, y, or z element of a 3-D vector by index + */ +static inline void vmathV3SetElem( VmathVector3 *result, int idx, float value ); + +/* + * Get an x, y, or z element of a 3-D vector by index + */ +static inline float vmathV3GetElem( const VmathVector3 *vec, int idx ); + +/* + * Add two 3-D vectors + */ +static inline void vmathV3Add( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Subtract a 3-D vector from another 3-D vector + */ +static inline void vmathV3Sub( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Add a 3-D vector to a 3-D point + */ +static inline void vmathV3AddP3( VmathPoint3 *result, const VmathVector3 *vec, const VmathPoint3 *pnt ); + +/* + * Multiply a 3-D vector by a scalar + */ +static inline void vmathV3ScalarMul( VmathVector3 *result, const VmathVector3 *vec, float scalar ); + +/* + * Divide a 3-D vector by a scalar + */ +static inline void vmathV3ScalarDiv( VmathVector3 *result, const VmathVector3 *vec, float scalar ); + +/* + * Negate all elements of a 3-D vector + */ +static inline void vmathV3Neg( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Construct x axis + */ +static inline void vmathV3MakeXAxis( VmathVector3 *result ); + +/* + * Construct y axis + */ +static inline void vmathV3MakeYAxis( VmathVector3 *result ); + +/* + * Construct z axis + */ +static inline void vmathV3MakeZAxis( VmathVector3 *result ); + +/* + * Multiply two 3-D vectors per element + */ +static inline void vmathV3MulPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Divide two 3-D vectors per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathV3DivPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Compute the reciprocal of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathV3RecipPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the square root of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathV3SqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the reciprocal square root of a 3-D vector per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathV3RsqrtPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute the absolute value of a 3-D vector per element + */ +static inline void vmathV3AbsPerElem( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Copy sign from one 3-D vector to another, per element + */ +static inline void vmathV3CopySignPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Maximum of two 3-D vectors per element + */ +static inline void vmathV3MaxPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Minimum of two 3-D vectors per element + */ +static inline void vmathV3MinPerElem( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Maximum element of a 3-D vector + */ +static inline float vmathV3MaxElem( const VmathVector3 *vec ); + +/* + * Minimum element of a 3-D vector + */ +static inline float vmathV3MinElem( const VmathVector3 *vec ); + +/* + * Compute the sum of all elements of a 3-D vector + */ +static inline float vmathV3Sum( const VmathVector3 *vec ); + +/* + * Compute the dot product of two 3-D vectors + */ +static inline float vmathV3Dot( const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Compute the square of the length of a 3-D vector + */ +static inline float vmathV3LengthSqr( const VmathVector3 *vec ); + +/* + * Compute the length of a 3-D vector + */ +static inline float vmathV3Length( const VmathVector3 *vec ); + +/* + * Normalize a 3-D vector + * NOTE: + * The result is unpredictable when all elements of vec are at or near zero. + */ +static inline void vmathV3Normalize( VmathVector3 *result, const VmathVector3 *vec ); + +/* + * Compute cross product of two 3-D vectors + */ +static inline void vmathV3Cross( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Outer product of two 3-D vectors + */ +static inline void vmathV3Outer( VmathMatrix3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Pre-multiply a row vector by a 3x3 matrix + * NOTE: + * Slower than column post-multiply. + */ +static inline void vmathV3RowMul( VmathVector3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); + +/* + * Cross-product matrix of a 3-D vector + */ +static inline void vmathV3CrossMatrix( VmathMatrix3 *result, const VmathVector3 *vec ); + +/* + * Create cross-product matrix and multiply + * NOTE: + * Faster than separately creating a cross-product matrix and multiplying. + */ +static inline void vmathV3CrossMatrixMul( VmathMatrix3 *result, const VmathVector3 *vec, const VmathMatrix3 *mat ); + +/* + * Linear interpolation between two 3-D vectors + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathV3Lerp( VmathVector3 *result, float t, const VmathVector3 *vec0, const VmathVector3 *vec1 ); + +/* + * Spherical linear interpolation between two 3-D vectors + * NOTE: + * The result is unpredictable if the vectors point in opposite directions. + * Does not clamp t between 0 and 1. + */ +static inline void vmathV3Slerp( VmathVector3 *result, float t, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); + +/* + * Conditionally select between two 3-D vectors + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathV3Select( VmathVector3 *result, const VmathVector3 *vec0, const VmathVector3 *vec1, unsigned int select1 ); + +/* + * Store x, y, and z elements of a 3-D vector in the first three words of a quadword. + * The value of the fourth word (the word with the highest address) remains unchanged + */ +static inline void vmathV3StoreXYZ( const VmathVector3 *vec, vec_float4 *quad ); + +/* + * Load four three-float 3-D vectors, stored in three quadwords + */ +static inline void vmathV3LoadXYZArray( VmathVector3 *vec0, VmathVector3 *vec1, VmathVector3 *vec2, VmathVector3 *vec3, const vec_float4 *threeQuads ); + +/* + * Store four 3-D vectors in three quadwords + */ +static inline void vmathV3StoreXYZArray( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, vec_float4 *threeQuads ); + +/* + * Store eight 3-D vectors as half-floats + */ +static inline void vmathV3StoreHalfFloats( const VmathVector3 *vec0, const VmathVector3 *vec1, const VmathVector3 *vec2, const VmathVector3 *vec3, const VmathVector3 *vec4, const VmathVector3 *vec5, const VmathVector3 *vec6, const VmathVector3 *vec7, vec_ushort8 *threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3-D vector + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV3Print( const VmathVector3 *vec ); + +/* + * Print a 3-D vector and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV3Prints( const VmathVector3 *vec, const char *name ); + +#endif + +/* + * Copy a 4-D vector + */ +static inline void vmathV4Copy( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Construct a 4-D vector from x, y, z, and w elements + */ +static inline void vmathV4MakeFromElems( VmathVector4 *result, float x, float y, float z, float w ); + +/* + * Construct a 4-D vector from a 3-D vector and a scalar + */ +static inline void vmathV4MakeFromV3Scalar( VmathVector4 *result, const VmathVector3 *xyz, float w ); + +/* + * Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 + */ +static inline void vmathV4MakeFromV3( VmathVector4 *result, const VmathVector3 *vec ); + +/* + * Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 + */ +static inline void vmathV4MakeFromP3( VmathVector4 *result, const VmathPoint3 *pnt ); + +/* + * Copy elements from a quaternion into a 4-D vector + */ +static inline void vmathV4MakeFromQ( VmathVector4 *result, const VmathQuat *quat ); + +/* + * Set all elements of a 4-D vector to the same scalar value + */ +static inline void vmathV4MakeFromScalar( VmathVector4 *result, float scalar ); + +/* + * Set vector float data in a 4-D vector + */ +static inline void vmathV4MakeFrom128( VmathVector4 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 4-D vector + */ +static inline vec_float4 vmathV4Get128( const VmathVector4 *vec ); + +/* + * Set the x, y, and z elements of a 4-D vector + * NOTE: + * This function does not change the w element. + */ +static inline void vmathV4SetXYZ( VmathVector4 *result, const VmathVector3 *vec ); + +/* + * Get the x, y, and z elements of a 4-D vector + */ +static inline void vmathV4GetXYZ( VmathVector3 *result, const VmathVector4 *vec ); + +/* + * Set the x element of a 4-D vector + */ +static inline void vmathV4SetX( VmathVector4 *result, float x ); + +/* + * Set the y element of a 4-D vector + */ +static inline void vmathV4SetY( VmathVector4 *result, float y ); + +/* + * Set the z element of a 4-D vector + */ +static inline void vmathV4SetZ( VmathVector4 *result, float z ); + +/* + * Set the w element of a 4-D vector + */ +static inline void vmathV4SetW( VmathVector4 *result, float w ); + +/* + * Get the x element of a 4-D vector + */ +static inline float vmathV4GetX( const VmathVector4 *vec ); + +/* + * Get the y element of a 4-D vector + */ +static inline float vmathV4GetY( const VmathVector4 *vec ); + +/* + * Get the z element of a 4-D vector + */ +static inline float vmathV4GetZ( const VmathVector4 *vec ); + +/* + * Get the w element of a 4-D vector + */ +static inline float vmathV4GetW( const VmathVector4 *vec ); + +/* + * Set an x, y, z, or w element of a 4-D vector by index + */ +static inline void vmathV4SetElem( VmathVector4 *result, int idx, float value ); + +/* + * Get an x, y, z, or w element of a 4-D vector by index + */ +static inline float vmathV4GetElem( const VmathVector4 *vec, int idx ); + +/* + * Add two 4-D vectors + */ +static inline void vmathV4Add( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Subtract a 4-D vector from another 4-D vector + */ +static inline void vmathV4Sub( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Multiply a 4-D vector by a scalar + */ +static inline void vmathV4ScalarMul( VmathVector4 *result, const VmathVector4 *vec, float scalar ); + +/* + * Divide a 4-D vector by a scalar + */ +static inline void vmathV4ScalarDiv( VmathVector4 *result, const VmathVector4 *vec, float scalar ); + +/* + * Negate all elements of a 4-D vector + */ +static inline void vmathV4Neg( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Construct x axis + */ +static inline void vmathV4MakeXAxis( VmathVector4 *result ); + +/* + * Construct y axis + */ +static inline void vmathV4MakeYAxis( VmathVector4 *result ); + +/* + * Construct z axis + */ +static inline void vmathV4MakeZAxis( VmathVector4 *result ); + +/* + * Construct w axis + */ +static inline void vmathV4MakeWAxis( VmathVector4 *result ); + +/* + * Multiply two 4-D vectors per element + */ +static inline void vmathV4MulPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Divide two 4-D vectors per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathV4DivPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Compute the reciprocal of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathV4RecipPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the square root of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathV4SqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the reciprocal square root of a 4-D vector per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathV4RsqrtPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Compute the absolute value of a 4-D vector per element + */ +static inline void vmathV4AbsPerElem( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Copy sign from one 4-D vector to another, per element + */ +static inline void vmathV4CopySignPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Maximum of two 4-D vectors per element + */ +static inline void vmathV4MaxPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Minimum of two 4-D vectors per element + */ +static inline void vmathV4MinPerElem( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Maximum element of a 4-D vector + */ +static inline float vmathV4MaxElem( const VmathVector4 *vec ); + +/* + * Minimum element of a 4-D vector + */ +static inline float vmathV4MinElem( const VmathVector4 *vec ); + +/* + * Compute the sum of all elements of a 4-D vector + */ +static inline float vmathV4Sum( const VmathVector4 *vec ); + +/* + * Compute the dot product of two 4-D vectors + */ +static inline float vmathV4Dot( const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Compute the square of the length of a 4-D vector + */ +static inline float vmathV4LengthSqr( const VmathVector4 *vec ); + +/* + * Compute the length of a 4-D vector + */ +static inline float vmathV4Length( const VmathVector4 *vec ); + +/* + * Normalize a 4-D vector + * NOTE: + * The result is unpredictable when all elements of vec are at or near zero. + */ +static inline void vmathV4Normalize( VmathVector4 *result, const VmathVector4 *vec ); + +/* + * Outer product of two 4-D vectors + */ +static inline void vmathV4Outer( VmathMatrix4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Linear interpolation between two 4-D vectors + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathV4Lerp( VmathVector4 *result, float t, const VmathVector4 *vec0, const VmathVector4 *vec1 ); + +/* + * Spherical linear interpolation between two 4-D vectors + * NOTE: + * The result is unpredictable if the vectors point in opposite directions. + * Does not clamp t between 0 and 1. + */ +static inline void vmathV4Slerp( VmathVector4 *result, float t, const VmathVector4 *unitVec0, const VmathVector4 *unitVec1 ); + +/* + * Conditionally select between two 4-D vectors + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathV4Select( VmathVector4 *result, const VmathVector4 *vec0, const VmathVector4 *vec1, unsigned int select1 ); + +/* + * Store four 4-D vectors as half-floats + */ +static inline void vmathV4StoreHalfFloats( const VmathVector4 *vec0, const VmathVector4 *vec1, const VmathVector4 *vec2, const VmathVector4 *vec3, vec_ushort8 *twoQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 4-D vector + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV4Print( const VmathVector4 *vec ); + +/* + * Print a 4-D vector and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathV4Prints( const VmathVector4 *vec, const char *name ); + +#endif + +/* + * Copy a 3-D point + */ +static inline void vmathP3Copy( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Construct a 3-D point from x, y, and z elements + */ +static inline void vmathP3MakeFromElems( VmathPoint3 *result, float x, float y, float z ); + +/* + * Copy elements from a 3-D vector into a 3-D point + */ +static inline void vmathP3MakeFromV3( VmathPoint3 *result, const VmathVector3 *vec ); + +/* + * Set all elements of a 3-D point to the same scalar value + */ +static inline void vmathP3MakeFromScalar( VmathPoint3 *result, float scalar ); + +/* + * Set vector float data in a 3-D point + */ +static inline void vmathP3MakeFrom128( VmathPoint3 *result, vec_float4 vf4 ); + +/* + * Get vector float data from a 3-D point + */ +static inline vec_float4 vmathP3Get128( const VmathPoint3 *pnt ); + +/* + * Set the x element of a 3-D point + */ +static inline void vmathP3SetX( VmathPoint3 *result, float x ); + +/* + * Set the y element of a 3-D point + */ +static inline void vmathP3SetY( VmathPoint3 *result, float y ); + +/* + * Set the z element of a 3-D point + */ +static inline void vmathP3SetZ( VmathPoint3 *result, float z ); + +/* + * Get the x element of a 3-D point + */ +static inline float vmathP3GetX( const VmathPoint3 *pnt ); + +/* + * Get the y element of a 3-D point + */ +static inline float vmathP3GetY( const VmathPoint3 *pnt ); + +/* + * Get the z element of a 3-D point + */ +static inline float vmathP3GetZ( const VmathPoint3 *pnt ); + +/* + * Set an x, y, or z element of a 3-D point by index + */ +static inline void vmathP3SetElem( VmathPoint3 *result, int idx, float value ); + +/* + * Get an x, y, or z element of a 3-D point by index + */ +static inline float vmathP3GetElem( const VmathPoint3 *pnt, int idx ); + +/* + * Subtract a 3-D point from another 3-D point + */ +static inline void vmathP3Sub( VmathVector3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Add a 3-D point to a 3-D vector + */ +static inline void vmathP3AddV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); + +/* + * Subtract a 3-D vector from a 3-D point + */ +static inline void vmathP3SubV3( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *vec ); + +/* + * Multiply two 3-D points per element + */ +static inline void vmathP3MulPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Divide two 3-D points per element + * NOTE: + * Floating-point behavior matches standard library function divf4. + */ +static inline void vmathP3DivPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Compute the reciprocal of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function recipf4. + */ +static inline void vmathP3RecipPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the square root of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function sqrtf4. + */ +static inline void vmathP3SqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the reciprocal square root of a 3-D point per element + * NOTE: + * Floating-point behavior matches standard library function rsqrtf4. + */ +static inline void vmathP3RsqrtPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Compute the absolute value of a 3-D point per element + */ +static inline void vmathP3AbsPerElem( VmathPoint3 *result, const VmathPoint3 *pnt ); + +/* + * Copy sign from one 3-D point to another, per element + */ +static inline void vmathP3CopySignPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Maximum of two 3-D points per element + */ +static inline void vmathP3MaxPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Minimum of two 3-D points per element + */ +static inline void vmathP3MinPerElem( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Maximum element of a 3-D point + */ +static inline float vmathP3MaxElem( const VmathPoint3 *pnt ); + +/* + * Minimum element of a 3-D point + */ +static inline float vmathP3MinElem( const VmathPoint3 *pnt ); + +/* + * Compute the sum of all elements of a 3-D point + */ +static inline float vmathP3Sum( const VmathPoint3 *pnt ); + +/* + * Apply uniform scale to a 3-D point + */ +static inline void vmathP3Scale( VmathPoint3 *result, const VmathPoint3 *pnt, float scaleVal ); + +/* + * Apply non-uniform scale to a 3-D point + */ +static inline void vmathP3NonUniformScale( VmathPoint3 *result, const VmathPoint3 *pnt, const VmathVector3 *scaleVec ); + +/* + * Scalar projection of a 3-D point on a unit-length 3-D vector + */ +static inline float vmathP3Projection( const VmathPoint3 *pnt, const VmathVector3 *unitVec ); + +/* + * Compute the square of the distance of a 3-D point from the coordinate-system origin + */ +static inline float vmathP3DistSqrFromOrigin( const VmathPoint3 *pnt ); + +/* + * Compute the distance of a 3-D point from the coordinate-system origin + */ +static inline float vmathP3DistFromOrigin( const VmathPoint3 *pnt ); + +/* + * Compute the square of the distance between two 3-D points + */ +static inline float vmathP3DistSqr( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Compute the distance between two 3-D points + */ +static inline float vmathP3Dist( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Linear interpolation between two 3-D points + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathP3Lerp( VmathPoint3 *result, float t, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1 ); + +/* + * Conditionally select between two 3-D points + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathP3Select( VmathPoint3 *result, const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, unsigned int select1 ); + +/* + * Store x, y, and z elements of a 3-D point in the first three words of a quadword. + * The value of the fourth word (the word with the highest address) remains unchanged + */ +static inline void vmathP3StoreXYZ( const VmathPoint3 *pnt, vec_float4 *quad ); + +/* + * Load four three-float 3-D points, stored in three quadwords + */ +static inline void vmathP3LoadXYZArray( VmathPoint3 *pnt0, VmathPoint3 *pnt1, VmathPoint3 *pnt2, VmathPoint3 *pnt3, const vec_float4 *threeQuads ); + +/* + * Store four 3-D points in three quadwords + */ +static inline void vmathP3StoreXYZArray( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, vec_float4 *threeQuads ); + +/* + * Store eight 3-D points as half-floats + */ +static inline void vmathP3StoreHalfFloats( const VmathPoint3 *pnt0, const VmathPoint3 *pnt1, const VmathPoint3 *pnt2, const VmathPoint3 *pnt3, const VmathPoint3 *pnt4, const VmathPoint3 *pnt5, const VmathPoint3 *pnt6, const VmathPoint3 *pnt7, vec_ushort8 *threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3-D point + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathP3Print( const VmathPoint3 *pnt ); + +/* + * Print a 3-D point and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathP3Prints( const VmathPoint3 *pnt, const char *name ); + +#endif + +/* + * Copy a quaternion + */ +static inline void vmathQCopy( VmathQuat *result, const VmathQuat *quat ); + +/* + * Construct a quaternion from x, y, z, and w elements + */ +static inline void vmathQMakeFromElems( VmathQuat *result, float x, float y, float z, float w ); + +/* + * Construct a quaternion from a 3-D vector and a scalar + */ +static inline void vmathQMakeFromV3Scalar( VmathQuat *result, const VmathVector3 *xyz, float w ); + +/* + * Copy elements from a 4-D vector into a quaternion + */ +static inline void vmathQMakeFromV4( VmathQuat *result, const VmathVector4 *vec ); + +/* + * Convert a rotation matrix to a unit-length quaternion + */ +static inline void vmathQMakeFromM3( VmathQuat *result, const VmathMatrix3 *rotMat ); + +/* + * Set all elements of a quaternion to the same scalar value + */ +static inline void vmathQMakeFromScalar( VmathQuat *result, float scalar ); + +/* + * Set vector float data in a quaternion + */ +static inline void vmathQMakeFrom128( VmathQuat *result, vec_float4 vf4 ); + +/* + * Get vector float data from a quaternion + */ +static inline vec_float4 vmathQGet128( const VmathQuat *quat ); + +/* + * Set the x, y, and z elements of a quaternion + * NOTE: + * This function does not change the w element. + */ +static inline void vmathQSetXYZ( VmathQuat *result, const VmathVector3 *vec ); + +/* + * Get the x, y, and z elements of a quaternion + */ +static inline void vmathQGetXYZ( VmathVector3 *result, const VmathQuat *quat ); + +/* + * Set the x element of a quaternion + */ +static inline void vmathQSetX( VmathQuat *result, float x ); + +/* + * Set the y element of a quaternion + */ +static inline void vmathQSetY( VmathQuat *result, float y ); + +/* + * Set the z element of a quaternion + */ +static inline void vmathQSetZ( VmathQuat *result, float z ); + +/* + * Set the w element of a quaternion + */ +static inline void vmathQSetW( VmathQuat *result, float w ); + +/* + * Get the x element of a quaternion + */ +static inline float vmathQGetX( const VmathQuat *quat ); + +/* + * Get the y element of a quaternion + */ +static inline float vmathQGetY( const VmathQuat *quat ); + +/* + * Get the z element of a quaternion + */ +static inline float vmathQGetZ( const VmathQuat *quat ); + +/* + * Get the w element of a quaternion + */ +static inline float vmathQGetW( const VmathQuat *quat ); + +/* + * Set an x, y, z, or w element of a quaternion by index + */ +static inline void vmathQSetElem( VmathQuat *result, int idx, float value ); + +/* + * Get an x, y, z, or w element of a quaternion by index + */ +static inline float vmathQGetElem( const VmathQuat *quat, int idx ); + +/* + * Add two quaternions + */ +static inline void vmathQAdd( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Subtract a quaternion from another quaternion + */ +static inline void vmathQSub( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Multiply two quaternions + */ +static inline void vmathQMul( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Multiply a quaternion by a scalar + */ +static inline void vmathQScalarMul( VmathQuat *result, const VmathQuat *quat, float scalar ); + +/* + * Divide a quaternion by a scalar + */ +static inline void vmathQScalarDiv( VmathQuat *result, const VmathQuat *quat, float scalar ); + +/* + * Negate all elements of a quaternion + */ +static inline void vmathQNeg( VmathQuat *result, const VmathQuat *quat ); + +/* + * Construct an identity quaternion + */ +static inline void vmathQMakeIdentity( VmathQuat *result ); + +/* + * Construct a quaternion to rotate between two unit-length 3-D vectors + * NOTE: + * The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. + */ +static inline void vmathQMakeRotationArc( VmathQuat *result, const VmathVector3 *unitVec0, const VmathVector3 *unitVec1 ); + +/* + * Construct a quaternion to rotate around a unit-length 3-D vector + */ +static inline void vmathQMakeRotationAxis( VmathQuat *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a quaternion to rotate around the x axis + */ +static inline void vmathQMakeRotationX( VmathQuat *result, float radians ); + +/* + * Construct a quaternion to rotate around the y axis + */ +static inline void vmathQMakeRotationY( VmathQuat *result, float radians ); + +/* + * Construct a quaternion to rotate around the z axis + */ +static inline void vmathQMakeRotationZ( VmathQuat *result, float radians ); + +/* + * Compute the conjugate of a quaternion + */ +static inline void vmathQConj( VmathQuat *result, const VmathQuat *quat ); + +/* + * Use a unit-length quaternion to rotate a 3-D vector + */ +static inline void vmathQRotate( VmathVector3 *result, const VmathQuat *unitQuat, const VmathVector3 *vec ); + +/* + * Compute the dot product of two quaternions + */ +static inline float vmathQDot( const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Compute the norm of a quaternion + */ +static inline float vmathQNorm( const VmathQuat *quat ); + +/* + * Compute the length of a quaternion + */ +static inline float vmathQLength( const VmathQuat *quat ); + +/* + * Normalize a quaternion + * NOTE: + * The result is unpredictable when all elements of quat are at or near zero. + */ +static inline void vmathQNormalize( VmathQuat *result, const VmathQuat *quat ); + +/* + * Linear interpolation between two quaternions + * NOTE: + * Does not clamp t between 0 and 1. + */ +static inline void vmathQLerp( VmathQuat *result, float t, const VmathQuat *quat0, const VmathQuat *quat1 ); + +/* + * Spherical linear interpolation between two quaternions + * NOTE: + * Interpolates along the shortest path between orientations. + * Does not clamp t between 0 and 1. + */ +static inline void vmathQSlerp( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1 ); + +/* + * Spherical quadrangle interpolation + */ +static inline void vmathQSquad( VmathQuat *result, float t, const VmathQuat *unitQuat0, const VmathQuat *unitQuat1, const VmathQuat *unitQuat2, const VmathQuat *unitQuat3 ); + +/* + * Conditionally select between two quaternions + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathQSelect( VmathQuat *result, const VmathQuat *quat0, const VmathQuat *quat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a quaternion + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathQPrint( const VmathQuat *quat ); + +/* + * Print a quaternion and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathQPrints( const VmathQuat *quat, const char *name ); + +#endif + +/* + * Copy a 3x3 matrix + */ +static inline void vmathM3Copy( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Construct a 3x3 matrix containing the specified columns + */ +static inline void vmathM3MakeFromCols( VmathMatrix3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2 ); + +/* + * Construct a 3x3 rotation matrix from a unit-length quaternion + */ +static inline void vmathM3MakeFromQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); + +/* + * Set all elements of a 3x3 matrix to the same scalar value + */ +static inline void vmathM3MakeFromScalar( VmathMatrix3 *result, float scalar ); + +/* + * Set column 0 of a 3x3 matrix + */ +static inline void vmathM3SetCol0( VmathMatrix3 *result, const VmathVector3 *col0 ); + +/* + * Set column 1 of a 3x3 matrix + */ +static inline void vmathM3SetCol1( VmathMatrix3 *result, const VmathVector3 *col1 ); + +/* + * Set column 2 of a 3x3 matrix + */ +static inline void vmathM3SetCol2( VmathMatrix3 *result, const VmathVector3 *col2 ); + +/* + * Get column 0 of a 3x3 matrix + */ +static inline void vmathM3GetCol0( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Get column 1 of a 3x3 matrix + */ +static inline void vmathM3GetCol1( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Get column 2 of a 3x3 matrix + */ +static inline void vmathM3GetCol2( VmathVector3 *result, const VmathMatrix3 *mat ); + +/* + * Set the column of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3SetCol( VmathMatrix3 *result, int col, const VmathVector3 *vec ); + +/* + * Set the row of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3SetRow( VmathMatrix3 *result, int row, const VmathVector3 *vec ); + +/* + * Get the column of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3GetCol( VmathVector3 *result, const VmathMatrix3 *mat, int col ); + +/* + * Get the row of a 3x3 matrix referred to by the specified index + */ +static inline void vmathM3GetRow( VmathVector3 *result, const VmathMatrix3 *mat, int row ); + +/* + * Set the element of a 3x3 matrix referred to by column and row indices + */ +static inline void vmathM3SetElem( VmathMatrix3 *result, int col, int row, float val ); + +/* + * Get the element of a 3x3 matrix referred to by column and row indices + */ +static inline float vmathM3GetElem( const VmathMatrix3 *mat, int col, int row ); + +/* + * Add two 3x3 matrices + */ +static inline void vmathM3Add( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Subtract a 3x3 matrix from another 3x3 matrix + */ +static inline void vmathM3Sub( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Negate all elements of a 3x3 matrix + */ +static inline void vmathM3Neg( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Multiply a 3x3 matrix by a scalar + */ +static inline void vmathM3ScalarMul( VmathMatrix3 *result, const VmathMatrix3 *mat, float scalar ); + +/* + * Multiply a 3x3 matrix by a 3-D vector + */ +static inline void vmathM3MulV3( VmathVector3 *result, const VmathMatrix3 *mat, const VmathVector3 *vec ); + +/* + * Multiply two 3x3 matrices + */ +static inline void vmathM3Mul( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Construct an identity 3x3 matrix + */ +static inline void vmathM3MakeIdentity( VmathMatrix3 *result ); + +/* + * Construct a 3x3 matrix to rotate around the x axis + */ +static inline void vmathM3MakeRotationX( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the y axis + */ +static inline void vmathM3MakeRotationY( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the z axis + */ +static inline void vmathM3MakeRotationZ( VmathMatrix3 *result, float radians ); + +/* + * Construct a 3x3 matrix to rotate around the x, y, and z axes + */ +static inline void vmathM3MakeRotationZYX( VmathMatrix3 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 3x3 matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathM3MakeRotationAxis( VmathMatrix3 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathM3MakeRotationQ( VmathMatrix3 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 3x3 matrix to perform scaling + */ +static inline void vmathM3MakeScale( VmathMatrix3 *result, const VmathVector3 *scaleVec ); + +/* + * Append (post-multiply) a scale transformation to a 3x3 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM3AppendScale( VmathMatrix3 *result, const VmathMatrix3 *mat, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 3x3 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM3PrependScale( VmathMatrix3 *result, const VmathVector3 *scaleVec, const VmathMatrix3 *mat ); + +/* + * Multiply two 3x3 matrices per element + */ +static inline void vmathM3MulPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1 ); + +/* + * Compute the absolute value of a 3x3 matrix per element + */ +static inline void vmathM3AbsPerElem( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Transpose of a 3x3 matrix + */ +static inline void vmathM3Transpose( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Compute the inverse of a 3x3 matrix + * NOTE: + * Result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM3Inverse( VmathMatrix3 *result, const VmathMatrix3 *mat ); + +/* + * Determinant of a 3x3 matrix + */ +static inline float vmathM3Determinant( const VmathMatrix3 *mat ); + +/* + * Conditionally select between two 3x3 matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathM3Select( VmathMatrix3 *result, const VmathMatrix3 *mat0, const VmathMatrix3 *mat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3x3 matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM3Print( const VmathMatrix3 *mat ); + +/* + * Print a 3x3 matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM3Prints( const VmathMatrix3 *mat, const char *name ); + +#endif + +/* + * Copy a 4x4 matrix + */ +static inline void vmathM4Copy( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Construct a 4x4 matrix containing the specified columns + */ +static inline void vmathM4MakeFromCols( VmathMatrix4 *result, const VmathVector4 *col0, const VmathVector4 *col1, const VmathVector4 *col2, const VmathVector4 *col3 ); + +/* + * Construct a 4x4 matrix from a 3x4 transformation matrix + */ +static inline void vmathM4MakeFromT3( VmathMatrix4 *result, const VmathTransform3 *mat ); + +/* + * Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector + */ +static inline void vmathM4MakeFromM3V3( VmathMatrix4 *result, const VmathMatrix3 *mat, const VmathVector3 *translateVec ); + +/* + * Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector + */ +static inline void vmathM4MakeFromQV3( VmathMatrix4 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); + +/* + * Set all elements of a 4x4 matrix to the same scalar value + */ +static inline void vmathM4MakeFromScalar( VmathMatrix4 *result, float scalar ); + +/* + * Set the upper-left 3x3 submatrix + * NOTE: + * This function does not change the bottom row elements. + */ +static inline void vmathM4SetUpper3x3( VmathMatrix4 *result, const VmathMatrix3 *mat3 ); + +/* + * Get the upper-left 3x3 submatrix of a 4x4 matrix + */ +static inline void vmathM4GetUpper3x3( VmathMatrix3 *result, const VmathMatrix4 *mat ); + +/* + * Set translation component + * NOTE: + * This function does not change the bottom row elements. + */ +static inline void vmathM4SetTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); + +/* + * Get the translation component of a 4x4 matrix + */ +static inline void vmathM4GetTranslation( VmathVector3 *result, const VmathMatrix4 *mat ); + +/* + * Set column 0 of a 4x4 matrix + */ +static inline void vmathM4SetCol0( VmathMatrix4 *result, const VmathVector4 *col0 ); + +/* + * Set column 1 of a 4x4 matrix + */ +static inline void vmathM4SetCol1( VmathMatrix4 *result, const VmathVector4 *col1 ); + +/* + * Set column 2 of a 4x4 matrix + */ +static inline void vmathM4SetCol2( VmathMatrix4 *result, const VmathVector4 *col2 ); + +/* + * Set column 3 of a 4x4 matrix + */ +static inline void vmathM4SetCol3( VmathMatrix4 *result, const VmathVector4 *col3 ); + +/* + * Get column 0 of a 4x4 matrix + */ +static inline void vmathM4GetCol0( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 1 of a 4x4 matrix + */ +static inline void vmathM4GetCol1( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 2 of a 4x4 matrix + */ +static inline void vmathM4GetCol2( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Get column 3 of a 4x4 matrix + */ +static inline void vmathM4GetCol3( VmathVector4 *result, const VmathMatrix4 *mat ); + +/* + * Set the column of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4SetCol( VmathMatrix4 *result, int col, const VmathVector4 *vec ); + +/* + * Set the row of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4SetRow( VmathMatrix4 *result, int row, const VmathVector4 *vec ); + +/* + * Get the column of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4GetCol( VmathVector4 *result, const VmathMatrix4 *mat, int col ); + +/* + * Get the row of a 4x4 matrix referred to by the specified index + */ +static inline void vmathM4GetRow( VmathVector4 *result, const VmathMatrix4 *mat, int row ); + +/* + * Set the element of a 4x4 matrix referred to by column and row indices + */ +static inline void vmathM4SetElem( VmathMatrix4 *result, int col, int row, float val ); + +/* + * Get the element of a 4x4 matrix referred to by column and row indices + */ +static inline float vmathM4GetElem( const VmathMatrix4 *mat, int col, int row ); + +/* + * Add two 4x4 matrices + */ +static inline void vmathM4Add( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Subtract a 4x4 matrix from another 4x4 matrix + */ +static inline void vmathM4Sub( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Negate all elements of a 4x4 matrix + */ +static inline void vmathM4Neg( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Multiply a 4x4 matrix by a scalar + */ +static inline void vmathM4ScalarMul( VmathMatrix4 *result, const VmathMatrix4 *mat, float scalar ); + +/* + * Multiply a 4x4 matrix by a 4-D vector + */ +static inline void vmathM4MulV4( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector4 *vec ); + +/* + * Multiply a 4x4 matrix by a 3-D vector + */ +static inline void vmathM4MulV3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathVector3 *vec ); + +/* + * Multiply a 4x4 matrix by a 3-D point + */ +static inline void vmathM4MulP3( VmathVector4 *result, const VmathMatrix4 *mat, const VmathPoint3 *pnt ); + +/* + * Multiply two 4x4 matrices + */ +static inline void vmathM4Mul( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Multiply a 4x4 matrix by a 3x4 transformation matrix + */ +static inline void vmathM4MulT3( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathTransform3 *tfrm ); + +/* + * Construct an identity 4x4 matrix + */ +static inline void vmathM4MakeIdentity( VmathMatrix4 *result ); + +/* + * Construct a 4x4 matrix to rotate around the x axis + */ +static inline void vmathM4MakeRotationX( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the y axis + */ +static inline void vmathM4MakeRotationY( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the z axis + */ +static inline void vmathM4MakeRotationZ( VmathMatrix4 *result, float radians ); + +/* + * Construct a 4x4 matrix to rotate around the x, y, and z axes + */ +static inline void vmathM4MakeRotationZYX( VmathMatrix4 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 4x4 matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathM4MakeRotationAxis( VmathMatrix4 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathM4MakeRotationQ( VmathMatrix4 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 4x4 matrix to perform scaling + */ +static inline void vmathM4MakeScale( VmathMatrix4 *result, const VmathVector3 *scaleVec ); + +/* + * Construct a 4x4 matrix to perform translation + */ +static inline void vmathM4MakeTranslation( VmathMatrix4 *result, const VmathVector3 *translateVec ); + +/* + * Construct viewing matrix based on eye position, position looked at, and up direction + */ +static inline void vmathM4MakeLookAt( VmathMatrix4 *result, const VmathPoint3 *eyePos, const VmathPoint3 *lookAtPos, const VmathVector3 *upVec ); + +/* + * Construct a perspective projection matrix + */ +static inline void vmathM4MakePerspective( VmathMatrix4 *result, float fovyRadians, float aspect, float zNear, float zFar ); + +/* + * Construct a perspective projection matrix based on frustum + */ +static inline void vmathM4MakeFrustum( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); + +/* + * Construct an orthographic projection matrix + */ +static inline void vmathM4MakeOrthographic( VmathMatrix4 *result, float left, float right, float bottom, float top, float zNear, float zFar ); + +/* + * Append (post-multiply) a scale transformation to a 4x4 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM4AppendScale( VmathMatrix4 *result, const VmathMatrix4 *mat, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 4x4 matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathM4PrependScale( VmathMatrix4 *result, const VmathVector3 *scaleVec, const VmathMatrix4 *mat ); + +/* + * Multiply two 4x4 matrices per element + */ +static inline void vmathM4MulPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1 ); + +/* + * Compute the absolute value of a 4x4 matrix per element + */ +static inline void vmathM4AbsPerElem( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Transpose of a 4x4 matrix + */ +static inline void vmathM4Transpose( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix + * NOTE: + * Result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM4Inverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. + */ +static inline void vmathM4AffineInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. + */ +static inline void vmathM4OrthoInverse( VmathMatrix4 *result, const VmathMatrix4 *mat ); + +/* + * Determinant of a 4x4 matrix + */ +static inline float vmathM4Determinant( const VmathMatrix4 *mat ); + +/* + * Conditionally select between two 4x4 matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathM4Select( VmathMatrix4 *result, const VmathMatrix4 *mat0, const VmathMatrix4 *mat1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 4x4 matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM4Print( const VmathMatrix4 *mat ); + +/* + * Print a 4x4 matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathM4Prints( const VmathMatrix4 *mat, const char *name ); + +#endif + +/* + * Copy a 3x4 transformation matrix + */ +static inline void vmathT3Copy( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Construct a 3x4 transformation matrix containing the specified columns + */ +static inline void vmathT3MakeFromCols( VmathTransform3 *result, const VmathVector3 *col0, const VmathVector3 *col1, const VmathVector3 *col2, const VmathVector3 *col3 ); + +/* + * Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector + */ +static inline void vmathT3MakeFromM3V3( VmathTransform3 *result, const VmathMatrix3 *tfrm, const VmathVector3 *translateVec ); + +/* + * Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector + */ +static inline void vmathT3MakeFromQV3( VmathTransform3 *result, const VmathQuat *unitQuat, const VmathVector3 *translateVec ); + +/* + * Set all elements of a 3x4 transformation matrix to the same scalar value + */ +static inline void vmathT3MakeFromScalar( VmathTransform3 *result, float scalar ); + +/* + * Set the upper-left 3x3 submatrix + */ +static inline void vmathT3SetUpper3x3( VmathTransform3 *result, const VmathMatrix3 *mat3 ); + +/* + * Get the upper-left 3x3 submatrix of a 3x4 transformation matrix + */ +static inline void vmathT3GetUpper3x3( VmathMatrix3 *result, const VmathTransform3 *tfrm ); + +/* + * Set translation component + */ +static inline void vmathT3SetTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); + +/* + * Get the translation component of a 3x4 transformation matrix + */ +static inline void vmathT3GetTranslation( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Set column 0 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol0( VmathTransform3 *result, const VmathVector3 *col0 ); + +/* + * Set column 1 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol1( VmathTransform3 *result, const VmathVector3 *col1 ); + +/* + * Set column 2 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol2( VmathTransform3 *result, const VmathVector3 *col2 ); + +/* + * Set column 3 of a 3x4 transformation matrix + */ +static inline void vmathT3SetCol3( VmathTransform3 *result, const VmathVector3 *col3 ); + +/* + * Get column 0 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol0( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 1 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol1( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 2 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol2( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Get column 3 of a 3x4 transformation matrix + */ +static inline void vmathT3GetCol3( VmathVector3 *result, const VmathTransform3 *tfrm ); + +/* + * Set the column of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3SetCol( VmathTransform3 *result, int col, const VmathVector3 *vec ); + +/* + * Set the row of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3SetRow( VmathTransform3 *result, int row, const VmathVector4 *vec ); + +/* + * Get the column of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3GetCol( VmathVector3 *result, const VmathTransform3 *tfrm, int col ); + +/* + * Get the row of a 3x4 transformation matrix referred to by the specified index + */ +static inline void vmathT3GetRow( VmathVector4 *result, const VmathTransform3 *tfrm, int row ); + +/* + * Set the element of a 3x4 transformation matrix referred to by column and row indices + */ +static inline void vmathT3SetElem( VmathTransform3 *result, int col, int row, float val ); + +/* + * Get the element of a 3x4 transformation matrix referred to by column and row indices + */ +static inline float vmathT3GetElem( const VmathTransform3 *tfrm, int col, int row ); + +/* + * Multiply a 3x4 transformation matrix by a 3-D vector + */ +static inline void vmathT3MulV3( VmathVector3 *result, const VmathTransform3 *tfrm, const VmathVector3 *vec ); + +/* + * Multiply a 3x4 transformation matrix by a 3-D point + */ +static inline void vmathT3MulP3( VmathPoint3 *result, const VmathTransform3 *tfrm, const VmathPoint3 *pnt ); + +/* + * Multiply two 3x4 transformation matrices + */ +static inline void vmathT3Mul( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); + +/* + * Construct an identity 3x4 transformation matrix + */ +static inline void vmathT3MakeIdentity( VmathTransform3 *result ); + +/* + * Construct a 3x4 transformation matrix to rotate around the x axis + */ +static inline void vmathT3MakeRotationX( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the y axis + */ +static inline void vmathT3MakeRotationY( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the z axis + */ +static inline void vmathT3MakeRotationZ( VmathTransform3 *result, float radians ); + +/* + * Construct a 3x4 transformation matrix to rotate around the x, y, and z axes + */ +static inline void vmathT3MakeRotationZYX( VmathTransform3 *result, const VmathVector3 *radiansXYZ ); + +/* + * Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector + */ +static inline void vmathT3MakeRotationAxis( VmathTransform3 *result, float radians, const VmathVector3 *unitVec ); + +/* + * Construct a rotation matrix from a unit-length quaternion + */ +static inline void vmathT3MakeRotationQ( VmathTransform3 *result, const VmathQuat *unitQuat ); + +/* + * Construct a 3x4 transformation matrix to perform scaling + */ +static inline void vmathT3MakeScale( VmathTransform3 *result, const VmathVector3 *scaleVec ); + +/* + * Construct a 3x4 transformation matrix to perform translation + */ +static inline void vmathT3MakeTranslation( VmathTransform3 *result, const VmathVector3 *translateVec ); + +/* + * Append (post-multiply) a scale transformation to a 3x4 transformation matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathT3AppendScale( VmathTransform3 *result, const VmathTransform3 *tfrm, const VmathVector3 *scaleVec ); + +/* + * Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix + * NOTE: + * Faster than creating and multiplying a scale transformation matrix. + */ +static inline void vmathT3PrependScale( VmathTransform3 *result, const VmathVector3 *scaleVec, const VmathTransform3 *tfrm ); + +/* + * Multiply two 3x4 transformation matrices per element + */ +static inline void vmathT3MulPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1 ); + +/* + * Compute the absolute value of a 3x4 transformation matrix per element + */ +static inline void vmathT3AbsPerElem( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Inverse of a 3x4 transformation matrix + * NOTE: + * Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. + */ +static inline void vmathT3Inverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix + * NOTE: + * This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. + */ +static inline void vmathT3OrthoInverse( VmathTransform3 *result, const VmathTransform3 *tfrm ); + +/* + * Conditionally select between two 3x4 transformation matrices + * NOTE: + * This function uses a conditional select instruction to avoid a branch. + */ +static inline void vmathT3Select( VmathTransform3 *result, const VmathTransform3 *tfrm0, const VmathTransform3 *tfrm1, unsigned int select1 ); + +#ifdef _VECTORMATH_DEBUG + +/* + * Print a 3x4 transformation matrix + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathT3Print( const VmathTransform3 *tfrm ); + +/* + * Print a 3x4 transformation matrix and an associated string identifier + * NOTE: + * Function is only defined when _VECTORMATH_DEBUG is defined. + */ +static inline void vmathT3Prints( const VmathTransform3 *tfrm, const char *name ); + +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#include "vec_aos.h" +#include "quat_aos.h" +#include "mat_aos.h" + +#endif diff --git a/common/vectormath/spu/cpp/boolInVec.h b/common/vectormath/spu/cpp/boolInVec.h index 93a3ad29..ac535843 100644 --- a/common/vectormath/spu/cpp/boolInVec.h +++ b/common/vectormath/spu/cpp/boolInVec.h @@ -1,246 +1,246 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _BOOLINVEC_H -#define _BOOLINVEC_H - -#include - -namespace Vectormath { - -class floatInVec; - -//-------------------------------------------------------------------------------------------------- -// boolInVec class -// - -class boolInVec -{ - private: - vec_uint4 mData; - - inline boolInVec(vec_uint4 vec); - public: - inline boolInVec() {} - - // matches standard type conversions - // - inline boolInVec(floatInVec vec); - - // explicit cast from bool - // - explicit inline boolInVec(bool scalar); - -#ifdef _VECTORMATH_NO_SCALAR_CAST - // explicit cast to bool - // - inline bool getAsBool() const; -#else - // implicit cast to bool - // - inline operator bool() const; -#endif - - // get vector data - // bool value is in the 0 word slot of vector as 0 (false) or -1 (true) - // - inline vec_uint4 get128() const; - - // operators - // - inline const boolInVec operator ! () const; - inline boolInVec& operator = (boolInVec vec); - inline boolInVec& operator &= (boolInVec vec); - inline boolInVec& operator ^= (boolInVec vec); - inline boolInVec& operator |= (boolInVec vec); - - // friend functions - // - friend inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); - friend inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); - friend inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); -}; - -//-------------------------------------------------------------------------------------------------- -// boolInVec functions -// - -// operators -// -inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); -inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); - -// select between vec0 and vec1 using boolInVec. -// false selects vec0, true selects vec1 -// -inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); - -} // namespace Vectormath - -//-------------------------------------------------------------------------------------------------- -// boolInVec implementation -// - -#include "floatInVec.h" - -namespace Vectormath { - -inline -boolInVec::boolInVec(vec_uint4 vec) -{ - mData = vec; -} - -inline -boolInVec::boolInVec(floatInVec vec) -{ - *this = (vec != floatInVec(0.0f)); -} - -inline -boolInVec::boolInVec(bool scalar) -{ - mData = spu_promote((unsigned int)-scalar, 0); -} - -#ifdef _VECTORMATH_NO_SCALAR_CAST -inline -bool -boolInVec::getAsBool() const -#else -inline -boolInVec::operator bool() const -#endif -{ - return (bool)spu_extract(mData, 0); -} - -inline -vec_uint4 -boolInVec::get128() const -{ - return mData; -} - -inline -const boolInVec -boolInVec::operator ! () const -{ - return boolInVec(spu_nor(mData, mData)); -} - -inline -boolInVec& -boolInVec::operator = (boolInVec vec) -{ - mData = vec.mData; - return *this; -} - -inline -boolInVec& -boolInVec::operator &= (boolInVec vec) -{ - *this = *this & vec; - return *this; -} - -inline -boolInVec& -boolInVec::operator ^= (boolInVec vec) -{ - *this = *this ^ vec; - return *this; -} - -inline -boolInVec& -boolInVec::operator |= (boolInVec vec) -{ - *this = *this | vec; - return *this; -} - -inline -const boolInVec -operator == (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(spu_cmpeq(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator != (boolInVec vec0, boolInVec vec1) -{ - return !(vec0 == vec1); -} - -inline -const boolInVec -operator & (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(spu_and(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator | (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(spu_or(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator ^ (boolInVec vec0, boolInVec vec1) -{ - return boolInVec(spu_xor(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1) -{ - return boolInVec(spu_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); -} - -} // namespace Vectormath - -#endif // boolInVec_h +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _BOOLINVEC_H +#define _BOOLINVEC_H + +#include + +namespace Vectormath { + +class floatInVec; + +//-------------------------------------------------------------------------------------------------- +// boolInVec class +// + +class boolInVec +{ + private: + vec_uint4 mData; + + inline boolInVec(vec_uint4 vec); + public: + inline boolInVec() {} + + // matches standard type conversions + // + inline boolInVec(floatInVec vec); + + // explicit cast from bool + // + explicit inline boolInVec(bool scalar); + +#ifdef _VECTORMATH_NO_SCALAR_CAST + // explicit cast to bool + // + inline bool getAsBool() const; +#else + // implicit cast to bool + // + inline operator bool() const; +#endif + + // get vector data + // bool value is in the 0 word slot of vector as 0 (false) or -1 (true) + // + inline vec_uint4 get128() const; + + // operators + // + inline const boolInVec operator ! () const; + inline boolInVec& operator = (boolInVec vec); + inline boolInVec& operator &= (boolInVec vec); + inline boolInVec& operator ^= (boolInVec vec); + inline boolInVec& operator |= (boolInVec vec); + + // friend functions + // + friend inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); + friend inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); + friend inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); +}; + +//-------------------------------------------------------------------------------------------------- +// boolInVec functions +// + +// operators +// +inline const boolInVec operator == (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator != (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator & (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator ^ (boolInVec vec0, boolInVec vec1); +inline const boolInVec operator | (boolInVec vec0, boolInVec vec1); + +// select between vec0 and vec1 using boolInVec. +// false selects vec0, true selects vec1 +// +inline const boolInVec select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1); + +} // namespace Vectormath + +//-------------------------------------------------------------------------------------------------- +// boolInVec implementation +// + +#include "floatInVec.h" + +namespace Vectormath { + +inline +boolInVec::boolInVec(vec_uint4 vec) +{ + mData = vec; +} + +inline +boolInVec::boolInVec(floatInVec vec) +{ + *this = (vec != floatInVec(0.0f)); +} + +inline +boolInVec::boolInVec(bool scalar) +{ + mData = spu_promote((unsigned int)-scalar, 0); +} + +#ifdef _VECTORMATH_NO_SCALAR_CAST +inline +bool +boolInVec::getAsBool() const +#else +inline +boolInVec::operator bool() const +#endif +{ + return (bool)spu_extract(mData, 0); +} + +inline +vec_uint4 +boolInVec::get128() const +{ + return mData; +} + +inline +const boolInVec +boolInVec::operator ! () const +{ + return boolInVec(spu_nor(mData, mData)); +} + +inline +boolInVec& +boolInVec::operator = (boolInVec vec) +{ + mData = vec.mData; + return *this; +} + +inline +boolInVec& +boolInVec::operator &= (boolInVec vec) +{ + *this = *this & vec; + return *this; +} + +inline +boolInVec& +boolInVec::operator ^= (boolInVec vec) +{ + *this = *this ^ vec; + return *this; +} + +inline +boolInVec& +boolInVec::operator |= (boolInVec vec) +{ + *this = *this | vec; + return *this; +} + +inline +const boolInVec +operator == (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(spu_cmpeq(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator != (boolInVec vec0, boolInVec vec1) +{ + return !(vec0 == vec1); +} + +inline +const boolInVec +operator & (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(spu_and(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator | (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(spu_or(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator ^ (boolInVec vec0, boolInVec vec1) +{ + return boolInVec(spu_xor(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +select(boolInVec vec0, boolInVec vec1, boolInVec select_vec1) +{ + return boolInVec(spu_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); +} + +} // namespace Vectormath + +#endif // boolInVec_h diff --git a/common/vectormath/spu/cpp/floatInVec.h b/common/vectormath/spu/cpp/floatInVec.h index 7521c0c4..638f22f9 100644 --- a/common/vectormath/spu/cpp/floatInVec.h +++ b/common/vectormath/spu/cpp/floatInVec.h @@ -1,339 +1,339 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _FLOATINVEC_H -#define _FLOATINVEC_H - -#include -#include -#include -#undef bool - -namespace Vectormath { - -class boolInVec; - -//-------------------------------------------------------------------------------------------------- -// floatInVec class -// - -class floatInVec -{ - private: - vec_float4 mData; - - inline floatInVec(vec_float4 vec); - public: - inline floatInVec() {} - - // matches standard type conversions - // - inline floatInVec(boolInVec vec); - - // construct from a slot of vec_float4 - // - inline floatInVec(vec_float4 vec, int slot); - - // explicit cast from float - // - explicit inline floatInVec(float scalar); - -#ifdef _VECTORMATH_NO_SCALAR_CAST - // explicit cast to float - // - inline float getAsFloat() const; -#else - // implicit cast to float - // - inline operator float() const; -#endif - - // get vector data - // float value is in 0 word slot of vector - // - inline vec_float4 get128() const; - - // operators - // - inline const floatInVec operator ++ (int); - inline const floatInVec operator -- (int); - inline floatInVec& operator ++ (); - inline floatInVec& operator -- (); - inline const floatInVec operator - () const; - inline floatInVec& operator = (floatInVec vec); - inline floatInVec& operator *= (floatInVec vec); - inline floatInVec& operator /= (floatInVec vec); - inline floatInVec& operator += (floatInVec vec); - inline floatInVec& operator -= (floatInVec vec); - - // friend functions - // - friend inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); - friend inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); -}; - -//-------------------------------------------------------------------------------------------------- -// floatInVec functions -// - -// operators -// -inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); -inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); -inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); - -// select between vec0 and vec1 using boolInVec. -// false selects vec0, true selects vec1 -// -inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); - -} // namespace Vectormath - -//-------------------------------------------------------------------------------------------------- -// floatInVec implementation -// - -#include "boolInVec.h" - -namespace Vectormath { - -inline -floatInVec::floatInVec(vec_float4 vec) -{ - mData = vec; -} - -inline -floatInVec::floatInVec(boolInVec vec) -{ - mData = spu_sel(spu_splats(0.0f), spu_splats(1.0f), vec.get128()); -} - -inline -floatInVec::floatInVec(vec_float4 vec, int slot) -{ - mData = spu_promote(spu_extract(vec, slot), 0); -} - -inline -floatInVec::floatInVec(float scalar) -{ - mData = spu_promote(scalar, 0); -} - -#ifdef _VECTORMATH_NO_SCALAR_CAST -inline -float -floatInVec::getAsFloat() const -#else -inline -floatInVec::operator float() const -#endif -{ - return spu_extract(mData,0); -} - -inline -vec_float4 -floatInVec::get128() const -{ - return mData; -} - -inline -const floatInVec -floatInVec::operator ++ (int) -{ - vec_float4 olddata = mData; - operator ++(); - return floatInVec(olddata); -} - -inline -const floatInVec -floatInVec::operator -- (int) -{ - vec_float4 olddata = mData; - operator --(); - return floatInVec(olddata); -} - -inline -floatInVec& -floatInVec::operator ++ () -{ - *this += floatInVec(1.0f); - return *this; -} - -inline -floatInVec& -floatInVec::operator -- () -{ - *this -= floatInVec(1.0f); - return *this; -} - -inline -const floatInVec -floatInVec::operator - () const -{ - return floatInVec((vec_float4)spu_xor((vec_uint4)mData, spu_splats(0x80000000))); -} - -inline -floatInVec& -floatInVec::operator = (floatInVec vec) -{ - mData = vec.mData; - return *this; -} - -inline -floatInVec& -floatInVec::operator *= (floatInVec vec) -{ - *this = *this * vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator /= (floatInVec vec) -{ - *this = *this / vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator += (floatInVec vec) -{ - *this = *this + vec; - return *this; -} - -inline -floatInVec& -floatInVec::operator -= (floatInVec vec) -{ - *this = *this - vec; - return *this; -} - -inline -const floatInVec -operator * (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(spu_mul(vec0.get128(), vec1.get128())); -} - -inline -const floatInVec -operator / (floatInVec num, floatInVec den) -{ - return floatInVec(divf4(num.get128(), den.get128())); -} - -inline -const floatInVec -operator + (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(spu_add(vec0.get128(), vec1.get128())); -} - -inline -const floatInVec -operator - (floatInVec vec0, floatInVec vec1) -{ - return floatInVec(spu_sub(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator < (floatInVec vec0, floatInVec vec1) -{ - return boolInVec(spu_cmpgt(vec1.get128(), vec0.get128())); -} - -inline -const boolInVec -operator <= (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 > vec1); -} - -inline -const boolInVec -operator > (floatInVec vec0, floatInVec vec1) -{ - return boolInVec(spu_cmpgt(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator >= (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 < vec1); -} - -inline -const boolInVec -operator == (floatInVec vec0, floatInVec vec1) -{ - return boolInVec(spu_cmpeq(vec0.get128(), vec1.get128())); -} - -inline -const boolInVec -operator != (floatInVec vec0, floatInVec vec1) -{ - return !(vec0 == vec1); -} - -inline -const floatInVec -select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1) -{ - return floatInVec(spu_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); -} - -} // namespace Vectormath - -#endif // floatInVec_h +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FLOATINVEC_H +#define _FLOATINVEC_H + +#include +#include +#include +#undef bool + +namespace Vectormath { + +class boolInVec; + +//-------------------------------------------------------------------------------------------------- +// floatInVec class +// + +class floatInVec +{ + private: + vec_float4 mData; + + inline floatInVec(vec_float4 vec); + public: + inline floatInVec() {} + + // matches standard type conversions + // + inline floatInVec(boolInVec vec); + + // construct from a slot of vec_float4 + // + inline floatInVec(vec_float4 vec, int slot); + + // explicit cast from float + // + explicit inline floatInVec(float scalar); + +#ifdef _VECTORMATH_NO_SCALAR_CAST + // explicit cast to float + // + inline float getAsFloat() const; +#else + // implicit cast to float + // + inline operator float() const; +#endif + + // get vector data + // float value is in 0 word slot of vector + // + inline vec_float4 get128() const; + + // operators + // + inline const floatInVec operator ++ (int); + inline const floatInVec operator -- (int); + inline floatInVec& operator ++ (); + inline floatInVec& operator -- (); + inline const floatInVec operator - () const; + inline floatInVec& operator = (floatInVec vec); + inline floatInVec& operator *= (floatInVec vec); + inline floatInVec& operator /= (floatInVec vec); + inline floatInVec& operator += (floatInVec vec); + inline floatInVec& operator -= (floatInVec vec); + + // friend functions + // + friend inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); + friend inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); +}; + +//-------------------------------------------------------------------------------------------------- +// floatInVec functions +// + +// operators +// +inline const floatInVec operator * (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator / (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator + (floatInVec vec0, floatInVec vec1); +inline const floatInVec operator - (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator < (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator <= (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator > (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator >= (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator == (floatInVec vec0, floatInVec vec1); +inline const boolInVec operator != (floatInVec vec0, floatInVec vec1); + +// select between vec0 and vec1 using boolInVec. +// false selects vec0, true selects vec1 +// +inline const floatInVec select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1); + +} // namespace Vectormath + +//-------------------------------------------------------------------------------------------------- +// floatInVec implementation +// + +#include "boolInVec.h" + +namespace Vectormath { + +inline +floatInVec::floatInVec(vec_float4 vec) +{ + mData = vec; +} + +inline +floatInVec::floatInVec(boolInVec vec) +{ + mData = spu_sel(spu_splats(0.0f), spu_splats(1.0f), vec.get128()); +} + +inline +floatInVec::floatInVec(vec_float4 vec, int slot) +{ + mData = spu_promote(spu_extract(vec, slot), 0); +} + +inline +floatInVec::floatInVec(float scalar) +{ + mData = spu_promote(scalar, 0); +} + +#ifdef _VECTORMATH_NO_SCALAR_CAST +inline +float +floatInVec::getAsFloat() const +#else +inline +floatInVec::operator float() const +#endif +{ + return spu_extract(mData,0); +} + +inline +vec_float4 +floatInVec::get128() const +{ + return mData; +} + +inline +const floatInVec +floatInVec::operator ++ (int) +{ + vec_float4 olddata = mData; + operator ++(); + return floatInVec(olddata); +} + +inline +const floatInVec +floatInVec::operator -- (int) +{ + vec_float4 olddata = mData; + operator --(); + return floatInVec(olddata); +} + +inline +floatInVec& +floatInVec::operator ++ () +{ + *this += floatInVec(1.0f); + return *this; +} + +inline +floatInVec& +floatInVec::operator -- () +{ + *this -= floatInVec(1.0f); + return *this; +} + +inline +const floatInVec +floatInVec::operator - () const +{ + return floatInVec((vec_float4)spu_xor((vec_uint4)mData, spu_splats(0x80000000))); +} + +inline +floatInVec& +floatInVec::operator = (floatInVec vec) +{ + mData = vec.mData; + return *this; +} + +inline +floatInVec& +floatInVec::operator *= (floatInVec vec) +{ + *this = *this * vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator /= (floatInVec vec) +{ + *this = *this / vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator += (floatInVec vec) +{ + *this = *this + vec; + return *this; +} + +inline +floatInVec& +floatInVec::operator -= (floatInVec vec) +{ + *this = *this - vec; + return *this; +} + +inline +const floatInVec +operator * (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(spu_mul(vec0.get128(), vec1.get128())); +} + +inline +const floatInVec +operator / (floatInVec num, floatInVec den) +{ + return floatInVec(divf4(num.get128(), den.get128())); +} + +inline +const floatInVec +operator + (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(spu_add(vec0.get128(), vec1.get128())); +} + +inline +const floatInVec +operator - (floatInVec vec0, floatInVec vec1) +{ + return floatInVec(spu_sub(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator < (floatInVec vec0, floatInVec vec1) +{ + return boolInVec(spu_cmpgt(vec1.get128(), vec0.get128())); +} + +inline +const boolInVec +operator <= (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 > vec1); +} + +inline +const boolInVec +operator > (floatInVec vec0, floatInVec vec1) +{ + return boolInVec(spu_cmpgt(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator >= (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 < vec1); +} + +inline +const boolInVec +operator == (floatInVec vec0, floatInVec vec1) +{ + return boolInVec(spu_cmpeq(vec0.get128(), vec1.get128())); +} + +inline +const boolInVec +operator != (floatInVec vec0, floatInVec vec1) +{ + return !(vec0 == vec1); +} + +inline +const floatInVec +select(floatInVec vec0, floatInVec vec1, boolInVec select_vec1) +{ + return floatInVec(spu_sel(vec0.get128(), vec1.get128(), select_vec1.get128())); +} + +} // namespace Vectormath + +#endif // floatInVec_h diff --git a/common/vectormath/spu/cpp/mat_aos.h b/common/vectormath/spu/cpp/mat_aos.h index a2fd611e..d4f955c2 100644 --- a/common/vectormath/spu/cpp/mat_aos.h +++ b/common/vectormath/spu/cpp/mat_aos.h @@ -1,2027 +1,2027 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_MAT_AOS_CPP_H -#define _VECTORMATH_MAT_AOS_CPP_H - -namespace Vectormath { -namespace Aos { - -//----------------------------------------------------------------------------- -// Constants -// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - -#define _VECTORMATH_SHUF_XAYB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_ZCWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_ZBW0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XCY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_0ZB0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_C0X0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_YA00 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_Z }) -#define _VECTORMATH_SHUF_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) -#define _VECTORMATH_SHUF_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X }) -#define _VECTORMATH_SHUF_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y }) -#define _VECTORMATH_SHUF_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_ZAY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_BZX0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_0ZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A }) -#define _VECTORMATH_SHUF_Z0XB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_B }) -#define _VECTORMATH_SHUF_YX0C ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_C }) -#define _VECTORMATH_SHUF_CZD0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_D, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_SHUF_BBY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) -#define _VECTORMATH_PI_OVER_2 1.570796327f - -//----------------------------------------------------------------------------- -// Definitions - -inline Matrix3::Matrix3( const Matrix3 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; -} - -inline Matrix3::Matrix3( float scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); -} - -inline Matrix3::Matrix3( Quat unitQuat ) -{ - vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - vec_uint4 select_x = (vec_uint4)spu_maskb(0xf000); - vec_uint4 select_z = (vec_uint4)spu_maskb(0x00f0); - xyzw_2 = spu_add( unitQuat.get128(), unitQuat.get128() ); - wwww = spu_shuffle( unitQuat.get128(), unitQuat.get128(), shuffle_wwww ); - yzxw = spu_shuffle( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_SHUF_YZXW ); - zxyw = spu_shuffle( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_SHUF_ZXYW ); - yzxw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_YZXW ); - zxyw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_ZXYW ); - tmp0 = spu_mul( yzxw_2, wwww ); - tmp1 = spu_nmsub( yzxw, yzxw_2, spu_splats(1.0f) ); - tmp2 = spu_mul( yzxw, xyzw_2 ); - tmp0 = spu_madd( zxyw, xyzw_2, tmp0 ); - tmp1 = spu_nmsub( zxyw, zxyw_2, tmp1 ); - tmp2 = spu_nmsub( zxyw_2, wwww, tmp2 ); - tmp3 = spu_sel( tmp0, tmp1, select_x ); - tmp4 = spu_sel( tmp1, tmp2, select_x ); - tmp5 = spu_sel( tmp2, tmp0, select_x ); - mCol0 = Vector3( spu_sel( tmp3, tmp2, select_z ) ); - mCol1 = Vector3( spu_sel( tmp4, tmp0, select_z ) ); - mCol2 = Vector3( spu_sel( tmp5, tmp1, select_z ) ); -} - -inline Matrix3::Matrix3( Vector3 _col0, Vector3 _col1, Vector3 _col2 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; -} - -inline Matrix3 & Matrix3::setCol0( Vector3 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Matrix3 & Matrix3::setCol1( Vector3 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Matrix3 & Matrix3::setCol2( Vector3 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Matrix3 & Matrix3::setCol( int col, Vector3 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Matrix3 & Matrix3::setRow( int row, Vector3 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - return *this; -} - -inline Matrix3 & Matrix3::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline float Matrix3::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector3 Matrix3::getCol0( ) const -{ - return mCol0; -} - -inline const Vector3 Matrix3::getCol1( ) const -{ - return mCol1; -} - -inline const Vector3 Matrix3::getCol2( ) const -{ - return mCol2; -} - -inline const Vector3 Matrix3::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector3 Matrix3::getRow( int row ) const -{ - return Vector3( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ) ); -} - -inline Vector3 & Matrix3::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector3 Matrix3::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Matrix3 & Matrix3::operator =( const Matrix3 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - return *this; -} - -inline const Matrix3 transpose( const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, res0, res1, res2; - tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); - res0 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); - res1 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); - res2 = spu_shuffle( tmp1, mat.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 inverse( const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; - tmp2 = _vmathVfCross( mat.getCol0().get128(), mat.getCol1().get128() ); - tmp0 = _vmathVfCross( mat.getCol1().get128(), mat.getCol2().get128() ); - tmp1 = _vmathVfCross( mat.getCol2().get128(), mat.getCol0().get128() ); - dot = _vmathVfDot3( tmp2, mat.getCol2().get128() ); - dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); - invdet = recipf4( dot ); - tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); - tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); - inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); - inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); - inv0 = spu_mul( inv0, invdet ); - inv1 = spu_mul( inv1, invdet ); - inv2 = spu_mul( inv2, invdet ); - return Matrix3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ) - ); -} - -inline float determinant( const Matrix3 & mat ) -{ - return dot( mat.getCol2(), cross( mat.getCol0(), mat.getCol1() ) ); -} - -inline const Matrix3 Matrix3::operator +( const Matrix3 & mat ) const -{ - return Matrix3( - ( mCol0 + mat.mCol0 ), - ( mCol1 + mat.mCol1 ), - ( mCol2 + mat.mCol2 ) - ); -} - -inline const Matrix3 Matrix3::operator -( const Matrix3 & mat ) const -{ - return Matrix3( - ( mCol0 - mat.mCol0 ), - ( mCol1 - mat.mCol1 ), - ( mCol2 - mat.mCol2 ) - ); -} - -inline Matrix3 & Matrix3::operator +=( const Matrix3 & mat ) -{ - *this = *this + mat; - return *this; -} - -inline Matrix3 & Matrix3::operator -=( const Matrix3 & mat ) -{ - *this = *this - mat; - return *this; -} - -inline const Matrix3 Matrix3::operator -( ) const -{ - return Matrix3( - ( -mCol0 ), - ( -mCol1 ), - ( -mCol2 ) - ); -} - -inline const Matrix3 absPerElem( const Matrix3 & mat ) -{ - return Matrix3( - absPerElem( mat.getCol0() ), - absPerElem( mat.getCol1() ), - absPerElem( mat.getCol2() ) - ); -} - -inline const Matrix3 Matrix3::operator *( float scalar ) const -{ - return Matrix3( - ( mCol0 * scalar ), - ( mCol1 * scalar ), - ( mCol2 * scalar ) - ); -} - -inline Matrix3 & Matrix3::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Matrix3 operator *( float scalar, const Matrix3 & mat ) -{ - return mat * scalar; -} - -inline const Vector3 Matrix3::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); - res = spu_mul( mCol0.get128(), xxxx ); - res = spu_madd( mCol1.get128(), yyyy, res ); - res = spu_madd( mCol2.get128(), zzzz, res ); - return Vector3( res ); -} - -inline const Matrix3 Matrix3::operator *( const Matrix3 & mat ) const -{ - return Matrix3( - ( *this * mat.mCol0 ), - ( *this * mat.mCol1 ), - ( *this * mat.mCol2 ) - ); -} - -inline Matrix3 & Matrix3::operator *=( const Matrix3 & mat ) -{ - *this = *this * mat; - return *this; -} - -inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ) -{ - return Matrix3( - mulPerElem( mat0.getCol0(), mat1.getCol0() ), - mulPerElem( mat0.getCol1(), mat1.getCol1() ), - mulPerElem( mat0.getCol2(), mat1.getCol2() ) - ); -} - -inline const Matrix3 Matrix3::identity( ) -{ - return Matrix3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ) - ); -} - -inline const Matrix3 Matrix3::rotationX( float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - return Matrix3( - Vector3::xAxis( ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 Matrix3::rotationY( float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - return Matrix3( - Vector3( res0 ), - Vector3::yAxis( ), - Vector3( res2 ) - ); -} - -inline const Matrix3 Matrix3::rotationZ( float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3::zAxis( ) - ); -} - -inline const Matrix3 Matrix3::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ.get128(); - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - return Matrix3( - Vector3( spu_mul( Z0, Y0 ) ), - Vector3( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), - Vector3( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ) - ); -} - -inline const Matrix3 Matrix3::rotation( float radians, Vector3 unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - axis = unitVec.get128(); - sincosf4( spu_splats( radians ), &s, &c ); - xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); - yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); - zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); - oneMinusC = spu_sub( spu_splats(1.0f), c ); - axisS = spu_mul( axis, s ); - negAxisS = negatef4( axisS ); - tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); - tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); - tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); - tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); - tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); - tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); - return Matrix3( - Vector3( spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ) ), - Vector3( spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ) ), - Vector3( spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ) ) - ); -} - -inline const Matrix3 Matrix3::rotation( Quat unitQuat ) -{ - return Matrix3( unitQuat ); -} - -inline const Matrix3 Matrix3::scale( Vector3 scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - return Matrix3( - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ) - ); -} - -inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ) -{ - return Matrix3( - ( mat.getCol0() * scaleVec.getX( ) ), - ( mat.getCol1() * scaleVec.getY( ) ), - ( mat.getCol2() * scaleVec.getZ( ) ) - ); -} - -inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ) -{ - return Matrix3( - mulPerElem( mat.getCol0(), scaleVec ), - mulPerElem( mat.getCol1(), scaleVec ), - mulPerElem( mat.getCol2(), scaleVec ) - ); -} - -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ) -{ - return Matrix3( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Matrix3 & mat ) -{ - print( mat.getRow( 0 ) ); - print( mat.getRow( 1 ) ); - print( mat.getRow( 2 ) ); -} - -inline void print( const Matrix3 & mat, const char * name ) -{ - printf("%s:\n", name); - print( mat ); -} - -#endif - -inline Matrix4::Matrix4( const Matrix4 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - mCol3 = mat.mCol3; -} - -inline Matrix4::Matrix4( float scalar ) -{ - mCol0 = Vector4( scalar ); - mCol1 = Vector4( scalar ); - mCol2 = Vector4( scalar ); - mCol3 = Vector4( scalar ); -} - -inline Matrix4::Matrix4( const Transform3 & mat ) -{ - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( mat.getCol3(), 1.0f ); -} - -inline Matrix4::Matrix4( Vector4 _col0, Vector4 _col1, Vector4 _col2, Vector4 _col3 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; - mCol3 = _col3; -} - -inline Matrix4::Matrix4( const Matrix3 & mat, Vector3 translateVec ) -{ - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( translateVec, 1.0f ); -} - -inline Matrix4::Matrix4( Quat unitQuat, Vector3 translateVec ) -{ - Matrix3 mat; - mat = Matrix3( unitQuat ); - mCol0 = Vector4( mat.getCol0(), 0.0f ); - mCol1 = Vector4( mat.getCol1(), 0.0f ); - mCol2 = Vector4( mat.getCol2(), 0.0f ); - mCol3 = Vector4( translateVec, 1.0f ); -} - -inline Matrix4 & Matrix4::setCol0( Vector4 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Matrix4 & Matrix4::setCol1( Vector4 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Matrix4 & Matrix4::setCol2( Vector4 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Matrix4 & Matrix4::setCol3( Vector4 _col3 ) -{ - mCol3 = _col3; - return *this; -} - -inline Matrix4 & Matrix4::setCol( int col, Vector4 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Matrix4 & Matrix4::setRow( int row, Vector4 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - mCol3.setElem( row, vec.getElem( 3 ) ); - return *this; -} - -inline Matrix4 & Matrix4::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline float Matrix4::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector4 Matrix4::getCol0( ) const -{ - return mCol0; -} - -inline const Vector4 Matrix4::getCol1( ) const -{ - return mCol1; -} - -inline const Vector4 Matrix4::getCol2( ) const -{ - return mCol2; -} - -inline const Vector4 Matrix4::getCol3( ) const -{ - return mCol3; -} - -inline const Vector4 Matrix4::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector4 Matrix4::getRow( int row ) const -{ - return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); -} - -inline Vector4 & Matrix4::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector4 Matrix4::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Matrix4 & Matrix4::operator =( const Matrix4 & mat ) -{ - mCol0 = mat.mCol0; - mCol1 = mat.mCol1; - mCol2 = mat.mCol2; - mCol3 = mat.mCol3; - return *this; -} - -inline const Matrix4 transpose( const Matrix4 & mat ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; - tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat.getCol1().get128(), mat.getCol3().get128(), _VECTORMATH_SHUF_XAYB ); - tmp2 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); - tmp3 = spu_shuffle( mat.getCol1().get128(), mat.getCol3().get128(), _VECTORMATH_SHUF_ZCWD ); - res0 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_XAYB ); - res1 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_ZCWD ); - res2 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_XAYB ); - res3 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_ZCWD ); - return Matrix4( - Vector4( res0 ), - Vector4( res1 ), - Vector4( res2 ), - Vector4( res3 ) - ); -} - -inline const Matrix4 inverse( const Matrix4 & mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 in0, in1, in2, in3; - vec_float4 tmp0, tmp1, tmp2, tmp3; - vec_float4 cof0, cof1, cof2, cof3; - vec_float4 t0, t1, t2, t3; - vec_float4 t01, t02, t03, t12, t23; - vec_float4 t1r, t2r; - vec_float4 t01r, t02r, t03r, t12r, t23r; - vec_float4 t1r3, t1r3r; - vec_float4 det, det1, det2, det3, invdet; - in0 = mat.getCol0().get128(); - in1 = mat.getCol1().get128(); - in2 = mat.getCol2().get128(); - in3 = mat.getCol3().get128(); - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ - tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ - tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ - tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ - t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ - t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ - t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ - t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = spu_mul(t2, t3); /* CL GP KD OH */ - t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ - cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ - cof1 = spu_mul(t0, t23); /* AGP ECL IOH MKD */ - t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ - cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ - cof1 = spu_msub(t0, t23r, cof1); /* AOH EKD IGP MCL - cof1 */ - cof1 = spu_rlqwbyte(cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ - - t12 = spu_mul(t1, t2); /* JC NG BK FO */ - t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ - cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - cof3 = spu_mul(t0, t12); /* ANG EJC IFO MBK */ - t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ - cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - cof3 = spu_msub(t0, t12r, cof3); /* AFO EBK ING MJC - cof3 */ - cof3 = spu_rlqwbyte(cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ - t1r = spu_rlqwbyte(t1, 8); /* B F J N */ - t2r = spu_rlqwbyte(t2, 8); /* K O C G */ - t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ - t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ - cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - cof2 = spu_mul(t0, t1r3); /* AFP EBL INH MJD */ - t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ - cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - cof2 = spu_msub(t0, t1r3r, cof2); /* ANH EJD IFP MBL - cof2 */ - cof2 = spu_rlqwbyte(cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ - t01 = spu_mul(t0, t1); /* AJ EN IB MF */ - t01 = spu_shuffle(t01, t01, _VECTORMATH_SHUF_YXWZ); /* EN AJ MF IB */ - cof2 = spu_madd(t3, t01, cof2); /* LEN PAJ DMF HIB + cof2 */ - cof3 = spu_msub(t2r, t01, cof3); /* KEN OAJ CMF GIB - cof3 */ - t01r = spu_rlqwbyte(t01, 8); /* MF IB EN AJ */ - cof2 = spu_msub(t3, t01r, cof2); /* LMF PIB DEN HAJ - cof2 */ - cof3 = spu_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ - t03 = spu_mul(t0, t3); /* AL EP ID MH */ - t03 = spu_shuffle(t03, t03, _VECTORMATH_SHUF_YXWZ); /* EP AL MH ID */ - cof1 = spu_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ - cof2 = spu_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ - t03r = spu_rlqwbyte(t03, 8); /* MH ID EP AL */ - cof1 = spu_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ - cof2 = spu_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ - t02 = spu_mul(t0, t2r); /* AK EO IC MG */ - t02 = spu_shuffle(t02, t02, _VECTORMATH_SHUF_YXWZ); /* E0 AK MG IC */ - cof1 = spu_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ - cof3 = spu_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ - t02r = spu_rlqwbyte(t02, 8); /* MG IC EO AK */ - cof1 = spu_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ - cof3 = spu_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ - /* Compute the determinant of the matrix - * - * det = sum_across(t0 * cof0); - * - * We perform a sum across the entire vector so that - * we don't have to splat the result when multiplying the - * cofactors by the inverse of the determinant. - */ - det = spu_mul(t0, cof0); - det1 = spu_rlqwbyte(det, 4); - det2 = spu_rlqwbyte(det, 8); - det3 = spu_rlqwbyte(det, 12); - det = spu_add(det, det1); - det2 = spu_add(det2, det3); - det = spu_add(det, det2); - /* Compute the reciprocal of the determinant. - */ - invdet = recipf4(det); - /* Multiply the cofactors by the reciprocal of the determinant. - */ - return Matrix4( - Vector4( spu_mul(cof0, invdet) ), - Vector4( spu_mul(cof1, invdet) ), - Vector4( spu_mul(cof2, invdet) ), - Vector4( spu_mul(cof3, invdet) ) - ); -} - -inline const Matrix4 affineInverse( const Matrix4 & mat ) -{ - Transform3 affineMat; - affineMat.setCol0( mat.getCol0().getXYZ( ) ); - affineMat.setCol1( mat.getCol1().getXYZ( ) ); - affineMat.setCol2( mat.getCol2().getXYZ( ) ); - affineMat.setCol3( mat.getCol3().getXYZ( ) ); - return Matrix4( inverse( affineMat ) ); -} - -inline const Matrix4 orthoInverse( const Matrix4 & mat ) -{ - Transform3 affineMat; - affineMat.setCol0( mat.getCol0().getXYZ( ) ); - affineMat.setCol1( mat.getCol1().getXYZ( ) ); - affineMat.setCol2( mat.getCol2().getXYZ( ) ); - affineMat.setCol3( mat.getCol3().getXYZ( ) ); - return Matrix4( orthoInverse( affineMat ) ); -} - -inline float determinant( const Matrix4 & mat ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 in0, in1, in2, in3; - vec_float4 tmp0, tmp1, tmp2, tmp3; - vec_float4 cof0; - vec_float4 t0, t1, t2, t3; - vec_float4 t12, t23; - vec_float4 t1r, t2r; - vec_float4 t12r, t23r; - vec_float4 t1r3, t1r3r; - in0 = mat.getCol0().get128(); - in1 = mat.getCol1().get128(); - in2 = mat.getCol2().get128(); - in3 = mat.getCol3().get128(); - /* Perform transform of the input matrix of the form: - * A B C D - * E F G H - * I J K L - * M N O P - * - * The pseudo transpose of the input matrix is trans: - * A E I M - * J N B F - * C G K O - * L P D H - */ - tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ - tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ - tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ - tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ - t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ - t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ - t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ - t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ - /* Generate a cofactor matrix. The computed cofactors reside in - * cof0, cof1, cof2, cof3. - */ - t23 = spu_mul(t2, t3); /* CL GP KD OH */ - t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ - cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ - t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ - cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ - - t12 = spu_mul(t1, t2); /* JC NG BK FO */ - t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ - cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ - t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ - cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ - t1r = spu_rlqwbyte(t1, 8); /* B F J N */ - t2r = spu_rlqwbyte(t2, 8); /* K O C G */ - t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ - t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ - cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ - t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ - cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ - return spu_extract( _vmathVfDot4(t0,cof0), 0 ); -} - -inline const Matrix4 Matrix4::operator +( const Matrix4 & mat ) const -{ - return Matrix4( - ( mCol0 + mat.mCol0 ), - ( mCol1 + mat.mCol1 ), - ( mCol2 + mat.mCol2 ), - ( mCol3 + mat.mCol3 ) - ); -} - -inline const Matrix4 Matrix4::operator -( const Matrix4 & mat ) const -{ - return Matrix4( - ( mCol0 - mat.mCol0 ), - ( mCol1 - mat.mCol1 ), - ( mCol2 - mat.mCol2 ), - ( mCol3 - mat.mCol3 ) - ); -} - -inline Matrix4 & Matrix4::operator +=( const Matrix4 & mat ) -{ - *this = *this + mat; - return *this; -} - -inline Matrix4 & Matrix4::operator -=( const Matrix4 & mat ) -{ - *this = *this - mat; - return *this; -} - -inline const Matrix4 Matrix4::operator -( ) const -{ - return Matrix4( - ( -mCol0 ), - ( -mCol1 ), - ( -mCol2 ), - ( -mCol3 ) - ); -} - -inline const Matrix4 absPerElem( const Matrix4 & mat ) -{ - return Matrix4( - absPerElem( mat.getCol0() ), - absPerElem( mat.getCol1() ), - absPerElem( mat.getCol2() ), - absPerElem( mat.getCol3() ) - ); -} - -inline const Matrix4 Matrix4::operator *( float scalar ) const -{ - return Matrix4( - ( mCol0 * scalar ), - ( mCol1 * scalar ), - ( mCol2 * scalar ), - ( mCol3 * scalar ) - ); -} - -inline Matrix4 & Matrix4::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Matrix4 operator *( float scalar, const Matrix4 & mat ) -{ - return mat * scalar; -} - -inline const Vector4 Matrix4::operator *( Vector4 vec ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz, wwww; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); - wwww = spu_shuffle( vec.get128(), vec.get128(), shuffle_wwww ); - tmp0 = spu_mul( mCol0.get128(), xxxx ); - tmp1 = spu_mul( mCol1.get128(), yyyy ); - tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = spu_madd( mCol3.get128(), wwww, tmp1 ); - res = spu_add( tmp0, tmp1 ); - return Vector4( res ); -} - -inline const Vector4 Matrix4::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); - res = spu_mul( mCol0.get128(), xxxx ); - res = spu_madd( mCol1.get128(), yyyy, res ); - res = spu_madd( mCol2.get128(), zzzz, res ); - return Vector4( res ); -} - -inline const Vector4 Matrix4::operator *( Point3 pnt ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_zzzz ); - tmp0 = spu_mul( mCol0.get128(), xxxx ); - tmp1 = spu_mul( mCol1.get128(), yyyy ); - tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = spu_add( mCol3.get128(), tmp1 ); - res = spu_add( tmp0, tmp1 ); - return Vector4( res ); -} - -inline const Matrix4 Matrix4::operator *( const Matrix4 & mat ) const -{ - return Matrix4( - ( *this * mat.mCol0 ), - ( *this * mat.mCol1 ), - ( *this * mat.mCol2 ), - ( *this * mat.mCol3 ) - ); -} - -inline Matrix4 & Matrix4::operator *=( const Matrix4 & mat ) -{ - *this = *this * mat; - return *this; -} - -inline const Matrix4 Matrix4::operator *( const Transform3 & tfrm ) const -{ - return Matrix4( - ( *this * tfrm.getCol0() ), - ( *this * tfrm.getCol1() ), - ( *this * tfrm.getCol2() ), - ( *this * Point3( tfrm.getCol3() ) ) - ); -} - -inline Matrix4 & Matrix4::operator *=( const Transform3 & tfrm ) -{ - *this = *this * tfrm; - return *this; -} - -inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ) -{ - return Matrix4( - mulPerElem( mat0.getCol0(), mat1.getCol0() ), - mulPerElem( mat0.getCol1(), mat1.getCol1() ), - mulPerElem( mat0.getCol2(), mat1.getCol2() ), - mulPerElem( mat0.getCol3(), mat1.getCol3() ) - ); -} - -inline const Matrix4 Matrix4::identity( ) -{ - return Matrix4( - Vector4::xAxis( ), - Vector4::yAxis( ), - Vector4::zAxis( ), - Vector4::wAxis( ) - ); -} - -inline Matrix4 & Matrix4::setUpper3x3( const Matrix3 & mat3 ) -{ - mCol0.setXYZ( mat3.getCol0() ); - mCol1.setXYZ( mat3.getCol1() ); - mCol2.setXYZ( mat3.getCol2() ); - return *this; -} - -inline const Matrix3 Matrix4::getUpper3x3( ) const -{ - return Matrix3( - mCol0.getXYZ( ), - mCol1.getXYZ( ), - mCol2.getXYZ( ) - ); -} - -inline Matrix4 & Matrix4::setTranslation( Vector3 translateVec ) -{ - mCol3.setXYZ( translateVec ); - return *this; -} - -inline const Vector3 Matrix4::getTranslation( ) const -{ - return mCol3.getXYZ( ); -} - -inline const Matrix4 Matrix4::rotationX( float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - return Matrix4( - Vector4::xAxis( ), - Vector4( res1 ), - Vector4( res2 ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationY( float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - return Matrix4( - Vector4( res0 ), - Vector4::yAxis( ), - Vector4( res2 ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationZ( float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - return Matrix4( - Vector4( res0 ), - Vector4( res1 ), - Vector4::zAxis( ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ.get128(); - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - return Matrix4( - Vector4( spu_mul( Z0, Y0 ) ), - Vector4( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), - Vector4( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotation( float radians, Vector3 unitVec ) -{ - vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - axis = unitVec.get128(); - sincosf4( spu_splats( radians ), &s, &c ); - xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); - yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); - zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); - oneMinusC = spu_sub( spu_splats(1.0f), c ); - axisS = spu_mul( axis, s ); - negAxisS = negatef4( axisS ); - tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); - tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); - tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); - tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); - tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); - tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); - zeroW = (vec_float4)spu_maskb(0x000f); - axis = spu_andc( axis, zeroW ); - return Matrix4( - Vector4( spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ) ), - Vector4( spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ) ), - Vector4( spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 Matrix4::rotation( Quat unitQuat ) -{ - return Matrix4( Transform3::rotation( unitQuat ) ); -} - -inline const Matrix4 Matrix4::scale( Vector3 scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - return Matrix4( - Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), - Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), - Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ), - Vector4::wAxis( ) - ); -} - -inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ) -{ - return Matrix4( - ( mat.getCol0() * scaleVec.getX( ) ), - ( mat.getCol1() * scaleVec.getY( ) ), - ( mat.getCol2() * scaleVec.getZ( ) ), - mat.getCol3() - ); -} - -inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ) -{ - Vector4 scale4; - scale4 = Vector4( scaleVec, 1.0f ); - return Matrix4( - mulPerElem( mat.getCol0(), scale4 ), - mulPerElem( mat.getCol1(), scale4 ), - mulPerElem( mat.getCol2(), scale4 ), - mulPerElem( mat.getCol3(), scale4 ) - ); -} - -inline const Matrix4 Matrix4::translation( Vector3 translateVec ) -{ - return Matrix4( - Vector4::xAxis( ), - Vector4::yAxis( ), - Vector4::zAxis( ), - Vector4( translateVec, 1.0f ) - ); -} - -inline const Matrix4 Matrix4::lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ) -{ - Matrix4 m4EyeFrame; - Vector3 v3X, v3Y, v3Z; - v3Y = normalize( upVec ); - v3Z = normalize( ( eyePos - lookAtPos ) ); - v3X = normalize( cross( v3Y, v3Z ) ); - v3Y = cross( v3Z, v3X ); - m4EyeFrame = Matrix4( Vector4( v3X ), Vector4( v3Y ), Vector4( v3Z ), Vector4( eyePos ) ); - return orthoInverse( m4EyeFrame ); -} - -inline const Matrix4 Matrix4::perspective( float fovyRadians, float aspect, float zNear, float zFar ) -{ - float f, rangeInv; - vec_float4 zero, col0, col1, col2, col3; - f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); - rangeInv = 1.0f / ( zNear - zFar ); - zero = spu_splats(0.0f); - col0 = zero; - col1 = zero; - col2 = zero; - col3 = zero; - col0 = spu_insert( f / aspect, col0, 0 ); - col1 = spu_insert( f, col1, 1 ); - col2 = spu_insert( ( zNear + zFar ) * rangeInv, col2, 2 ); - col2 = spu_insert( -1.0f, col2, 3 ); - col3 = spu_insert( zNear * zFar * rangeInv * 2.0f, col3, 2 ); - return Matrix4( - Vector4( col0 ), - Vector4( col1 ), - Vector4( col2 ), - Vector4( col3 ) - ); -} - -inline const Matrix4 Matrix4::frustum( float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff; - vec_float4 diagonal, column, near2; - vec_float4 zero = spu_splats(0.0f); - lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); - lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); - diff = spu_sub( rtn, lbf ); - sum = spu_add( rtn, lbf ); - inv_diff = recipf4( diff ); - near2 = spu_splats( zNear ); - near2 = spu_add( near2, near2 ); - diagonal = spu_mul( near2, inv_diff ); - column = spu_mul( sum, inv_diff ); - return Matrix4( - Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ) ), - Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ) ), - Vector4( spu_sel( column, spu_splats(-1.0f), (vec_uint4)spu_maskb(0x000f) ) ), - Vector4( spu_sel( zero, spu_mul( diagonal, spu_splats(zFar) ), (vec_uint4)spu_maskb(0x00f0) ) ) - ); -} - -inline const Matrix4 Matrix4::orthographic( float left, float right, float bottom, float top, float zNear, float zFar ) -{ - /* function implementation based on code from STIDC SDK: */ - /* -------------------------------------------------------------- */ - /* PLEASE DO NOT MODIFY THIS SECTION */ - /* This prolog section is automatically generated. */ - /* */ - /* (C)Copyright */ - /* Sony Computer Entertainment, Inc., */ - /* Toshiba Corporation, */ - /* International Business Machines Corporation, */ - /* 2001,2002. */ - /* S/T/I Confidential Information */ - /* -------------------------------------------------------------- */ - vec_float4 lbf, rtn; - vec_float4 diff, sum, inv_diff, neg_inv_diff; - vec_float4 diagonal, column; - vec_float4 zero = spu_splats(0.0f); - lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); - lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); - rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); - diff = spu_sub( rtn, lbf ); - sum = spu_add( rtn, lbf ); - inv_diff = recipf4( diff ); - neg_inv_diff = negatef4( inv_diff ); - diagonal = spu_add( inv_diff, inv_diff ); - column = spu_mul( sum, spu_sel( neg_inv_diff, inv_diff, (vec_uint4)spu_maskb(0x00f0) ) ); - return Matrix4( - Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ) ), - Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ) ), - Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x00f0) ) ), - Vector4( spu_sel( column, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ) ) - ); -} - -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ) -{ - return Matrix4( - select( mat0.getCol0(), mat1.getCol0(), select1 ), - select( mat0.getCol1(), mat1.getCol1(), select1 ), - select( mat0.getCol2(), mat1.getCol2(), select1 ), - select( mat0.getCol3(), mat1.getCol3(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Matrix4 & mat ) -{ - print( mat.getRow( 0 ) ); - print( mat.getRow( 1 ) ); - print( mat.getRow( 2 ) ); - print( mat.getRow( 3 ) ); -} - -inline void print( const Matrix4 & mat, const char * name ) -{ - printf("%s:\n", name); - print( mat ); -} - -#endif - -inline Transform3::Transform3( const Transform3 & tfrm ) -{ - mCol0 = tfrm.mCol0; - mCol1 = tfrm.mCol1; - mCol2 = tfrm.mCol2; - mCol3 = tfrm.mCol3; -} - -inline Transform3::Transform3( float scalar ) -{ - mCol0 = Vector3( scalar ); - mCol1 = Vector3( scalar ); - mCol2 = Vector3( scalar ); - mCol3 = Vector3( scalar ); -} - -inline Transform3::Transform3( Vector3 _col0, Vector3 _col1, Vector3 _col2, Vector3 _col3 ) -{ - mCol0 = _col0; - mCol1 = _col1; - mCol2 = _col2; - mCol3 = _col3; -} - -inline Transform3::Transform3( const Matrix3 & tfrm, Vector3 translateVec ) -{ - this->setUpper3x3( tfrm ); - this->setTranslation( translateVec ); -} - -inline Transform3::Transform3( Quat unitQuat, Vector3 translateVec ) -{ - this->setUpper3x3( Matrix3( unitQuat ) ); - this->setTranslation( translateVec ); -} - -inline Transform3 & Transform3::setCol0( Vector3 _col0 ) -{ - mCol0 = _col0; - return *this; -} - -inline Transform3 & Transform3::setCol1( Vector3 _col1 ) -{ - mCol1 = _col1; - return *this; -} - -inline Transform3 & Transform3::setCol2( Vector3 _col2 ) -{ - mCol2 = _col2; - return *this; -} - -inline Transform3 & Transform3::setCol3( Vector3 _col3 ) -{ - mCol3 = _col3; - return *this; -} - -inline Transform3 & Transform3::setCol( int col, Vector3 vec ) -{ - *(&mCol0 + col) = vec; - return *this; -} - -inline Transform3 & Transform3::setRow( int row, Vector4 vec ) -{ - mCol0.setElem( row, vec.getElem( 0 ) ); - mCol1.setElem( row, vec.getElem( 1 ) ); - mCol2.setElem( row, vec.getElem( 2 ) ); - mCol3.setElem( row, vec.getElem( 3 ) ); - return *this; -} - -inline Transform3 & Transform3::setElem( int col, int row, float val ) -{ - (*this)[col].setElem(row, val); - return *this; -} - -inline float Transform3::getElem( int col, int row ) const -{ - return this->getCol( col ).getElem( row ); -} - -inline const Vector3 Transform3::getCol0( ) const -{ - return mCol0; -} - -inline const Vector3 Transform3::getCol1( ) const -{ - return mCol1; -} - -inline const Vector3 Transform3::getCol2( ) const -{ - return mCol2; -} - -inline const Vector3 Transform3::getCol3( ) const -{ - return mCol3; -} - -inline const Vector3 Transform3::getCol( int col ) const -{ - return *(&mCol0 + col); -} - -inline const Vector4 Transform3::getRow( int row ) const -{ - return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); -} - -inline Vector3 & Transform3::operator []( int col ) -{ - return *(&mCol0 + col); -} - -inline const Vector3 Transform3::operator []( int col ) const -{ - return *(&mCol0 + col); -} - -inline Transform3 & Transform3::operator =( const Transform3 & tfrm ) -{ - mCol0 = tfrm.mCol0; - mCol1 = tfrm.mCol1; - mCol2 = tfrm.mCol2; - mCol3 = tfrm.mCol3; - return *this; -} - -inline const Transform3 inverse( const Transform3 & tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp2 = _vmathVfCross( tfrm.getCol0().get128(), tfrm.getCol1().get128() ); - tmp0 = _vmathVfCross( tfrm.getCol1().get128(), tfrm.getCol2().get128() ); - tmp1 = _vmathVfCross( tfrm.getCol2().get128(), tfrm.getCol0().get128() ); - inv3 = negatef4( tfrm.getCol3().get128() ); - dot = _vmathVfDot3( tmp2, tfrm.getCol2().get128() ); - dot = spu_shuffle( dot, dot, shuffle_xxxx ); - invdet = recipf4( dot ); - tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); - tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); - inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); - xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); - inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); - zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); - inv3 = spu_mul( inv0, xxxx ); - inv3 = spu_madd( inv1, yyyy, inv3 ); - inv3 = spu_madd( inv2, zzzz, inv3 ); - inv0 = spu_mul( inv0, invdet ); - inv1 = spu_mul( inv1, invdet ); - inv2 = spu_mul( inv2, invdet ); - inv3 = spu_mul( inv3, invdet ); - return Transform3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ), - Vector3( inv3 ) - ); -} - -inline const Transform3 orthoInverse( const Transform3 & tfrm ) -{ - vec_float4 inv0, inv1, inv2, inv3; - vec_float4 tmp0, tmp1; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp0 = spu_shuffle( tfrm.getCol0().get128(), tfrm.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( tfrm.getCol0().get128(), tfrm.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); - inv3 = negatef4( tfrm.getCol3().get128() ); - inv0 = spu_shuffle( tmp0, tfrm.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); - xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); - inv1 = spu_shuffle( tmp0, tfrm.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); - inv2 = spu_shuffle( tmp1, tfrm.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); - zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); - inv3 = spu_mul( inv0, xxxx ); - inv3 = spu_madd( inv1, yyyy, inv3 ); - inv3 = spu_madd( inv2, zzzz, inv3 ); - return Transform3( - Vector3( inv0 ), - Vector3( inv1 ), - Vector3( inv2 ), - Vector3( inv3 ) - ); -} - -inline const Transform3 absPerElem( const Transform3 & tfrm ) -{ - return Transform3( - absPerElem( tfrm.getCol0() ), - absPerElem( tfrm.getCol1() ), - absPerElem( tfrm.getCol2() ), - absPerElem( tfrm.getCol3() ) - ); -} - -inline const Vector3 Transform3::operator *( Vector3 vec ) const -{ - vec_float4 res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); - res = spu_mul( mCol0.get128(), xxxx ); - res = spu_madd( mCol1.get128(), yyyy, res ); - res = spu_madd( mCol2.get128(), zzzz, res ); - return Vector3( res ); -} - -inline const Point3 Transform3::operator *( Point3 pnt ) const -{ - vec_float4 tmp0, tmp1, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - xxxx = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_xxxx ); - yyyy = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_yyyy ); - zzzz = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_zzzz ); - tmp0 = spu_mul( mCol0.get128(), xxxx ); - tmp1 = spu_mul( mCol1.get128(), yyyy ); - tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); - tmp1 = spu_add( mCol3.get128(), tmp1 ); - res = spu_add( tmp0, tmp1 ); - return Point3( res ); -} - -inline const Transform3 Transform3::operator *( const Transform3 & tfrm ) const -{ - return Transform3( - ( *this * tfrm.mCol0 ), - ( *this * tfrm.mCol1 ), - ( *this * tfrm.mCol2 ), - Vector3( ( *this * Point3( tfrm.mCol3 ) ) ) - ); -} - -inline Transform3 & Transform3::operator *=( const Transform3 & tfrm ) -{ - *this = *this * tfrm; - return *this; -} - -inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ) -{ - return Transform3( - mulPerElem( tfrm0.getCol0(), tfrm1.getCol0() ), - mulPerElem( tfrm0.getCol1(), tfrm1.getCol1() ), - mulPerElem( tfrm0.getCol2(), tfrm1.getCol2() ), - mulPerElem( tfrm0.getCol3(), tfrm1.getCol3() ) - ); -} - -inline const Transform3 Transform3::identity( ) -{ - return Transform3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ), - Vector3( 0.0f ) - ); -} - -inline Transform3 & Transform3::setUpper3x3( const Matrix3 & tfrm ) -{ - mCol0 = tfrm.getCol0(); - mCol1 = tfrm.getCol1(); - mCol2 = tfrm.getCol2(); - return *this; -} - -inline const Matrix3 Transform3::getUpper3x3( ) const -{ - return Matrix3( mCol0, mCol1, mCol2 ); -} - -inline Transform3 & Transform3::setTranslation( Vector3 translateVec ) -{ - mCol3 = translateVec; - return *this; -} - -inline const Vector3 Transform3::getTranslation( ) const -{ - return mCol3; -} - -inline const Transform3 Transform3::rotationX( float radians ) -{ - vec_float4 s, c, res1, res2; - vec_uint4 select_y, select_z; - vec_float4 zero; - select_y = (vec_uint4)spu_maskb(0x0f00); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res1 = spu_sel( zero, c, select_y ); - res1 = spu_sel( res1, s, select_z ); - res2 = spu_sel( zero, negatef4(s), select_y ); - res2 = spu_sel( res2, c, select_z ); - return Transform3( - Vector3::xAxis( ), - Vector3( res1 ), - Vector3( res2 ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationY( float radians ) -{ - vec_float4 s, c, res0, res2; - vec_uint4 select_x, select_z; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_z = (vec_uint4)spu_maskb(0x00f0); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, negatef4(s), select_z ); - res2 = spu_sel( zero, s, select_x ); - res2 = spu_sel( res2, c, select_z ); - return Transform3( - Vector3( res0 ), - Vector3::yAxis( ), - Vector3( res2 ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationZ( float radians ) -{ - vec_float4 s, c, res0, res1; - vec_uint4 select_x, select_y; - vec_float4 zero; - select_x = (vec_uint4)spu_maskb(0xf000); - select_y = (vec_uint4)spu_maskb(0x0f00); - zero = spu_splats(0.0f); - sincosf4( spu_splats(radians), &s, &c ); - res0 = spu_sel( zero, c, select_x ); - res0 = spu_sel( res0, s, select_y ); - res1 = spu_sel( zero, negatef4(s), select_x ); - res1 = spu_sel( res1, c, select_y ); - return Transform3( - Vector3( res0 ), - Vector3( res1 ), - Vector3::zAxis( ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotationZYX( Vector3 radiansXYZ ) -{ - vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - angles = radiansXYZ.get128(); - angles = spu_insert( 0.0f, angles, 3 ); - sincosf4( angles, &s, &c ); - negS = negatef4( s ); - Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); - Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); - Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); - Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); - X0 = spu_shuffle( s, s, shuffle_xxxx ); - X1 = spu_shuffle( c, c, shuffle_xxxx ); - tmp = spu_mul( Z0, Y1 ); - return Transform3( - Vector3( spu_mul( Z0, Y0 ) ), - Vector3( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), - Vector3( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 Transform3::rotation( float radians, Vector3 unitVec ) -{ - return Transform3( Matrix3::rotation( radians, unitVec ), Vector3( 0.0f ) ); -} - -inline const Transform3 Transform3::rotation( Quat unitQuat ) -{ - return Transform3( Matrix3( unitQuat ), Vector3( 0.0f ) ); -} - -inline const Transform3 Transform3::scale( Vector3 scaleVec ) -{ - vec_float4 zero = spu_splats(0.0f); - return Transform3( - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), - Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ), - Vector3( 0.0f ) - ); -} - -inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ) -{ - return Transform3( - ( tfrm.getCol0() * scaleVec.getX( ) ), - ( tfrm.getCol1() * scaleVec.getY( ) ), - ( tfrm.getCol2() * scaleVec.getZ( ) ), - tfrm.getCol3() - ); -} - -inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ) -{ - return Transform3( - mulPerElem( tfrm.getCol0(), scaleVec ), - mulPerElem( tfrm.getCol1(), scaleVec ), - mulPerElem( tfrm.getCol2(), scaleVec ), - mulPerElem( tfrm.getCol3(), scaleVec ) - ); -} - -inline const Transform3 Transform3::translation( Vector3 translateVec ) -{ - return Transform3( - Vector3::xAxis( ), - Vector3::yAxis( ), - Vector3::zAxis( ), - translateVec - ); -} - -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ) -{ - return Transform3( - select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), - select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), - select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), - select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) - ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( const Transform3 & tfrm ) -{ - print( tfrm.getRow( 0 ) ); - print( tfrm.getRow( 1 ) ); - print( tfrm.getRow( 2 ) ); -} - -inline void print( const Transform3 & tfrm, const char * name ) -{ - printf("%s:\n", name); - print( tfrm ); -} - -#endif - -inline Quat::Quat( const Matrix3 & tfrm ) -{ - vec_float4 res; - vec_float4 col0, col1, col2; - vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; - vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; - vec_float4 radicand, invSqrt, scale; - vec_float4 res0, res1, res2, res3; - vec_float4 xx, yy, zz; - vec_uint4 select_x = (vec_uint4)spu_maskb( 0xf000 ); - vec_uint4 select_y = (vec_uint4)spu_maskb( 0x0f00 ); - vec_uint4 select_z = (vec_uint4)spu_maskb( 0x00f0 ); - vec_uint4 select_w = (vec_uint4)spu_maskb( 0x000f ); - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((unsigned int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((unsigned int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((unsigned int)0x08090a0b); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((unsigned int)0x0c0d0e0f); - - col0 = tfrm.getCol0().get128(); - col1 = tfrm.getCol1().get128(); - col2 = tfrm.getCol2().get128(); - - /* four cases: */ - /* trace > 0 */ - /* else */ - /* xx largest diagonal element */ - /* yy largest diagonal element */ - /* zz largest diagonal element */ - - /* compute quaternion for each case */ - - xx_yy = spu_sel( col0, col1, select_y ); - xx_yy_zz_xx = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_XYCX ); - yy_zz_xx_yy = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_YCXY ); - zz_xx_yy_zz = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_CXYC ); - - diagSum = spu_add( spu_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - diagDiff = spu_sub( spu_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); - radicand = spu_add( spu_sel( diagDiff, diagSum, select_w ), spu_splats(1.0f) ); - invSqrt = rsqrtf4( radicand ); - - zy_xz_yx = spu_sel( col0, col1, select_z ); - zy_xz_yx = spu_shuffle( zy_xz_yx, col2, _VECTORMATH_SHUF_ZAY0 ); - yz_zx_xy = spu_sel( col0, col1, select_x ); - yz_zx_xy = spu_shuffle( yz_zx_xy, col2, _VECTORMATH_SHUF_BZX0 ); - - sum = spu_add( zy_xz_yx, yz_zx_xy ); - diff = spu_sub( zy_xz_yx, yz_zx_xy ); - - scale = spu_mul( invSqrt, spu_splats(0.5f) ); - res0 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_0ZYA ); - res1 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_Z0XB ); - res2 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_YX0C ); - res3 = diff; - res0 = spu_sel( res0, radicand, select_x ); - res1 = spu_sel( res1, radicand, select_y ); - res2 = spu_sel( res2, radicand, select_z ); - res3 = spu_sel( res3, radicand, select_w ); - res0 = spu_mul( res0, spu_shuffle( scale, scale, shuffle_xxxx ) ); - res1 = spu_mul( res1, spu_shuffle( scale, scale, shuffle_yyyy ) ); - res2 = spu_mul( res2, spu_shuffle( scale, scale, shuffle_zzzz ) ); - res3 = spu_mul( res3, spu_shuffle( scale, scale, shuffle_wwww ) ); - - /* determine case and select answer */ - - xx = spu_shuffle( col0, col0, shuffle_xxxx ); - yy = spu_shuffle( col1, col1, shuffle_yyyy ); - zz = spu_shuffle( col2, col2, shuffle_zzzz ); - res = spu_sel( res0, res1, spu_cmpgt( yy, xx ) ); - res = spu_sel( res, res2, spu_and( spu_cmpgt( zz, xx ), spu_cmpgt( zz, yy ) ) ); - res = spu_sel( res, res3, spu_cmpgt( spu_shuffle( diagSum, diagSum, shuffle_xxxx ), spu_splats(0.0f) ) ); - mVec128 = res; -} - -inline const Matrix3 outer( Vector3 tfrm0, Vector3 tfrm1 ) -{ - return Matrix3( - ( tfrm0 * tfrm1.getX( ) ), - ( tfrm0 * tfrm1.getY( ) ), - ( tfrm0 * tfrm1.getZ( ) ) - ); -} - -inline const Matrix4 outer( Vector4 tfrm0, Vector4 tfrm1 ) -{ - return Matrix4( - ( tfrm0 * tfrm1.getX( ) ), - ( tfrm0 * tfrm1.getY( ) ), - ( tfrm0 * tfrm1.getZ( ) ), - ( tfrm0 * tfrm1.getW( ) ) - ); -} - -inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ) -{ - vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; - vec_float4 xxxx, yyyy, zzzz; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); - tmp1 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); - xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); - mcol0 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); - mcol1 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); - mcol2 = spu_shuffle( tmp1, mat.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); - yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); - res = spu_mul( mcol0, xxxx ); - zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); - res = spu_madd( mcol1, yyyy, res ); - res = spu_madd( mcol2, zzzz, res ); - return Vector3( res ); -} - -inline const Matrix3 crossMatrix( Vector3 vec ) -{ - vec_float4 neg, res0, res1, res2; - neg = negatef4( vec.get128() ); - res0 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_0ZB0 ); - res1 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_C0X0 ); - res2 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_YA00 ); - return Matrix3( - Vector3( res0 ), - Vector3( res1 ), - Vector3( res2 ) - ); -} - -inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ) -{ - return Matrix3( cross( vec, mat.getCol0() ), cross( vec, mat.getCol1() ), cross( vec, mat.getCol2() ) ); -} - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_MAT_AOS_CPP_H +#define _VECTORMATH_MAT_AOS_CPP_H + +namespace Vectormath { +namespace Aos { + +//----------------------------------------------------------------------------- +// Constants +// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + +#define _VECTORMATH_SHUF_XAYB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_ZCWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_ZBW0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XCY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XYAB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_ZWCD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_0ZB0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_C0X0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_YA00 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_XAZC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_YXWZ ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_Z }) +#define _VECTORMATH_SHUF_YBWD ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_D }) +#define _VECTORMATH_SHUF_XYCX ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X }) +#define _VECTORMATH_SHUF_YCXY ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y }) +#define _VECTORMATH_SHUF_CXYC ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_ZAY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_BZX0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_0ZYA ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_A }) +#define _VECTORMATH_SHUF_Z0XB ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_B }) +#define _VECTORMATH_SHUF_YX0C ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_0, _VECTORMATH_SHUF_C }) +#define _VECTORMATH_SHUF_CZD0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_C, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_D, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_SHUF_BBY0 ((vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_0 }) +#define _VECTORMATH_PI_OVER_2 1.570796327f + +//----------------------------------------------------------------------------- +// Definitions + +inline Matrix3::Matrix3( const Matrix3 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; +} + +inline Matrix3::Matrix3( float scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); +} + +inline Matrix3::Matrix3( Quat unitQuat ) +{ + vec_float4 xyzw_2, wwww, yzxw, zxyw, yzxw_2, zxyw_2; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + vec_uint4 select_x = (vec_uint4)spu_maskb(0xf000); + vec_uint4 select_z = (vec_uint4)spu_maskb(0x00f0); + xyzw_2 = spu_add( unitQuat.get128(), unitQuat.get128() ); + wwww = spu_shuffle( unitQuat.get128(), unitQuat.get128(), shuffle_wwww ); + yzxw = spu_shuffle( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_SHUF_YZXW ); + zxyw = spu_shuffle( unitQuat.get128(), unitQuat.get128(), _VECTORMATH_SHUF_ZXYW ); + yzxw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_YZXW ); + zxyw_2 = spu_shuffle( xyzw_2, xyzw_2, _VECTORMATH_SHUF_ZXYW ); + tmp0 = spu_mul( yzxw_2, wwww ); + tmp1 = spu_nmsub( yzxw, yzxw_2, spu_splats(1.0f) ); + tmp2 = spu_mul( yzxw, xyzw_2 ); + tmp0 = spu_madd( zxyw, xyzw_2, tmp0 ); + tmp1 = spu_nmsub( zxyw, zxyw_2, tmp1 ); + tmp2 = spu_nmsub( zxyw_2, wwww, tmp2 ); + tmp3 = spu_sel( tmp0, tmp1, select_x ); + tmp4 = spu_sel( tmp1, tmp2, select_x ); + tmp5 = spu_sel( tmp2, tmp0, select_x ); + mCol0 = Vector3( spu_sel( tmp3, tmp2, select_z ) ); + mCol1 = Vector3( spu_sel( tmp4, tmp0, select_z ) ); + mCol2 = Vector3( spu_sel( tmp5, tmp1, select_z ) ); +} + +inline Matrix3::Matrix3( Vector3 _col0, Vector3 _col1, Vector3 _col2 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; +} + +inline Matrix3 & Matrix3::setCol0( Vector3 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Matrix3 & Matrix3::setCol1( Vector3 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Matrix3 & Matrix3::setCol2( Vector3 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Matrix3 & Matrix3::setCol( int col, Vector3 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Matrix3 & Matrix3::setRow( int row, Vector3 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + return *this; +} + +inline Matrix3 & Matrix3::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline float Matrix3::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector3 Matrix3::getCol0( ) const +{ + return mCol0; +} + +inline const Vector3 Matrix3::getCol1( ) const +{ + return mCol1; +} + +inline const Vector3 Matrix3::getCol2( ) const +{ + return mCol2; +} + +inline const Vector3 Matrix3::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector3 Matrix3::getRow( int row ) const +{ + return Vector3( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ) ); +} + +inline Vector3 & Matrix3::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector3 Matrix3::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Matrix3 & Matrix3::operator =( const Matrix3 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + return *this; +} + +inline const Matrix3 transpose( const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, res0, res1, res2; + tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); + res0 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); + res1 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); + res2 = spu_shuffle( tmp1, mat.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 inverse( const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet, inv0, inv1, inv2; + tmp2 = _vmathVfCross( mat.getCol0().get128(), mat.getCol1().get128() ); + tmp0 = _vmathVfCross( mat.getCol1().get128(), mat.getCol2().get128() ); + tmp1 = _vmathVfCross( mat.getCol2().get128(), mat.getCol0().get128() ); + dot = _vmathVfDot3( tmp2, mat.getCol2().get128() ); + dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); + invdet = recipf4( dot ); + tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); + tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); + inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); + inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); + inv0 = spu_mul( inv0, invdet ); + inv1 = spu_mul( inv1, invdet ); + inv2 = spu_mul( inv2, invdet ); + return Matrix3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ) + ); +} + +inline float determinant( const Matrix3 & mat ) +{ + return dot( mat.getCol2(), cross( mat.getCol0(), mat.getCol1() ) ); +} + +inline const Matrix3 Matrix3::operator +( const Matrix3 & mat ) const +{ + return Matrix3( + ( mCol0 + mat.mCol0 ), + ( mCol1 + mat.mCol1 ), + ( mCol2 + mat.mCol2 ) + ); +} + +inline const Matrix3 Matrix3::operator -( const Matrix3 & mat ) const +{ + return Matrix3( + ( mCol0 - mat.mCol0 ), + ( mCol1 - mat.mCol1 ), + ( mCol2 - mat.mCol2 ) + ); +} + +inline Matrix3 & Matrix3::operator +=( const Matrix3 & mat ) +{ + *this = *this + mat; + return *this; +} + +inline Matrix3 & Matrix3::operator -=( const Matrix3 & mat ) +{ + *this = *this - mat; + return *this; +} + +inline const Matrix3 Matrix3::operator -( ) const +{ + return Matrix3( + ( -mCol0 ), + ( -mCol1 ), + ( -mCol2 ) + ); +} + +inline const Matrix3 absPerElem( const Matrix3 & mat ) +{ + return Matrix3( + absPerElem( mat.getCol0() ), + absPerElem( mat.getCol1() ), + absPerElem( mat.getCol2() ) + ); +} + +inline const Matrix3 Matrix3::operator *( float scalar ) const +{ + return Matrix3( + ( mCol0 * scalar ), + ( mCol1 * scalar ), + ( mCol2 * scalar ) + ); +} + +inline Matrix3 & Matrix3::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Matrix3 operator *( float scalar, const Matrix3 & mat ) +{ + return mat * scalar; +} + +inline const Vector3 Matrix3::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); + res = spu_mul( mCol0.get128(), xxxx ); + res = spu_madd( mCol1.get128(), yyyy, res ); + res = spu_madd( mCol2.get128(), zzzz, res ); + return Vector3( res ); +} + +inline const Matrix3 Matrix3::operator *( const Matrix3 & mat ) const +{ + return Matrix3( + ( *this * mat.mCol0 ), + ( *this * mat.mCol1 ), + ( *this * mat.mCol2 ) + ); +} + +inline Matrix3 & Matrix3::operator *=( const Matrix3 & mat ) +{ + *this = *this * mat; + return *this; +} + +inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ) +{ + return Matrix3( + mulPerElem( mat0.getCol0(), mat1.getCol0() ), + mulPerElem( mat0.getCol1(), mat1.getCol1() ), + mulPerElem( mat0.getCol2(), mat1.getCol2() ) + ); +} + +inline const Matrix3 Matrix3::identity( ) +{ + return Matrix3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ) + ); +} + +inline const Matrix3 Matrix3::rotationX( float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + return Matrix3( + Vector3::xAxis( ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 Matrix3::rotationY( float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + return Matrix3( + Vector3( res0 ), + Vector3::yAxis( ), + Vector3( res2 ) + ); +} + +inline const Matrix3 Matrix3::rotationZ( float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3::zAxis( ) + ); +} + +inline const Matrix3 Matrix3::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ.get128(); + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + return Matrix3( + Vector3( spu_mul( Z0, Y0 ) ), + Vector3( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), + Vector3( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ) + ); +} + +inline const Matrix3 Matrix3::rotation( float radians, Vector3 unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + axis = unitVec.get128(); + sincosf4( spu_splats( radians ), &s, &c ); + xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); + yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); + zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); + oneMinusC = spu_sub( spu_splats(1.0f), c ); + axisS = spu_mul( axis, s ); + negAxisS = negatef4( axisS ); + tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); + tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); + tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); + tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); + tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); + tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); + return Matrix3( + Vector3( spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ) ), + Vector3( spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ) ), + Vector3( spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ) ) + ); +} + +inline const Matrix3 Matrix3::rotation( Quat unitQuat ) +{ + return Matrix3( unitQuat ); +} + +inline const Matrix3 Matrix3::scale( Vector3 scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + return Matrix3( + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ) + ); +} + +inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ) +{ + return Matrix3( + ( mat.getCol0() * scaleVec.getX( ) ), + ( mat.getCol1() * scaleVec.getY( ) ), + ( mat.getCol2() * scaleVec.getZ( ) ) + ); +} + +inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ) +{ + return Matrix3( + mulPerElem( mat.getCol0(), scaleVec ), + mulPerElem( mat.getCol1(), scaleVec ), + mulPerElem( mat.getCol2(), scaleVec ) + ); +} + +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ) +{ + return Matrix3( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Matrix3 & mat ) +{ + print( mat.getRow( 0 ) ); + print( mat.getRow( 1 ) ); + print( mat.getRow( 2 ) ); +} + +inline void print( const Matrix3 & mat, const char * name ) +{ + printf("%s:\n", name); + print( mat ); +} + +#endif + +inline Matrix4::Matrix4( const Matrix4 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + mCol3 = mat.mCol3; +} + +inline Matrix4::Matrix4( float scalar ) +{ + mCol0 = Vector4( scalar ); + mCol1 = Vector4( scalar ); + mCol2 = Vector4( scalar ); + mCol3 = Vector4( scalar ); +} + +inline Matrix4::Matrix4( const Transform3 & mat ) +{ + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( mat.getCol3(), 1.0f ); +} + +inline Matrix4::Matrix4( Vector4 _col0, Vector4 _col1, Vector4 _col2, Vector4 _col3 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; + mCol3 = _col3; +} + +inline Matrix4::Matrix4( const Matrix3 & mat, Vector3 translateVec ) +{ + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( translateVec, 1.0f ); +} + +inline Matrix4::Matrix4( Quat unitQuat, Vector3 translateVec ) +{ + Matrix3 mat; + mat = Matrix3( unitQuat ); + mCol0 = Vector4( mat.getCol0(), 0.0f ); + mCol1 = Vector4( mat.getCol1(), 0.0f ); + mCol2 = Vector4( mat.getCol2(), 0.0f ); + mCol3 = Vector4( translateVec, 1.0f ); +} + +inline Matrix4 & Matrix4::setCol0( Vector4 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Matrix4 & Matrix4::setCol1( Vector4 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Matrix4 & Matrix4::setCol2( Vector4 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Matrix4 & Matrix4::setCol3( Vector4 _col3 ) +{ + mCol3 = _col3; + return *this; +} + +inline Matrix4 & Matrix4::setCol( int col, Vector4 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Matrix4 & Matrix4::setRow( int row, Vector4 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + mCol3.setElem( row, vec.getElem( 3 ) ); + return *this; +} + +inline Matrix4 & Matrix4::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline float Matrix4::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector4 Matrix4::getCol0( ) const +{ + return mCol0; +} + +inline const Vector4 Matrix4::getCol1( ) const +{ + return mCol1; +} + +inline const Vector4 Matrix4::getCol2( ) const +{ + return mCol2; +} + +inline const Vector4 Matrix4::getCol3( ) const +{ + return mCol3; +} + +inline const Vector4 Matrix4::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector4 Matrix4::getRow( int row ) const +{ + return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); +} + +inline Vector4 & Matrix4::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector4 Matrix4::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Matrix4 & Matrix4::operator =( const Matrix4 & mat ) +{ + mCol0 = mat.mCol0; + mCol1 = mat.mCol1; + mCol2 = mat.mCol2; + mCol3 = mat.mCol3; + return *this; +} + +inline const Matrix4 transpose( const Matrix4 & mat ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, res0, res1, res2, res3; + tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat.getCol1().get128(), mat.getCol3().get128(), _VECTORMATH_SHUF_XAYB ); + tmp2 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); + tmp3 = spu_shuffle( mat.getCol1().get128(), mat.getCol3().get128(), _VECTORMATH_SHUF_ZCWD ); + res0 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_XAYB ); + res1 = spu_shuffle( tmp0, tmp1, _VECTORMATH_SHUF_ZCWD ); + res2 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_XAYB ); + res3 = spu_shuffle( tmp2, tmp3, _VECTORMATH_SHUF_ZCWD ); + return Matrix4( + Vector4( res0 ), + Vector4( res1 ), + Vector4( res2 ), + Vector4( res3 ) + ); +} + +inline const Matrix4 inverse( const Matrix4 & mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 in0, in1, in2, in3; + vec_float4 tmp0, tmp1, tmp2, tmp3; + vec_float4 cof0, cof1, cof2, cof3; + vec_float4 t0, t1, t2, t3; + vec_float4 t01, t02, t03, t12, t23; + vec_float4 t1r, t2r; + vec_float4 t01r, t02r, t03r, t12r, t23r; + vec_float4 t1r3, t1r3r; + vec_float4 det, det1, det2, det3, invdet; + in0 = mat.getCol0().get128(); + in1 = mat.getCol1().get128(); + in2 = mat.getCol2().get128(); + in3 = mat.getCol3().get128(); + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ + tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ + tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ + tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ + t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ + t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ + t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ + t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = spu_mul(t2, t3); /* CL GP KD OH */ + t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ + cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ + cof1 = spu_mul(t0, t23); /* AGP ECL IOH MKD */ + t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ + cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ + cof1 = spu_msub(t0, t23r, cof1); /* AOH EKD IGP MCL - cof1 */ + cof1 = spu_rlqwbyte(cof1, 8); /* IGP MCL AOH EKD - IOH MKD AGP ECL */ + + t12 = spu_mul(t1, t2); /* JC NG BK FO */ + t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ + cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + cof3 = spu_mul(t0, t12); /* ANG EJC IFO MBK */ + t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ + cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + cof3 = spu_msub(t0, t12r, cof3); /* AFO EBK ING MJC - cof3 */ + cof3 = spu_rlqwbyte(cof3, 8); /* ING MJC AFO EBK - IFO MBK ANG EJC */ + t1r = spu_rlqwbyte(t1, 8); /* B F J N */ + t2r = spu_rlqwbyte(t2, 8); /* K O C G */ + t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ + t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ + cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + cof2 = spu_mul(t0, t1r3); /* AFP EBL INH MJD */ + t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ + cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + cof2 = spu_msub(t0, t1r3r, cof2); /* ANH EJD IFP MBL - cof2 */ + cof2 = spu_rlqwbyte(cof2, 8); /* IFP MBL ANH EJD - INH MJD AFP EBL */ + t01 = spu_mul(t0, t1); /* AJ EN IB MF */ + t01 = spu_shuffle(t01, t01, _VECTORMATH_SHUF_YXWZ); /* EN AJ MF IB */ + cof2 = spu_madd(t3, t01, cof2); /* LEN PAJ DMF HIB + cof2 */ + cof3 = spu_msub(t2r, t01, cof3); /* KEN OAJ CMF GIB - cof3 */ + t01r = spu_rlqwbyte(t01, 8); /* MF IB EN AJ */ + cof2 = spu_msub(t3, t01r, cof2); /* LMF PIB DEN HAJ - cof2 */ + cof3 = spu_nmsub(t2r, t01r, cof3); /* cof3 - KMF OIB CEN GAJ */ + t03 = spu_mul(t0, t3); /* AL EP ID MH */ + t03 = spu_shuffle(t03, t03, _VECTORMATH_SHUF_YXWZ); /* EP AL MH ID */ + cof1 = spu_nmsub(t2r, t03, cof1); /* cof1 - KEP OAL CMH GID */ + cof2 = spu_madd(t1, t03, cof2); /* JEP NAL BMH FID + cof2 */ + t03r = spu_rlqwbyte(t03, 8); /* MH ID EP AL */ + cof1 = spu_madd(t2r, t03r, cof1); /* KMH OID CEP GAL + cof1 */ + cof2 = spu_nmsub(t1, t03r, cof2); /* cof2 - JMH NID BEP FAL */ + t02 = spu_mul(t0, t2r); /* AK EO IC MG */ + t02 = spu_shuffle(t02, t02, _VECTORMATH_SHUF_YXWZ); /* E0 AK MG IC */ + cof1 = spu_madd(t3, t02, cof1); /* LEO PAK DMG HIC + cof1 */ + cof3 = spu_nmsub(t1, t02, cof3); /* cof3 - JEO NAK BMG FIC */ + t02r = spu_rlqwbyte(t02, 8); /* MG IC EO AK */ + cof1 = spu_nmsub(t3, t02r, cof1); /* cof1 - LMG PIC DEO HAK */ + cof3 = spu_madd(t1, t02r, cof3); /* JMG NIC BEO FAK + cof3 */ + /* Compute the determinant of the matrix + * + * det = sum_across(t0 * cof0); + * + * We perform a sum across the entire vector so that + * we don't have to splat the result when multiplying the + * cofactors by the inverse of the determinant. + */ + det = spu_mul(t0, cof0); + det1 = spu_rlqwbyte(det, 4); + det2 = spu_rlqwbyte(det, 8); + det3 = spu_rlqwbyte(det, 12); + det = spu_add(det, det1); + det2 = spu_add(det2, det3); + det = spu_add(det, det2); + /* Compute the reciprocal of the determinant. + */ + invdet = recipf4(det); + /* Multiply the cofactors by the reciprocal of the determinant. + */ + return Matrix4( + Vector4( spu_mul(cof0, invdet) ), + Vector4( spu_mul(cof1, invdet) ), + Vector4( spu_mul(cof2, invdet) ), + Vector4( spu_mul(cof3, invdet) ) + ); +} + +inline const Matrix4 affineInverse( const Matrix4 & mat ) +{ + Transform3 affineMat; + affineMat.setCol0( mat.getCol0().getXYZ( ) ); + affineMat.setCol1( mat.getCol1().getXYZ( ) ); + affineMat.setCol2( mat.getCol2().getXYZ( ) ); + affineMat.setCol3( mat.getCol3().getXYZ( ) ); + return Matrix4( inverse( affineMat ) ); +} + +inline const Matrix4 orthoInverse( const Matrix4 & mat ) +{ + Transform3 affineMat; + affineMat.setCol0( mat.getCol0().getXYZ( ) ); + affineMat.setCol1( mat.getCol1().getXYZ( ) ); + affineMat.setCol2( mat.getCol2().getXYZ( ) ); + affineMat.setCol3( mat.getCol3().getXYZ( ) ); + return Matrix4( orthoInverse( affineMat ) ); +} + +inline float determinant( const Matrix4 & mat ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 in0, in1, in2, in3; + vec_float4 tmp0, tmp1, tmp2, tmp3; + vec_float4 cof0; + vec_float4 t0, t1, t2, t3; + vec_float4 t12, t23; + vec_float4 t1r, t2r; + vec_float4 t12r, t23r; + vec_float4 t1r3, t1r3r; + in0 = mat.getCol0().get128(); + in1 = mat.getCol1().get128(); + in2 = mat.getCol2().get128(); + in3 = mat.getCol3().get128(); + /* Perform transform of the input matrix of the form: + * A B C D + * E F G H + * I J K L + * M N O P + * + * The pseudo transpose of the input matrix is trans: + * A E I M + * J N B F + * C G K O + * L P D H + */ + tmp0 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_XAZC); /* A E C G */ + tmp1 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_XAZC); /* I M K O */ + tmp2 = spu_shuffle(in0, in1, _VECTORMATH_SHUF_YBWD); /* B F D H */ + tmp3 = spu_shuffle(in2, in3, _VECTORMATH_SHUF_YBWD); /* J N L P */ + t0 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_XYAB); /* A E I M */ + t1 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_XYAB); /* J N B F */ + t2 = spu_shuffle(tmp0, tmp1, _VECTORMATH_SHUF_ZWCD); /* C G K O */ + t3 = spu_shuffle(tmp3, tmp2, _VECTORMATH_SHUF_ZWCD); /* L P D H */ + /* Generate a cofactor matrix. The computed cofactors reside in + * cof0, cof1, cof2, cof3. + */ + t23 = spu_mul(t2, t3); /* CL GP KD OH */ + t23 = spu_shuffle(t23, t23, _VECTORMATH_SHUF_YXWZ); /* GP CL OH KD */ + cof0 = spu_mul(t1, t23); /* JGP NCL BOH FKD */ + t23r = spu_rlqwbyte(t23, 8); /* OH KD GP CL */ + cof0 = spu_msub(t1, t23r, cof0); /* JOH NKD BGP FCL - cof0 */ + + t12 = spu_mul(t1, t2); /* JC NG BK FO */ + t12 = spu_shuffle(t12, t12, _VECTORMATH_SHUF_YXWZ); /* NG JC FO BK */ + cof0 = spu_madd(t3, t12, cof0); /* LNG PJC DFO HBK + cof0 */ + t12r = spu_rlqwbyte(t12, 8); /* FO BK NG JC */ + cof0 = spu_nmsub(t3, t12r, cof0); /* cof0 - LFO PBK DNG HJC */ + t1r = spu_rlqwbyte(t1, 8); /* B F J N */ + t2r = spu_rlqwbyte(t2, 8); /* K O C G */ + t1r3 = spu_mul(t1r, t3); /* BL FP JD NH */ + t1r3 = spu_shuffle(t1r3, t1r3, _VECTORMATH_SHUF_YXWZ); /* FP BL NH JD */ + cof0 = spu_madd(t2r, t1r3, cof0); /* KFP OBL CNH GJD + cof0 */ + t1r3r = spu_rlqwbyte(t1r3, 8); /* NH JD FP BL */ + cof0 = spu_nmsub(t2r, t1r3r, cof0); /* cof0 - KNH OJD CFP GBL */ + return spu_extract( _vmathVfDot4(t0,cof0), 0 ); +} + +inline const Matrix4 Matrix4::operator +( const Matrix4 & mat ) const +{ + return Matrix4( + ( mCol0 + mat.mCol0 ), + ( mCol1 + mat.mCol1 ), + ( mCol2 + mat.mCol2 ), + ( mCol3 + mat.mCol3 ) + ); +} + +inline const Matrix4 Matrix4::operator -( const Matrix4 & mat ) const +{ + return Matrix4( + ( mCol0 - mat.mCol0 ), + ( mCol1 - mat.mCol1 ), + ( mCol2 - mat.mCol2 ), + ( mCol3 - mat.mCol3 ) + ); +} + +inline Matrix4 & Matrix4::operator +=( const Matrix4 & mat ) +{ + *this = *this + mat; + return *this; +} + +inline Matrix4 & Matrix4::operator -=( const Matrix4 & mat ) +{ + *this = *this - mat; + return *this; +} + +inline const Matrix4 Matrix4::operator -( ) const +{ + return Matrix4( + ( -mCol0 ), + ( -mCol1 ), + ( -mCol2 ), + ( -mCol3 ) + ); +} + +inline const Matrix4 absPerElem( const Matrix4 & mat ) +{ + return Matrix4( + absPerElem( mat.getCol0() ), + absPerElem( mat.getCol1() ), + absPerElem( mat.getCol2() ), + absPerElem( mat.getCol3() ) + ); +} + +inline const Matrix4 Matrix4::operator *( float scalar ) const +{ + return Matrix4( + ( mCol0 * scalar ), + ( mCol1 * scalar ), + ( mCol2 * scalar ), + ( mCol3 * scalar ) + ); +} + +inline Matrix4 & Matrix4::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Matrix4 operator *( float scalar, const Matrix4 & mat ) +{ + return mat * scalar; +} + +inline const Vector4 Matrix4::operator *( Vector4 vec ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz, wwww; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); + wwww = spu_shuffle( vec.get128(), vec.get128(), shuffle_wwww ); + tmp0 = spu_mul( mCol0.get128(), xxxx ); + tmp1 = spu_mul( mCol1.get128(), yyyy ); + tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = spu_madd( mCol3.get128(), wwww, tmp1 ); + res = spu_add( tmp0, tmp1 ); + return Vector4( res ); +} + +inline const Vector4 Matrix4::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); + res = spu_mul( mCol0.get128(), xxxx ); + res = spu_madd( mCol1.get128(), yyyy, res ); + res = spu_madd( mCol2.get128(), zzzz, res ); + return Vector4( res ); +} + +inline const Vector4 Matrix4::operator *( Point3 pnt ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_zzzz ); + tmp0 = spu_mul( mCol0.get128(), xxxx ); + tmp1 = spu_mul( mCol1.get128(), yyyy ); + tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = spu_add( mCol3.get128(), tmp1 ); + res = spu_add( tmp0, tmp1 ); + return Vector4( res ); +} + +inline const Matrix4 Matrix4::operator *( const Matrix4 & mat ) const +{ + return Matrix4( + ( *this * mat.mCol0 ), + ( *this * mat.mCol1 ), + ( *this * mat.mCol2 ), + ( *this * mat.mCol3 ) + ); +} + +inline Matrix4 & Matrix4::operator *=( const Matrix4 & mat ) +{ + *this = *this * mat; + return *this; +} + +inline const Matrix4 Matrix4::operator *( const Transform3 & tfrm ) const +{ + return Matrix4( + ( *this * tfrm.getCol0() ), + ( *this * tfrm.getCol1() ), + ( *this * tfrm.getCol2() ), + ( *this * Point3( tfrm.getCol3() ) ) + ); +} + +inline Matrix4 & Matrix4::operator *=( const Transform3 & tfrm ) +{ + *this = *this * tfrm; + return *this; +} + +inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ) +{ + return Matrix4( + mulPerElem( mat0.getCol0(), mat1.getCol0() ), + mulPerElem( mat0.getCol1(), mat1.getCol1() ), + mulPerElem( mat0.getCol2(), mat1.getCol2() ), + mulPerElem( mat0.getCol3(), mat1.getCol3() ) + ); +} + +inline const Matrix4 Matrix4::identity( ) +{ + return Matrix4( + Vector4::xAxis( ), + Vector4::yAxis( ), + Vector4::zAxis( ), + Vector4::wAxis( ) + ); +} + +inline Matrix4 & Matrix4::setUpper3x3( const Matrix3 & mat3 ) +{ + mCol0.setXYZ( mat3.getCol0() ); + mCol1.setXYZ( mat3.getCol1() ); + mCol2.setXYZ( mat3.getCol2() ); + return *this; +} + +inline const Matrix3 Matrix4::getUpper3x3( ) const +{ + return Matrix3( + mCol0.getXYZ( ), + mCol1.getXYZ( ), + mCol2.getXYZ( ) + ); +} + +inline Matrix4 & Matrix4::setTranslation( Vector3 translateVec ) +{ + mCol3.setXYZ( translateVec ); + return *this; +} + +inline const Vector3 Matrix4::getTranslation( ) const +{ + return mCol3.getXYZ( ); +} + +inline const Matrix4 Matrix4::rotationX( float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + return Matrix4( + Vector4::xAxis( ), + Vector4( res1 ), + Vector4( res2 ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationY( float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + return Matrix4( + Vector4( res0 ), + Vector4::yAxis( ), + Vector4( res2 ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationZ( float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + return Matrix4( + Vector4( res0 ), + Vector4( res1 ), + Vector4::zAxis( ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ.get128(); + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + return Matrix4( + Vector4( spu_mul( Z0, Y0 ) ), + Vector4( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), + Vector4( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotation( float radians, Vector3 unitVec ) +{ + vec_float4 axis, s, c, oneMinusC, axisS, negAxisS, xxxx, yyyy, zzzz, tmp0, tmp1, tmp2, zeroW; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + axis = unitVec.get128(); + sincosf4( spu_splats( radians ), &s, &c ); + xxxx = spu_shuffle( axis, axis, shuffle_xxxx ); + yyyy = spu_shuffle( axis, axis, shuffle_yyyy ); + zzzz = spu_shuffle( axis, axis, shuffle_zzzz ); + oneMinusC = spu_sub( spu_splats(1.0f), c ); + axisS = spu_mul( axis, s ); + negAxisS = negatef4( axisS ); + tmp0 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_0ZB0 ); + tmp1 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_C0X0 ); + tmp2 = spu_shuffle( axisS, negAxisS, _VECTORMATH_SHUF_YA00 ); + tmp0 = spu_sel( tmp0, c, (vec_uint4)spu_maskb(0xf000) ); + tmp1 = spu_sel( tmp1, c, (vec_uint4)spu_maskb(0x0f00) ); + tmp2 = spu_sel( tmp2, c, (vec_uint4)spu_maskb(0x00f0) ); + zeroW = (vec_float4)spu_maskb(0x000f); + axis = spu_andc( axis, zeroW ); + return Matrix4( + Vector4( spu_madd( spu_mul( axis, xxxx ), oneMinusC, tmp0 ) ), + Vector4( spu_madd( spu_mul( axis, yyyy ), oneMinusC, tmp1 ) ), + Vector4( spu_madd( spu_mul( axis, zzzz ), oneMinusC, tmp2 ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 Matrix4::rotation( Quat unitQuat ) +{ + return Matrix4( Transform3::rotation( unitQuat ) ); +} + +inline const Matrix4 Matrix4::scale( Vector3 scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + return Matrix4( + Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), + Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), + Vector4( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ), + Vector4::wAxis( ) + ); +} + +inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ) +{ + return Matrix4( + ( mat.getCol0() * scaleVec.getX( ) ), + ( mat.getCol1() * scaleVec.getY( ) ), + ( mat.getCol2() * scaleVec.getZ( ) ), + mat.getCol3() + ); +} + +inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ) +{ + Vector4 scale4; + scale4 = Vector4( scaleVec, 1.0f ); + return Matrix4( + mulPerElem( mat.getCol0(), scale4 ), + mulPerElem( mat.getCol1(), scale4 ), + mulPerElem( mat.getCol2(), scale4 ), + mulPerElem( mat.getCol3(), scale4 ) + ); +} + +inline const Matrix4 Matrix4::translation( Vector3 translateVec ) +{ + return Matrix4( + Vector4::xAxis( ), + Vector4::yAxis( ), + Vector4::zAxis( ), + Vector4( translateVec, 1.0f ) + ); +} + +inline const Matrix4 Matrix4::lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ) +{ + Matrix4 m4EyeFrame; + Vector3 v3X, v3Y, v3Z; + v3Y = normalize( upVec ); + v3Z = normalize( ( eyePos - lookAtPos ) ); + v3X = normalize( cross( v3Y, v3Z ) ); + v3Y = cross( v3Z, v3X ); + m4EyeFrame = Matrix4( Vector4( v3X ), Vector4( v3Y ), Vector4( v3Z ), Vector4( eyePos ) ); + return orthoInverse( m4EyeFrame ); +} + +inline const Matrix4 Matrix4::perspective( float fovyRadians, float aspect, float zNear, float zFar ) +{ + float f, rangeInv; + vec_float4 zero, col0, col1, col2, col3; + f = tanf( _VECTORMATH_PI_OVER_2 - fovyRadians * 0.5f ); + rangeInv = 1.0f / ( zNear - zFar ); + zero = spu_splats(0.0f); + col0 = zero; + col1 = zero; + col2 = zero; + col3 = zero; + col0 = spu_insert( f / aspect, col0, 0 ); + col1 = spu_insert( f, col1, 1 ); + col2 = spu_insert( ( zNear + zFar ) * rangeInv, col2, 2 ); + col2 = spu_insert( -1.0f, col2, 3 ); + col3 = spu_insert( zNear * zFar * rangeInv * 2.0f, col3, 2 ); + return Matrix4( + Vector4( col0 ), + Vector4( col1 ), + Vector4( col2 ), + Vector4( col3 ) + ); +} + +inline const Matrix4 Matrix4::frustum( float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff; + vec_float4 diagonal, column, near2; + vec_float4 zero = spu_splats(0.0f); + lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); + lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); + diff = spu_sub( rtn, lbf ); + sum = spu_add( rtn, lbf ); + inv_diff = recipf4( diff ); + near2 = spu_splats( zNear ); + near2 = spu_add( near2, near2 ); + diagonal = spu_mul( near2, inv_diff ); + column = spu_mul( sum, inv_diff ); + return Matrix4( + Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ) ), + Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ) ), + Vector4( spu_sel( column, spu_splats(-1.0f), (vec_uint4)spu_maskb(0x000f) ) ), + Vector4( spu_sel( zero, spu_mul( diagonal, spu_splats(zFar) ), (vec_uint4)spu_maskb(0x00f0) ) ) + ); +} + +inline const Matrix4 Matrix4::orthographic( float left, float right, float bottom, float top, float zNear, float zFar ) +{ + /* function implementation based on code from STIDC SDK: */ + /* -------------------------------------------------------------- */ + /* PLEASE DO NOT MODIFY THIS SECTION */ + /* This prolog section is automatically generated. */ + /* */ + /* (C)Copyright */ + /* Sony Computer Entertainment, Inc., */ + /* Toshiba Corporation, */ + /* International Business Machines Corporation, */ + /* 2001,2002. */ + /* S/T/I Confidential Information */ + /* -------------------------------------------------------------- */ + vec_float4 lbf, rtn; + vec_float4 diff, sum, inv_diff, neg_inv_diff; + vec_float4 diagonal, column; + vec_float4 zero = spu_splats(0.0f); + lbf = spu_shuffle( spu_promote(left,0), spu_promote(zFar,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( spu_promote(right,0), spu_promote(zNear,0), _VECTORMATH_SHUF_XAYB ); + lbf = spu_shuffle( lbf, spu_promote(bottom,0), _VECTORMATH_SHUF_XAYB ); + rtn = spu_shuffle( rtn, spu_promote(top,0), _VECTORMATH_SHUF_XAYB ); + diff = spu_sub( rtn, lbf ); + sum = spu_add( rtn, lbf ); + inv_diff = recipf4( diff ); + neg_inv_diff = negatef4( inv_diff ); + diagonal = spu_add( inv_diff, inv_diff ); + column = spu_mul( sum, spu_sel( neg_inv_diff, inv_diff, (vec_uint4)spu_maskb(0x00f0) ) ); + return Matrix4( + Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0xf000) ) ), + Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x0f00) ) ), + Vector4( spu_sel( zero, diagonal, (vec_uint4)spu_maskb(0x00f0) ) ), + Vector4( spu_sel( column, spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ) ) + ); +} + +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ) +{ + return Matrix4( + select( mat0.getCol0(), mat1.getCol0(), select1 ), + select( mat0.getCol1(), mat1.getCol1(), select1 ), + select( mat0.getCol2(), mat1.getCol2(), select1 ), + select( mat0.getCol3(), mat1.getCol3(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Matrix4 & mat ) +{ + print( mat.getRow( 0 ) ); + print( mat.getRow( 1 ) ); + print( mat.getRow( 2 ) ); + print( mat.getRow( 3 ) ); +} + +inline void print( const Matrix4 & mat, const char * name ) +{ + printf("%s:\n", name); + print( mat ); +} + +#endif + +inline Transform3::Transform3( const Transform3 & tfrm ) +{ + mCol0 = tfrm.mCol0; + mCol1 = tfrm.mCol1; + mCol2 = tfrm.mCol2; + mCol3 = tfrm.mCol3; +} + +inline Transform3::Transform3( float scalar ) +{ + mCol0 = Vector3( scalar ); + mCol1 = Vector3( scalar ); + mCol2 = Vector3( scalar ); + mCol3 = Vector3( scalar ); +} + +inline Transform3::Transform3( Vector3 _col0, Vector3 _col1, Vector3 _col2, Vector3 _col3 ) +{ + mCol0 = _col0; + mCol1 = _col1; + mCol2 = _col2; + mCol3 = _col3; +} + +inline Transform3::Transform3( const Matrix3 & tfrm, Vector3 translateVec ) +{ + this->setUpper3x3( tfrm ); + this->setTranslation( translateVec ); +} + +inline Transform3::Transform3( Quat unitQuat, Vector3 translateVec ) +{ + this->setUpper3x3( Matrix3( unitQuat ) ); + this->setTranslation( translateVec ); +} + +inline Transform3 & Transform3::setCol0( Vector3 _col0 ) +{ + mCol0 = _col0; + return *this; +} + +inline Transform3 & Transform3::setCol1( Vector3 _col1 ) +{ + mCol1 = _col1; + return *this; +} + +inline Transform3 & Transform3::setCol2( Vector3 _col2 ) +{ + mCol2 = _col2; + return *this; +} + +inline Transform3 & Transform3::setCol3( Vector3 _col3 ) +{ + mCol3 = _col3; + return *this; +} + +inline Transform3 & Transform3::setCol( int col, Vector3 vec ) +{ + *(&mCol0 + col) = vec; + return *this; +} + +inline Transform3 & Transform3::setRow( int row, Vector4 vec ) +{ + mCol0.setElem( row, vec.getElem( 0 ) ); + mCol1.setElem( row, vec.getElem( 1 ) ); + mCol2.setElem( row, vec.getElem( 2 ) ); + mCol3.setElem( row, vec.getElem( 3 ) ); + return *this; +} + +inline Transform3 & Transform3::setElem( int col, int row, float val ) +{ + (*this)[col].setElem(row, val); + return *this; +} + +inline float Transform3::getElem( int col, int row ) const +{ + return this->getCol( col ).getElem( row ); +} + +inline const Vector3 Transform3::getCol0( ) const +{ + return mCol0; +} + +inline const Vector3 Transform3::getCol1( ) const +{ + return mCol1; +} + +inline const Vector3 Transform3::getCol2( ) const +{ + return mCol2; +} + +inline const Vector3 Transform3::getCol3( ) const +{ + return mCol3; +} + +inline const Vector3 Transform3::getCol( int col ) const +{ + return *(&mCol0 + col); +} + +inline const Vector4 Transform3::getRow( int row ) const +{ + return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); +} + +inline Vector3 & Transform3::operator []( int col ) +{ + return *(&mCol0 + col); +} + +inline const Vector3 Transform3::operator []( int col ) const +{ + return *(&mCol0 + col); +} + +inline Transform3 & Transform3::operator =( const Transform3 & tfrm ) +{ + mCol0 = tfrm.mCol0; + mCol1 = tfrm.mCol1; + mCol2 = tfrm.mCol2; + mCol3 = tfrm.mCol3; + return *this; +} + +inline const Transform3 inverse( const Transform3 & tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1, tmp2, tmp3, tmp4, dot, invdet; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp2 = _vmathVfCross( tfrm.getCol0().get128(), tfrm.getCol1().get128() ); + tmp0 = _vmathVfCross( tfrm.getCol1().get128(), tfrm.getCol2().get128() ); + tmp1 = _vmathVfCross( tfrm.getCol2().get128(), tfrm.getCol0().get128() ); + inv3 = negatef4( tfrm.getCol3().get128() ); + dot = _vmathVfDot3( tmp2, tfrm.getCol2().get128() ); + dot = spu_shuffle( dot, dot, shuffle_xxxx ); + invdet = recipf4( dot ); + tmp3 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_XAYB ); + tmp4 = spu_shuffle( tmp0, tmp2, _VECTORMATH_SHUF_ZCWD ); + inv0 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_XAYB ); + xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); + inv1 = spu_shuffle( tmp3, tmp1, _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp4, tmp1, _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); + zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); + inv3 = spu_mul( inv0, xxxx ); + inv3 = spu_madd( inv1, yyyy, inv3 ); + inv3 = spu_madd( inv2, zzzz, inv3 ); + inv0 = spu_mul( inv0, invdet ); + inv1 = spu_mul( inv1, invdet ); + inv2 = spu_mul( inv2, invdet ); + inv3 = spu_mul( inv3, invdet ); + return Transform3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ), + Vector3( inv3 ) + ); +} + +inline const Transform3 orthoInverse( const Transform3 & tfrm ) +{ + vec_float4 inv0, inv1, inv2, inv3; + vec_float4 tmp0, tmp1; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp0 = spu_shuffle( tfrm.getCol0().get128(), tfrm.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( tfrm.getCol0().get128(), tfrm.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); + inv3 = negatef4( tfrm.getCol3().get128() ); + inv0 = spu_shuffle( tmp0, tfrm.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); + xxxx = spu_shuffle( inv3, inv3, shuffle_xxxx ); + inv1 = spu_shuffle( tmp0, tfrm.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); + inv2 = spu_shuffle( tmp1, tfrm.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( inv3, inv3, shuffle_yyyy ); + zzzz = spu_shuffle( inv3, inv3, shuffle_zzzz ); + inv3 = spu_mul( inv0, xxxx ); + inv3 = spu_madd( inv1, yyyy, inv3 ); + inv3 = spu_madd( inv2, zzzz, inv3 ); + return Transform3( + Vector3( inv0 ), + Vector3( inv1 ), + Vector3( inv2 ), + Vector3( inv3 ) + ); +} + +inline const Transform3 absPerElem( const Transform3 & tfrm ) +{ + return Transform3( + absPerElem( tfrm.getCol0() ), + absPerElem( tfrm.getCol1() ), + absPerElem( tfrm.getCol2() ), + absPerElem( tfrm.getCol3() ) + ); +} + +inline const Vector3 Transform3::operator *( Vector3 vec ) const +{ + vec_float4 res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); + res = spu_mul( mCol0.get128(), xxxx ); + res = spu_madd( mCol1.get128(), yyyy, res ); + res = spu_madd( mCol2.get128(), zzzz, res ); + return Vector3( res ); +} + +inline const Point3 Transform3::operator *( Point3 pnt ) const +{ + vec_float4 tmp0, tmp1, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + xxxx = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_xxxx ); + yyyy = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_yyyy ); + zzzz = spu_shuffle( pnt.get128(), pnt.get128(), shuffle_zzzz ); + tmp0 = spu_mul( mCol0.get128(), xxxx ); + tmp1 = spu_mul( mCol1.get128(), yyyy ); + tmp0 = spu_madd( mCol2.get128(), zzzz, tmp0 ); + tmp1 = spu_add( mCol3.get128(), tmp1 ); + res = spu_add( tmp0, tmp1 ); + return Point3( res ); +} + +inline const Transform3 Transform3::operator *( const Transform3 & tfrm ) const +{ + return Transform3( + ( *this * tfrm.mCol0 ), + ( *this * tfrm.mCol1 ), + ( *this * tfrm.mCol2 ), + Vector3( ( *this * Point3( tfrm.mCol3 ) ) ) + ); +} + +inline Transform3 & Transform3::operator *=( const Transform3 & tfrm ) +{ + *this = *this * tfrm; + return *this; +} + +inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ) +{ + return Transform3( + mulPerElem( tfrm0.getCol0(), tfrm1.getCol0() ), + mulPerElem( tfrm0.getCol1(), tfrm1.getCol1() ), + mulPerElem( tfrm0.getCol2(), tfrm1.getCol2() ), + mulPerElem( tfrm0.getCol3(), tfrm1.getCol3() ) + ); +} + +inline const Transform3 Transform3::identity( ) +{ + return Transform3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ), + Vector3( 0.0f ) + ); +} + +inline Transform3 & Transform3::setUpper3x3( const Matrix3 & tfrm ) +{ + mCol0 = tfrm.getCol0(); + mCol1 = tfrm.getCol1(); + mCol2 = tfrm.getCol2(); + return *this; +} + +inline const Matrix3 Transform3::getUpper3x3( ) const +{ + return Matrix3( mCol0, mCol1, mCol2 ); +} + +inline Transform3 & Transform3::setTranslation( Vector3 translateVec ) +{ + mCol3 = translateVec; + return *this; +} + +inline const Vector3 Transform3::getTranslation( ) const +{ + return mCol3; +} + +inline const Transform3 Transform3::rotationX( float radians ) +{ + vec_float4 s, c, res1, res2; + vec_uint4 select_y, select_z; + vec_float4 zero; + select_y = (vec_uint4)spu_maskb(0x0f00); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res1 = spu_sel( zero, c, select_y ); + res1 = spu_sel( res1, s, select_z ); + res2 = spu_sel( zero, negatef4(s), select_y ); + res2 = spu_sel( res2, c, select_z ); + return Transform3( + Vector3::xAxis( ), + Vector3( res1 ), + Vector3( res2 ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationY( float radians ) +{ + vec_float4 s, c, res0, res2; + vec_uint4 select_x, select_z; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_z = (vec_uint4)spu_maskb(0x00f0); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, negatef4(s), select_z ); + res2 = spu_sel( zero, s, select_x ); + res2 = spu_sel( res2, c, select_z ); + return Transform3( + Vector3( res0 ), + Vector3::yAxis( ), + Vector3( res2 ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationZ( float radians ) +{ + vec_float4 s, c, res0, res1; + vec_uint4 select_x, select_y; + vec_float4 zero; + select_x = (vec_uint4)spu_maskb(0xf000); + select_y = (vec_uint4)spu_maskb(0x0f00); + zero = spu_splats(0.0f); + sincosf4( spu_splats(radians), &s, &c ); + res0 = spu_sel( zero, c, select_x ); + res0 = spu_sel( res0, s, select_y ); + res1 = spu_sel( zero, negatef4(s), select_x ); + res1 = spu_sel( res1, c, select_y ); + return Transform3( + Vector3( res0 ), + Vector3( res1 ), + Vector3::zAxis( ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotationZYX( Vector3 radiansXYZ ) +{ + vec_float4 angles, s, negS, c, X0, X1, Y0, Y1, Z0, Z1, tmp; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + angles = radiansXYZ.get128(); + angles = spu_insert( 0.0f, angles, 3 ); + sincosf4( angles, &s, &c ); + negS = negatef4( s ); + Z0 = spu_shuffle( s, c, _VECTORMATH_SHUF_CZD0 ); + Z1 = spu_shuffle( c, negS, _VECTORMATH_SHUF_CZD0 ); + Y0 = spu_shuffle( negS, c, _VECTORMATH_SHUF_BBY0 ); + Y1 = spu_shuffle( c, s, _VECTORMATH_SHUF_BBY0 ); + X0 = spu_shuffle( s, s, shuffle_xxxx ); + X1 = spu_shuffle( c, c, shuffle_xxxx ); + tmp = spu_mul( Z0, Y1 ); + return Transform3( + Vector3( spu_mul( Z0, Y0 ) ), + Vector3( spu_madd( Z1, X1, spu_mul( tmp, X0 ) ) ), + Vector3( spu_nmsub( Z1, X0, spu_mul( tmp, X1 ) ) ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 Transform3::rotation( float radians, Vector3 unitVec ) +{ + return Transform3( Matrix3::rotation( radians, unitVec ), Vector3( 0.0f ) ); +} + +inline const Transform3 Transform3::rotation( Quat unitQuat ) +{ + return Transform3( Matrix3( unitQuat ), Vector3( 0.0f ) ); +} + +inline const Transform3 Transform3::scale( Vector3 scaleVec ) +{ + vec_float4 zero = spu_splats(0.0f); + return Transform3( + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0xf000) ) ), + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x0f00) ) ), + Vector3( spu_sel( zero, scaleVec.get128(), (vec_uint4)spu_maskb(0x00f0) ) ), + Vector3( 0.0f ) + ); +} + +inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ) +{ + return Transform3( + ( tfrm.getCol0() * scaleVec.getX( ) ), + ( tfrm.getCol1() * scaleVec.getY( ) ), + ( tfrm.getCol2() * scaleVec.getZ( ) ), + tfrm.getCol3() + ); +} + +inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ) +{ + return Transform3( + mulPerElem( tfrm.getCol0(), scaleVec ), + mulPerElem( tfrm.getCol1(), scaleVec ), + mulPerElem( tfrm.getCol2(), scaleVec ), + mulPerElem( tfrm.getCol3(), scaleVec ) + ); +} + +inline const Transform3 Transform3::translation( Vector3 translateVec ) +{ + return Transform3( + Vector3::xAxis( ), + Vector3::yAxis( ), + Vector3::zAxis( ), + translateVec + ); +} + +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ) +{ + return Transform3( + select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), + select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), + select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), + select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) + ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( const Transform3 & tfrm ) +{ + print( tfrm.getRow( 0 ) ); + print( tfrm.getRow( 1 ) ); + print( tfrm.getRow( 2 ) ); +} + +inline void print( const Transform3 & tfrm, const char * name ) +{ + printf("%s:\n", name); + print( tfrm ); +} + +#endif + +inline Quat::Quat( const Matrix3 & tfrm ) +{ + vec_float4 res; + vec_float4 col0, col1, col2; + vec_float4 xx_yy, xx_yy_zz_xx, yy_zz_xx_yy, zz_xx_yy_zz, diagSum, diagDiff; + vec_float4 zy_xz_yx, yz_zx_xy, sum, diff; + vec_float4 radicand, invSqrt, scale; + vec_float4 res0, res1, res2, res3; + vec_float4 xx, yy, zz; + vec_uint4 select_x = (vec_uint4)spu_maskb( 0xf000 ); + vec_uint4 select_y = (vec_uint4)spu_maskb( 0x0f00 ); + vec_uint4 select_z = (vec_uint4)spu_maskb( 0x00f0 ); + vec_uint4 select_w = (vec_uint4)spu_maskb( 0x000f ); + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((unsigned int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((unsigned int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((unsigned int)0x08090a0b); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((unsigned int)0x0c0d0e0f); + + col0 = tfrm.getCol0().get128(); + col1 = tfrm.getCol1().get128(); + col2 = tfrm.getCol2().get128(); + + /* four cases: */ + /* trace > 0 */ + /* else */ + /* xx largest diagonal element */ + /* yy largest diagonal element */ + /* zz largest diagonal element */ + + /* compute quaternion for each case */ + + xx_yy = spu_sel( col0, col1, select_y ); + xx_yy_zz_xx = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_XYCX ); + yy_zz_xx_yy = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_YCXY ); + zz_xx_yy_zz = spu_shuffle( xx_yy, col2, _VECTORMATH_SHUF_CXYC ); + + diagSum = spu_add( spu_add( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + diagDiff = spu_sub( spu_sub( xx_yy_zz_xx, yy_zz_xx_yy ), zz_xx_yy_zz ); + radicand = spu_add( spu_sel( diagDiff, diagSum, select_w ), spu_splats(1.0f) ); + invSqrt = rsqrtf4( radicand ); + + zy_xz_yx = spu_sel( col0, col1, select_z ); + zy_xz_yx = spu_shuffle( zy_xz_yx, col2, _VECTORMATH_SHUF_ZAY0 ); + yz_zx_xy = spu_sel( col0, col1, select_x ); + yz_zx_xy = spu_shuffle( yz_zx_xy, col2, _VECTORMATH_SHUF_BZX0 ); + + sum = spu_add( zy_xz_yx, yz_zx_xy ); + diff = spu_sub( zy_xz_yx, yz_zx_xy ); + + scale = spu_mul( invSqrt, spu_splats(0.5f) ); + res0 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_0ZYA ); + res1 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_Z0XB ); + res2 = spu_shuffle( sum, diff, _VECTORMATH_SHUF_YX0C ); + res3 = diff; + res0 = spu_sel( res0, radicand, select_x ); + res1 = spu_sel( res1, radicand, select_y ); + res2 = spu_sel( res2, radicand, select_z ); + res3 = spu_sel( res3, radicand, select_w ); + res0 = spu_mul( res0, spu_shuffle( scale, scale, shuffle_xxxx ) ); + res1 = spu_mul( res1, spu_shuffle( scale, scale, shuffle_yyyy ) ); + res2 = spu_mul( res2, spu_shuffle( scale, scale, shuffle_zzzz ) ); + res3 = spu_mul( res3, spu_shuffle( scale, scale, shuffle_wwww ) ); + + /* determine case and select answer */ + + xx = spu_shuffle( col0, col0, shuffle_xxxx ); + yy = spu_shuffle( col1, col1, shuffle_yyyy ); + zz = spu_shuffle( col2, col2, shuffle_zzzz ); + res = spu_sel( res0, res1, spu_cmpgt( yy, xx ) ); + res = spu_sel( res, res2, spu_and( spu_cmpgt( zz, xx ), spu_cmpgt( zz, yy ) ) ); + res = spu_sel( res, res3, spu_cmpgt( spu_shuffle( diagSum, diagSum, shuffle_xxxx ), spu_splats(0.0f) ) ); + mVec128 = res; +} + +inline const Matrix3 outer( Vector3 tfrm0, Vector3 tfrm1 ) +{ + return Matrix3( + ( tfrm0 * tfrm1.getX( ) ), + ( tfrm0 * tfrm1.getY( ) ), + ( tfrm0 * tfrm1.getZ( ) ) + ); +} + +inline const Matrix4 outer( Vector4 tfrm0, Vector4 tfrm1 ) +{ + return Matrix4( + ( tfrm0 * tfrm1.getX( ) ), + ( tfrm0 * tfrm1.getY( ) ), + ( tfrm0 * tfrm1.getZ( ) ), + ( tfrm0 * tfrm1.getW( ) ) + ); +} + +inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ) +{ + vec_float4 tmp0, tmp1, mcol0, mcol1, mcol2, res; + vec_float4 xxxx, yyyy, zzzz; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + tmp0 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_XAYB ); + tmp1 = spu_shuffle( mat.getCol0().get128(), mat.getCol2().get128(), _VECTORMATH_SHUF_ZCWD ); + xxxx = spu_shuffle( vec.get128(), vec.get128(), shuffle_xxxx ); + mcol0 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_XAYB ); + mcol1 = spu_shuffle( tmp0, mat.getCol1().get128(), _VECTORMATH_SHUF_ZBW0 ); + mcol2 = spu_shuffle( tmp1, mat.getCol1().get128(), _VECTORMATH_SHUF_XCY0 ); + yyyy = spu_shuffle( vec.get128(), vec.get128(), shuffle_yyyy ); + res = spu_mul( mcol0, xxxx ); + zzzz = spu_shuffle( vec.get128(), vec.get128(), shuffle_zzzz ); + res = spu_madd( mcol1, yyyy, res ); + res = spu_madd( mcol2, zzzz, res ); + return Vector3( res ); +} + +inline const Matrix3 crossMatrix( Vector3 vec ) +{ + vec_float4 neg, res0, res1, res2; + neg = negatef4( vec.get128() ); + res0 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_0ZB0 ); + res1 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_C0X0 ); + res2 = spu_shuffle( vec.get128(), neg, _VECTORMATH_SHUF_YA00 ); + return Matrix3( + Vector3( res0 ), + Vector3( res1 ), + Vector3( res2 ) + ); +} + +inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ) +{ + return Matrix3( cross( vec, mat.getCol0() ), cross( vec, mat.getCol1() ), cross( vec, mat.getCol2() ) ); +} + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/spu/cpp/quat_aos.h b/common/vectormath/spu/cpp/quat_aos.h index c150f4a2..55afc6d8 100644 --- a/common/vectormath/spu/cpp/quat_aos.h +++ b/common/vectormath/spu/cpp/quat_aos.h @@ -1,417 +1,449 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_QUAT_AOS_CPP_H -#define _VECTORMATH_QUAT_AOS_CPP_H -//----------------------------------------------------------------------------- -// Definitions - -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -#endif - -namespace Vectormath { -namespace Aos { - -inline Quat::Quat( float _x, float _y, float _z, float _w ) -{ - mVec128 = (vec_float4){ _x, _y, _z, _w }; -} - -inline Quat::Quat( Vector3 xyz, float _w ) -{ - mVec128 = spu_shuffle( xyz.get128(), spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); -} - -inline Quat::Quat( Vector4 vec ) -{ - mVec128 = vec.get128(); -} - -inline Quat::Quat( float scalar ) -{ - mVec128 = spu_splats( scalar ); -} - -inline Quat::Quat( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Quat Quat::identity( ) -{ - return Quat( _VECTORMATH_UNIT_0001 ); -} - -inline const Quat lerp( float t, Quat quat0, Quat quat1 ) -{ - return ( quat0 + ( ( quat1 - quat0 ) * t ) ); -} - -inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ) -{ - Quat start; - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot4( unitQuat0.get128(), unitQuat1.get128() ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(0.0f), cosAngle ); - cosAngle = spu_sel( cosAngle, negatef4( cosAngle ), selectMask ); - start = Quat( spu_sel( unitQuat0.get128(), negatef4( unitQuat0.get128() ), selectMask ) ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - return Quat( spu_madd( start.get128(), scale0, spu_mul( unitQuat1.get128(), scale1 ) ) ); -} - -inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) -{ - Quat tmp0, tmp1; - tmp0 = slerp( t, unitQuat0, unitQuat3 ); - tmp1 = slerp( t, unitQuat1, unitQuat2 ); - return slerp( ( ( 2.0f * t ) * ( 1.0f - t ) ), tmp0, tmp1 ); -} - -inline vec_float4 Quat::get128( ) const -{ - return mVec128; -} - -inline Quat & Quat::operator =( Quat quat ) -{ - mVec128 = quat.mVec128; - return *this; -} - -inline Quat & Quat::setXYZ( Vector3 vec ) -{ - mVec128 = spu_sel( vec.get128(), mVec128, (vec_uint4)spu_maskb(0x000f) ); - return *this; -} - -inline const Vector3 Quat::getXYZ( ) const -{ - return Vector3( mVec128 ); -} - -inline Quat & Quat::setX( float _x ) -{ - mVec128 = spu_insert( _x, mVec128, 0 ); - return *this; -} - -inline float Quat::getX( ) const -{ - return spu_extract( mVec128, 0 ); -} - -inline Quat & Quat::setY( float _y ) -{ - mVec128 = spu_insert( _y, mVec128, 1 ); - return *this; -} - -inline float Quat::getY( ) const -{ - return spu_extract( mVec128, 1 ); -} - -inline Quat & Quat::setZ( float _z ) -{ - mVec128 = spu_insert( _z, mVec128, 2 ); - return *this; -} - -inline float Quat::getZ( ) const -{ - return spu_extract( mVec128, 2 ); -} - -inline Quat & Quat::setW( float _w ) -{ - mVec128 = spu_insert( _w, mVec128, 3 ); - return *this; -} - -inline float Quat::getW( ) const -{ - return spu_extract( mVec128, 3 ); -} - -inline Quat & Quat::setElem( int idx, float value ) -{ - mVec128 = spu_insert( value, mVec128, idx ); - return *this; -} - -inline float Quat::getElem( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline VecIdx Quat::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline float Quat::operator []( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline const Quat Quat::operator +( Quat quat ) const -{ - return Quat( spu_add( mVec128, quat.mVec128 ) ); -} - -inline const Quat Quat::operator -( Quat quat ) const -{ - return Quat( spu_sub( mVec128, quat.mVec128 ) ); -} - -inline const Quat Quat::operator *( float scalar ) const -{ - return Quat( spu_mul( mVec128, spu_splats(scalar) ) ); -} - -inline Quat & Quat::operator +=( Quat quat ) -{ - *this = *this + quat; - return *this; -} - -inline Quat & Quat::operator -=( Quat quat ) -{ - *this = *this - quat; - return *this; -} - -inline Quat & Quat::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Quat Quat::operator /( float scalar ) const -{ - return Quat( divf4( mVec128, spu_splats(scalar) ) ); -} - -inline Quat & Quat::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Quat Quat::operator -( ) const -{ - return Quat( negatef4( mVec128 ) ); -} - -inline const Quat operator *( float scalar, Quat quat ) -{ - return quat * scalar; -} - -inline float dot( Quat quat0, Quat quat1 ) -{ - return spu_extract( _vmathVfDot4( quat0.get128(), quat1.get128() ), 0 ); -} - -inline float norm( Quat quat ) -{ - return spu_extract( _vmathVfDot4( quat.get128(), quat.get128() ), 0 ); -} - -inline float length( Quat quat ) -{ - return sqrtf( norm( quat ) ); -} - -inline const Quat normalize( Quat quat ) -{ - vec_float4 dot = _vmathVfDot4( quat.get128(), quat.get128() ); - return Quat( spu_mul( quat.get128(), rsqrtf4( dot ) ) ); -} - -inline const Quat Quat::rotation( Vector3 unitVec0, Vector3 unitVec1 ) -{ - Vector3 crossVec; - vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; - cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); - cosAngle = spu_shuffle( cosAngle, cosAngle, (vec_uchar16)spu_splats(0x00010203) ); - cosAngleX2Plus2 = spu_madd( cosAngle, spu_splats(2.0f), spu_splats(2.0f) ); - recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); - cosHalfAngleX2 = spu_mul( recipCosHalfAngleX2, cosAngleX2Plus2 ); - crossVec = cross( unitVec0, unitVec1 ); - res = spu_mul( crossVec.get128(), recipCosHalfAngleX2 ); - res = spu_sel( res, spu_mul( cosHalfAngleX2, spu_splats(0.5f) ), (vec_uint4)spu_maskb(0x000f) ); - return Quat( res ); -} - -inline const Quat Quat::rotation( float radians, Vector3 unitVec ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_mul( unitVec.get128(), s ), c, (vec_uint4)spu_maskb(0x000f) ); - return Quat( res ); -} - -inline const Quat Quat::rotationX( float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0xf000) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - return Quat( res ); -} - -inline const Quat Quat::rotationY( float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x0f00) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - return Quat( res ); -} - -inline const Quat Quat::rotationZ( float radians ) -{ - vec_float4 s, c, angle, res; - angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); - sincosf4( angle, &s, &c ); - res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x00f0) ); - res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); - return Quat( res ); -} - -inline const Quat Quat::operator *( Quat quat ) const -{ - vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; - vec_float4 product, l_wxyz, r_wxyz, xy, qw; - ldata = mVec128; - rdata = quat.mVec128; - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - tmp0 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_YZXW ); - qv = spu_mul( spu_shuffle( ldata, ldata, shuffle_wwww ), rdata ); - qv = spu_madd( spu_shuffle( rdata, rdata, shuffle_wwww ), ldata, qv ); - qv = spu_madd( tmp0, tmp1, qv ); - qv = spu_nmsub( tmp2, tmp3, qv ); - product = spu_mul( ldata, rdata ); - l_wxyz = spu_rlqwbyte( ldata, 12 ); - r_wxyz = spu_rlqwbyte( rdata, 12 ); - qw = spu_nmsub( l_wxyz, r_wxyz, product ); - xy = spu_madd( l_wxyz, r_wxyz, product ); - qw = spu_sub( qw, spu_rlqwbyte( xy, 8 ) ); - return Quat( spu_sel( qv, qw, (vec_uint4)spu_maskb( 0x000f ) ) ); -} - -inline Quat & Quat::operator *=( Quat quat ) -{ - *this = *this * quat; - return *this; -} - -inline const Vector3 rotate( Quat quat, Vector3 vec ) -{ - vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; - qdata = quat.get128(); - vdata = vec.get128(); - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); - tmp0 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_YZXW ); - wwww = spu_shuffle( qdata, qdata, shuffle_wwww ); - qv = spu_mul( wwww, vdata ); - qv = spu_madd( tmp0, tmp1, qv ); - qv = spu_nmsub( tmp2, tmp3, qv ); - product = spu_mul( qdata, vdata ); - qw = spu_madd( spu_rlqwbyte( qdata, 4 ), spu_rlqwbyte( vdata, 4 ), product ); - qw = spu_add( spu_rlqwbyte( product, 8 ), qw ); - tmp1 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_YZXW ); - res = spu_mul( spu_shuffle( qw, qw, shuffle_xxxx ), qdata ); - res = spu_madd( wwww, qv, res ); - res = spu_madd( tmp0, tmp1, res ); - res = spu_nmsub( tmp2, tmp3, res ); - return Vector3( res ); -} - -inline const Quat conj( Quat quat ) -{ - return Quat( spu_xor( quat.get128(), ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ) ); -} - -inline const Quat select( Quat quat0, Quat quat1, bool select1 ) -{ - return Quat( spu_sel( quat0.get128(), quat1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Quat quat ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat.get128(); - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -inline void print( Quat quat, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = quat.get128(); - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_QUAT_AOS_CPP_H +#define _VECTORMATH_QUAT_AOS_CPP_H +//----------------------------------------------------------------------------- +// Definitions + +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +#endif + +namespace Vectormath { +namespace Aos { + +inline Quat::Quat( float _x, float _y, float _z, float _w ) +{ + mVec128 = (vec_float4){ _x, _y, _z, _w }; +} + +inline Quat::Quat( Vector3 xyz, float _w ) +{ + mVec128 = spu_shuffle( xyz.get128(), spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); +} + +inline Quat::Quat( Vector4 vec ) +{ + mVec128 = vec.get128(); +} + +inline Quat::Quat( float scalar ) +{ + mVec128 = spu_splats( scalar ); +} + +inline Quat::Quat( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Quat Quat::identity( ) +{ + return Quat( _VECTORMATH_UNIT_0001 ); +} + +inline const Quat lerp( float t, Quat quat0, Quat quat1 ) +{ + return ( quat0 + ( ( quat1 - quat0 ) * t ) ); +} + +inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ) +{ + Quat start; + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot4( unitQuat0.get128(), unitQuat1.get128() ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(0.0f), cosAngle ); + cosAngle = spu_sel( cosAngle, negatef4( cosAngle ), selectMask ); + start = Quat( spu_sel( unitQuat0.get128(), negatef4( unitQuat0.get128() ), selectMask ) ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + return Quat( spu_madd( start.get128(), scale0, spu_mul( unitQuat1.get128(), scale1 ) ) ); +} + +inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ) +{ + Quat tmp0, tmp1; + tmp0 = slerp( t, unitQuat0, unitQuat3 ); + tmp1 = slerp( t, unitQuat1, unitQuat2 ); + return slerp( ( ( 2.0f * t ) * ( 1.0f - t ) ), tmp0, tmp1 ); +} + +inline vec_float4 Quat::get128( ) const +{ + return mVec128; +} + +inline void loadXYZW( Quat & quat, const vec_float4 * quad ) +{ + quat = Quat( *quad ); +} + +inline void loadXYZW( Quat & quat, const float * fptr ) +{ + const vec_float4 vfsrc0 = *((vec_float4*)((uintptr_t)fptr)); + const vec_float4 vfsrc1 = *((vec_float4*)(((uintptr_t)fptr) + 16)); + const vec_uchar16 vucpat = (vec_uchar16)spu_add((vec_ushort8)(spu_splats((unsigned char)(((int)fptr)&0xf))),((vec_ushort8){0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F})); + const vec_float4 vfval = spu_shuffle(vfsrc0, vfsrc1, vucpat); + quat = Quat( vfval ); +} + +inline void storeXYZW( Quat quat, float * fptr ) +{ + vec_float4 * vptr0 = (vec_float4*)((uintptr_t)fptr); + vec_float4 * vptr1 = (vec_float4*)(((uintptr_t)fptr) + 16); + vec_float4 dstVec0 = *vptr0; + vec_float4 dstVec1 = *vptr1; + uint32_t offset = (uint32_t)fptr & 0xf; + vec_uint4 mask = (vec_uint4)spu_splats(0xffffffff); + vec_uint4 mask0 = (vec_uint4)spu_rlmaskqwbyte(mask, -offset); + vec_uint4 mask1 = (vec_uint4)spu_slqwbyte(mask, 16 - offset); + vec_float4 vec0 = spu_rlmaskqwbyte(quat.get128(), -offset); + vec_float4 vec1 = spu_slqwbyte(quat.get128(), 16 - offset); + dstVec0 = spu_sel(dstVec0, vec0, mask0); + dstVec1 = spu_sel(dstVec1, vec1, mask1); + *vptr0 = dstVec0; + *vptr1 = dstVec1; +} + +inline Quat & Quat::operator =( Quat quat ) +{ + mVec128 = quat.mVec128; + return *this; +} + +inline Quat & Quat::setXYZ( Vector3 vec ) +{ + mVec128 = spu_sel( vec.get128(), mVec128, (vec_uint4)spu_maskb(0x000f) ); + return *this; +} + +inline const Vector3 Quat::getXYZ( ) const +{ + return Vector3( mVec128 ); +} + +inline Quat & Quat::setX( float _x ) +{ + mVec128 = spu_insert( _x, mVec128, 0 ); + return *this; +} + +inline float Quat::getX( ) const +{ + return spu_extract( mVec128, 0 ); +} + +inline Quat & Quat::setY( float _y ) +{ + mVec128 = spu_insert( _y, mVec128, 1 ); + return *this; +} + +inline float Quat::getY( ) const +{ + return spu_extract( mVec128, 1 ); +} + +inline Quat & Quat::setZ( float _z ) +{ + mVec128 = spu_insert( _z, mVec128, 2 ); + return *this; +} + +inline float Quat::getZ( ) const +{ + return spu_extract( mVec128, 2 ); +} + +inline Quat & Quat::setW( float _w ) +{ + mVec128 = spu_insert( _w, mVec128, 3 ); + return *this; +} + +inline float Quat::getW( ) const +{ + return spu_extract( mVec128, 3 ); +} + +inline Quat & Quat::setElem( int idx, float value ) +{ + mVec128 = spu_insert( value, mVec128, idx ); + return *this; +} + +inline float Quat::getElem( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline VecIdx Quat::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline float Quat::operator []( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline const Quat Quat::operator +( Quat quat ) const +{ + return Quat( spu_add( mVec128, quat.mVec128 ) ); +} + +inline const Quat Quat::operator -( Quat quat ) const +{ + return Quat( spu_sub( mVec128, quat.mVec128 ) ); +} + +inline const Quat Quat::operator *( float scalar ) const +{ + return Quat( spu_mul( mVec128, spu_splats(scalar) ) ); +} + +inline Quat & Quat::operator +=( Quat quat ) +{ + *this = *this + quat; + return *this; +} + +inline Quat & Quat::operator -=( Quat quat ) +{ + *this = *this - quat; + return *this; +} + +inline Quat & Quat::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Quat Quat::operator /( float scalar ) const +{ + return Quat( divf4( mVec128, spu_splats(scalar) ) ); +} + +inline Quat & Quat::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline const Quat Quat::operator -( ) const +{ + return Quat( negatef4( mVec128 ) ); +} + +inline const Quat operator *( float scalar, Quat quat ) +{ + return quat * scalar; +} + +inline float dot( Quat quat0, Quat quat1 ) +{ + return spu_extract( _vmathVfDot4( quat0.get128(), quat1.get128() ), 0 ); +} + +inline float norm( Quat quat ) +{ + return spu_extract( _vmathVfDot4( quat.get128(), quat.get128() ), 0 ); +} + +inline float length( Quat quat ) +{ + return sqrtf( norm( quat ) ); +} + +inline const Quat normalize( Quat quat ) +{ + vec_float4 dot = _vmathVfDot4( quat.get128(), quat.get128() ); + return Quat( spu_mul( quat.get128(), rsqrtf4( dot ) ) ); +} + +inline const Quat Quat::rotation( Vector3 unitVec0, Vector3 unitVec1 ) +{ + Vector3 crossVec; + vec_float4 cosAngle, cosAngleX2Plus2, recipCosHalfAngleX2, cosHalfAngleX2, res; + cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); + cosAngle = spu_shuffle( cosAngle, cosAngle, (vec_uchar16)spu_splats(0x00010203) ); + cosAngleX2Plus2 = spu_madd( cosAngle, spu_splats(2.0f), spu_splats(2.0f) ); + recipCosHalfAngleX2 = rsqrtf4( cosAngleX2Plus2 ); + cosHalfAngleX2 = spu_mul( recipCosHalfAngleX2, cosAngleX2Plus2 ); + crossVec = cross( unitVec0, unitVec1 ); + res = spu_mul( crossVec.get128(), recipCosHalfAngleX2 ); + res = spu_sel( res, spu_mul( cosHalfAngleX2, spu_splats(0.5f) ), (vec_uint4)spu_maskb(0x000f) ); + return Quat( res ); +} + +inline const Quat Quat::rotation( float radians, Vector3 unitVec ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_mul( unitVec.get128(), s ), c, (vec_uint4)spu_maskb(0x000f) ); + return Quat( res ); +} + +inline const Quat Quat::rotationX( float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0xf000) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + return Quat( res ); +} + +inline const Quat Quat::rotationY( float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x0f00) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + return Quat( res ); +} + +inline const Quat Quat::rotationZ( float radians ) +{ + vec_float4 s, c, angle, res; + angle = spu_mul( spu_splats(radians), spu_splats(0.5f) ); + sincosf4( angle, &s, &c ); + res = spu_sel( spu_splats(0.0f), s, (vec_uint4)spu_maskb(0x00f0) ); + res = spu_sel( res, c, (vec_uint4)spu_maskb(0x000f) ); + return Quat( res ); +} + +inline const Quat Quat::operator *( Quat quat ) const +{ + vec_float4 ldata, rdata, qv, tmp0, tmp1, tmp2, tmp3; + vec_float4 product, l_wxyz, r_wxyz, xy, qw; + ldata = mVec128; + rdata = quat.mVec128; + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + tmp0 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( ldata, ldata, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( rdata, rdata, _VECTORMATH_SHUF_YZXW ); + qv = spu_mul( spu_shuffle( ldata, ldata, shuffle_wwww ), rdata ); + qv = spu_madd( spu_shuffle( rdata, rdata, shuffle_wwww ), ldata, qv ); + qv = spu_madd( tmp0, tmp1, qv ); + qv = spu_nmsub( tmp2, tmp3, qv ); + product = spu_mul( ldata, rdata ); + l_wxyz = spu_rlqwbyte( ldata, 12 ); + r_wxyz = spu_rlqwbyte( rdata, 12 ); + qw = spu_nmsub( l_wxyz, r_wxyz, product ); + xy = spu_madd( l_wxyz, r_wxyz, product ); + qw = spu_sub( qw, spu_rlqwbyte( xy, 8 ) ); + return Quat( spu_sel( qv, qw, (vec_uint4)spu_maskb( 0x000f ) ) ); +} + +inline Quat & Quat::operator *=( Quat quat ) +{ + *this = *this * quat; + return *this; +} + +inline const Vector3 rotate( Quat quat, Vector3 vec ) +{ + vec_float4 qdata, vdata, product, tmp0, tmp1, tmp2, tmp3, wwww, qv, qw, res; + qdata = quat.get128(); + vdata = vec.get128(); + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_wwww = (vec_uchar16)spu_splats((int)0x0c0d0e0f); + tmp0 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( qdata, qdata, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( vdata, vdata, _VECTORMATH_SHUF_YZXW ); + wwww = spu_shuffle( qdata, qdata, shuffle_wwww ); + qv = spu_mul( wwww, vdata ); + qv = spu_madd( tmp0, tmp1, qv ); + qv = spu_nmsub( tmp2, tmp3, qv ); + product = spu_mul( qdata, vdata ); + qw = spu_madd( spu_rlqwbyte( qdata, 4 ), spu_rlqwbyte( vdata, 4 ), product ); + qw = spu_add( spu_rlqwbyte( product, 8 ), qw ); + tmp1 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( qv, qv, _VECTORMATH_SHUF_YZXW ); + res = spu_mul( spu_shuffle( qw, qw, shuffle_xxxx ), qdata ); + res = spu_madd( wwww, qv, res ); + res = spu_madd( tmp0, tmp1, res ); + res = spu_nmsub( tmp2, tmp3, res ); + return Vector3( res ); +} + +inline const Quat conj( Quat quat ) +{ + return Quat( spu_xor( quat.get128(), ((vec_float4)(vec_uint4){0x80000000,0x80000000,0x80000000,0}) ) ); +} + +inline const Quat select( Quat quat0, Quat quat1, bool select1 ) +{ + return Quat( spu_sel( quat0.get128(), quat1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Quat quat ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat.get128(); + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +inline void print( Quat quat, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = quat.get128(); + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/spu/cpp/vec_aos.h b/common/vectormath/spu/cpp/vec_aos.h index c983f181..1724a9c5 100644 --- a/common/vectormath/spu/cpp/vec_aos.h +++ b/common/vectormath/spu/cpp/vec_aos.h @@ -1,1167 +1,1263 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VEC_AOS_CPP_H -#define _VECTORMATH_VEC_AOS_CPP_H -//----------------------------------------------------------------------------- -// Constants -// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] - -#define _VECTORMATH_SHUF_X 0x00010203 -#define _VECTORMATH_SHUF_Y 0x04050607 -#define _VECTORMATH_SHUF_Z 0x08090a0b -#define _VECTORMATH_SHUF_W 0x0c0d0e0f -#define _VECTORMATH_SHUF_A 0x10111213 -#define _VECTORMATH_SHUF_B 0x14151617 -#define _VECTORMATH_SHUF_C 0x18191a1b -#define _VECTORMATH_SHUF_D 0x1c1d1e1f -#define _VECTORMATH_SHUF_0 0x80808080 -#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } -#define _VECTORMATH_SHUF_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_W } -#define _VECTORMATH_SHUF_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W } -#define _VECTORMATH_SHUF_WABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } -#define _VECTORMATH_SHUF_ZWAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } -#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } -#define _VECTORMATH_SHUF_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } -#define _VECTORMATH_SHUF_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } -#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } -#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } -#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } -#define _VECTORMATH_SLERP_TOL 0.999f - -//----------------------------------------------------------------------------- -// Definitions - -#ifndef _VECTORMATH_INTERNAL_FUNCTIONS -#define _VECTORMATH_INTERNAL_FUNCTIONS - -static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = spu_mul( vec0, vec1 ); - result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); - return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); -} - -static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 result; - result = spu_mul( vec0, vec1 ); - result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); - return spu_add( spu_rlqwbyte( result, 8 ), result ); -} - -static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) -{ - vec_float4 tmp0, tmp1, tmp2, tmp3, result; - tmp0 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_YZXW ); - tmp1 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_ZXYW ); - tmp2 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_ZXYW ); - tmp3 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_YZXW ); - result = spu_mul( tmp0, tmp1 ); - result = spu_nmsub( tmp2, tmp3, result ); - return result; -} - -static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) -{ - vec_int4 bexp; - vec_uint4 mant, sign, hfloat; - vec_uint4 notZero, isInf; - const vec_uint4 hfloatInf = spu_splats(0x00007c00u); - const vec_uint4 mergeMant = spu_splats(0x000003ffu); - const vec_uint4 mergeSign = spu_splats(0x00008000u); - - sign = spu_rlmask((vec_uint4)v, -16); - mant = spu_rlmask((vec_uint4)v, -13); - bexp = spu_and(spu_rlmask((vec_int4)v, -23), 0xff); - - notZero = spu_cmpgt(bexp, 112); - isInf = spu_cmpgt(bexp, 142); - - bexp = spu_add(bexp, -112); - bexp = spu_sl(bexp, 10); - - hfloat = spu_sel((vec_uint4)bexp, mant, mergeMant); - hfloat = spu_sel(spu_splats(0u), hfloat, notZero); - hfloat = spu_sel(hfloat, hfloatInf, isInf); - hfloat = spu_sel(hfloat, sign, mergeSign); - - return hfloat; -} - -static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) -{ - vec_uint4 hfloat_u, hfloat_v; - const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; - hfloat_u = _vmathVfToHalfFloatsUnpacked(u); - hfloat_v = _vmathVfToHalfFloatsUnpacked(v); - return (vec_ushort8)spu_shuffle(hfloat_u, hfloat_v, pack); -} - -#endif - -namespace Vectormath { -namespace Aos { - -inline VecIdx::operator float() const -{ - return spu_extract( ref, i ); -} - -inline float VecIdx::operator =( float scalar ) -{ - ref = spu_insert( scalar, ref, i ); - return scalar; -} - -inline float VecIdx::operator =( const VecIdx& scalar ) -{ - return *this = float(scalar); -} - -inline float VecIdx::operator *=( float scalar ) -{ - float tmp = spu_extract( ref, i ) * scalar; - ref = spu_insert( tmp, ref, i ); - return tmp; -} - -inline float VecIdx::operator /=( float scalar ) -{ - float tmp = spu_extract( ref, i ) / scalar; - ref = spu_insert( tmp, ref, i ); - return tmp; -} - -inline float VecIdx::operator +=( float scalar ) -{ - float tmp = spu_extract( ref, i ) + scalar; - ref = spu_insert( tmp, ref, i ); - return tmp; -} - -inline float VecIdx::operator -=( float scalar ) -{ - float tmp = spu_extract( ref, i ) - scalar; - ref = spu_insert( tmp, ref, i ); - return tmp; -} - -inline Vector3::Vector3( float _x, float _y, float _z ) -{ - mVec128 = (vec_float4){ _x, _y, _z, 0.0f }; -} - -inline Vector3::Vector3( Point3 pnt ) -{ - mVec128 = pnt.get128(); -} - -inline Vector3::Vector3( float scalar ) -{ - mVec128 = spu_splats( scalar ); -} - -inline Vector3::Vector3( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Vector3 Vector3::xAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_1000 ); -} - -inline const Vector3 Vector3::yAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_0100 ); -} - -inline const Vector3 Vector3::zAxis( ) -{ - return Vector3( _VECTORMATH_UNIT_0010 ); -} - -inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ) -{ - return ( vec0 + ( ( vec1 - vec0 ) * t ) ); -} - -inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - return Vector3( spu_madd( unitVec0.get128(), scale0, spu_mul( unitVec1.get128(), scale1 ) ) ); -} - -inline vec_float4 Vector3::get128( ) const -{ - return mVec128; -} - -inline void storeXYZ( Vector3 vec, vec_float4 * quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); - dstVec = spu_sel(vec.get128(), dstVec, mask); - *quad = dstVec; -} - -inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); - xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); - xyz3 = spu_rlqwbyte( zxyz, 4 ); - vec0 = Vector3( xyzx ); - vec1 = Vector3( xyz1 ); - vec2 = Vector3( xyz2 ); - vec3 = Vector3( xyz3 ); -} - -inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = spu_shuffle( vec0.get128(), vec1.get128(), _VECTORMATH_SHUF_XYZA ); - yzxy = spu_shuffle( vec1.get128(), vec2.get128(), _VECTORMATH_SHUF_YZAB ); - zxyz = spu_shuffle( vec2.get128(), vec3.get128(), _VECTORMATH_SHUF_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - storeXYZArray( vec0, vec1, vec2, vec3, xyz0 ); - storeXYZArray( vec4, vec5, vec6, vec7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -inline Vector3 & Vector3::operator =( Vector3 vec ) -{ - mVec128 = vec.mVec128; - return *this; -} - -inline Vector3 & Vector3::setX( float _x ) -{ - mVec128 = spu_insert( _x, mVec128, 0 ); - return *this; -} - -inline float Vector3::getX( ) const -{ - return spu_extract( mVec128, 0 ); -} - -inline Vector3 & Vector3::setY( float _y ) -{ - mVec128 = spu_insert( _y, mVec128, 1 ); - return *this; -} - -inline float Vector3::getY( ) const -{ - return spu_extract( mVec128, 1 ); -} - -inline Vector3 & Vector3::setZ( float _z ) -{ - mVec128 = spu_insert( _z, mVec128, 2 ); - return *this; -} - -inline float Vector3::getZ( ) const -{ - return spu_extract( mVec128, 2 ); -} - -inline Vector3 & Vector3::setElem( int idx, float value ) -{ - mVec128 = spu_insert( value, mVec128, idx ); - return *this; -} - -inline float Vector3::getElem( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline VecIdx Vector3::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline float Vector3::operator []( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline const Vector3 Vector3::operator +( Vector3 vec ) const -{ - return Vector3( spu_add( mVec128, vec.mVec128 ) ); -} - -inline const Vector3 Vector3::operator -( Vector3 vec ) const -{ - return Vector3( spu_sub( mVec128, vec.mVec128 ) ); -} - -inline const Point3 Vector3::operator +( Point3 pnt ) const -{ - return Point3( spu_add( mVec128, pnt.get128() ) ); -} - -inline const Vector3 Vector3::operator *( float scalar ) const -{ - return Vector3( spu_mul( mVec128, spu_splats(scalar) ) ); -} - -inline Vector3 & Vector3::operator +=( Vector3 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Vector3 & Vector3::operator -=( Vector3 vec ) -{ - *this = *this - vec; - return *this; -} - -inline Vector3 & Vector3::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Vector3 Vector3::operator /( float scalar ) const -{ - return Vector3( divf4( mVec128, spu_splats(scalar) ) ); -} - -inline Vector3 & Vector3::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Vector3 Vector3::operator -( ) const -{ - return Vector3( negatef4( mVec128 ) ); -} - -inline const Vector3 operator *( float scalar, Vector3 vec ) -{ - return vec * scalar; -} - -inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( spu_mul( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( divf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 recipPerElem( Vector3 vec ) -{ - return Vector3( recipf4( vec.get128() ) ); -} - -inline const Vector3 sqrtPerElem( Vector3 vec ) -{ - return Vector3( sqrtf4( vec.get128() ) ); -} - -inline const Vector3 rsqrtPerElem( Vector3 vec ) -{ - return Vector3( rsqrtf4( vec.get128() ) ); -} - -inline const Vector3 absPerElem( Vector3 vec ) -{ - return Vector3( fabsf4( vec.get128() ) ); -} - -inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( copysignf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( fmaxf4( vec0.get128(), vec1.get128() ) ); -} - -inline float maxElem( Vector3 vec ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); - result = fmaxf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( fminf4( vec0.get128(), vec1.get128() ) ); -} - -inline float minElem( Vector3 vec ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); - result = fminf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline float sum( Vector3 vec ) -{ - return - spu_extract( vec.get128(), 0 ) + - spu_extract( vec.get128(), 1 ) + - spu_extract( vec.get128(), 2 ); -} - -inline float dot( Vector3 vec0, Vector3 vec1 ) -{ - return spu_extract( _vmathVfDot3( vec0.get128(), vec1.get128() ), 0 ); -} - -inline float lengthSqr( Vector3 vec ) -{ - return spu_extract( _vmathVfDot3( vec.get128(), vec.get128() ), 0 ); -} - -inline float length( Vector3 vec ) -{ - return sqrtf( lengthSqr( vec ) ); -} - -inline const Vector3 normalize( Vector3 vec ) -{ - vec_float4 dot = _vmathVfDot3( vec.get128(), vec.get128() ); - dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); - return Vector3( spu_mul( vec.get128(), rsqrtf4( dot ) ) ); -} - -inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ) -{ - return Vector3( _vmathVfCross( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ) -{ - return Vector3( spu_sel( vec0.get128(), vec1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Vector3 vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -inline void print( Vector3 vec, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -inline Vector4::Vector4( float _x, float _y, float _z, float _w ) -{ - mVec128 = (vec_float4){ _x, _y, _z, _w }; -} - -inline Vector4::Vector4( Vector3 xyz, float _w ) -{ - mVec128 = spu_shuffle( xyz.get128(), spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); -} - -inline Vector4::Vector4( Vector3 vec ) -{ - mVec128 = spu_sel( vec.get128(), spu_splats(0.0f), (vec_uint4)spu_maskb(0x000f) ); -} - -inline Vector4::Vector4( Point3 pnt ) -{ - mVec128 = spu_sel( pnt.get128(), spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); -} - -inline Vector4::Vector4( Quat quat ) -{ - mVec128 = quat.get128(); -} - -inline Vector4::Vector4( float scalar ) -{ - mVec128 = spu_splats( scalar ); -} - -inline Vector4::Vector4( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Vector4 Vector4::xAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_1000 ); -} - -inline const Vector4 Vector4::yAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0100 ); -} - -inline const Vector4 Vector4::zAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0010 ); -} - -inline const Vector4 Vector4::wAxis( ) -{ - return Vector4( _VECTORMATH_UNIT_0001 ); -} - -inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ) -{ - return ( vec0 + ( ( vec1 - vec0 ) * t ) ); -} - -inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ) -{ - vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; - vec_uint4 selectMask; - vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); - vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); - vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); - cosAngle = _vmathVfDot4( unitVec0.get128(), unitVec1.get128() ); - cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); - selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); - angle = acosf4( cosAngle ); - tttt = spu_splats(t); - oneMinusT = spu_sub( spu_splats(1.0f), tttt ); - angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); - angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); - angles = spu_mul( angles, angle ); - sines = sinf4( angles ); - scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); - scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); - scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); - return Vector4( spu_madd( unitVec0.get128(), scale0, spu_mul( unitVec1.get128(), scale1 ) ) ); -} - -inline vec_float4 Vector4::get128( ) const -{ - return mVec128; -} - -inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ) -{ - twoQuads[0] = _vmath2VfToHalfFloats(vec0.get128(), vec1.get128()); - twoQuads[1] = _vmath2VfToHalfFloats(vec2.get128(), vec3.get128()); -} - -inline Vector4 & Vector4::operator =( Vector4 vec ) -{ - mVec128 = vec.mVec128; - return *this; -} - -inline Vector4 & Vector4::setXYZ( Vector3 vec ) -{ - mVec128 = spu_sel( vec.get128(), mVec128, (vec_uint4)spu_maskb(0x000f) ); - return *this; -} - -inline const Vector3 Vector4::getXYZ( ) const -{ - return Vector3( mVec128 ); -} - -inline Vector4 & Vector4::setX( float _x ) -{ - mVec128 = spu_insert( _x, mVec128, 0 ); - return *this; -} - -inline float Vector4::getX( ) const -{ - return spu_extract( mVec128, 0 ); -} - -inline Vector4 & Vector4::setY( float _y ) -{ - mVec128 = spu_insert( _y, mVec128, 1 ); - return *this; -} - -inline float Vector4::getY( ) const -{ - return spu_extract( mVec128, 1 ); -} - -inline Vector4 & Vector4::setZ( float _z ) -{ - mVec128 = spu_insert( _z, mVec128, 2 ); - return *this; -} - -inline float Vector4::getZ( ) const -{ - return spu_extract( mVec128, 2 ); -} - -inline Vector4 & Vector4::setW( float _w ) -{ - mVec128 = spu_insert( _w, mVec128, 3 ); - return *this; -} - -inline float Vector4::getW( ) const -{ - return spu_extract( mVec128, 3 ); -} - -inline Vector4 & Vector4::setElem( int idx, float value ) -{ - mVec128 = spu_insert( value, mVec128, idx ); - return *this; -} - -inline float Vector4::getElem( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline VecIdx Vector4::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline float Vector4::operator []( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline const Vector4 Vector4::operator +( Vector4 vec ) const -{ - return Vector4( spu_add( mVec128, vec.mVec128 ) ); -} - -inline const Vector4 Vector4::operator -( Vector4 vec ) const -{ - return Vector4( spu_sub( mVec128, vec.mVec128 ) ); -} - -inline const Vector4 Vector4::operator *( float scalar ) const -{ - return Vector4( spu_mul( mVec128, spu_splats(scalar) ) ); -} - -inline Vector4 & Vector4::operator +=( Vector4 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Vector4 & Vector4::operator -=( Vector4 vec ) -{ - *this = *this - vec; - return *this; -} - -inline Vector4 & Vector4::operator *=( float scalar ) -{ - *this = *this * scalar; - return *this; -} - -inline const Vector4 Vector4::operator /( float scalar ) const -{ - return Vector4( divf4( mVec128, spu_splats(scalar) ) ); -} - -inline Vector4 & Vector4::operator /=( float scalar ) -{ - *this = *this / scalar; - return *this; -} - -inline const Vector4 Vector4::operator -( ) const -{ - return Vector4( negatef4( mVec128 ) ); -} - -inline const Vector4 operator *( float scalar, Vector4 vec ) -{ - return vec * scalar; -} - -inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( spu_mul( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( divf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector4 recipPerElem( Vector4 vec ) -{ - return Vector4( recipf4( vec.get128() ) ); -} - -inline const Vector4 sqrtPerElem( Vector4 vec ) -{ - return Vector4( sqrtf4( vec.get128() ) ); -} - -inline const Vector4 rsqrtPerElem( Vector4 vec ) -{ - return Vector4( rsqrtf4( vec.get128() ) ); -} - -inline const Vector4 absPerElem( Vector4 vec ) -{ - return Vector4( fabsf4( vec.get128() ) ); -} - -inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( copysignf4( vec0.get128(), vec1.get128() ) ); -} - -inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( fmaxf4( vec0.get128(), vec1.get128() ) ); -} - -inline float maxElem( Vector4 vec ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); - result = fmaxf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); - result = fmaxf4( spu_promote( spu_extract( vec.get128(), 3 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ) -{ - return Vector4( fminf4( vec0.get128(), vec1.get128() ) ); -} - -inline float minElem( Vector4 vec ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); - result = fminf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); - result = fminf4( spu_promote( spu_extract( vec.get128(), 3 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline float sum( Vector4 vec ) -{ - return - spu_extract( vec.get128(), 0 ) + - spu_extract( vec.get128(), 1 ) + - spu_extract( vec.get128(), 2 ) + - spu_extract( vec.get128(), 3 ); -} - -inline float dot( Vector4 vec0, Vector4 vec1 ) -{ - return spu_extract( _vmathVfDot4( vec0.get128(), vec1.get128() ), 0 ); -} - -inline float lengthSqr( Vector4 vec ) -{ - return spu_extract( _vmathVfDot4( vec.get128(), vec.get128() ), 0 ); -} - -inline float length( Vector4 vec ) -{ - return sqrtf( lengthSqr( vec ) ); -} - -inline const Vector4 normalize( Vector4 vec ) -{ - vec_float4 dot = _vmathVfDot4( vec.get128(), vec.get128() ); - return Vector4( spu_mul( vec.get128(), rsqrtf4( dot ) ) ); -} - -inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ) -{ - return Vector4( spu_sel( vec0.get128(), vec1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Vector4 vec ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -inline void print( Vector4 vec, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = vec.get128(); - printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); -} - -#endif - -inline Point3::Point3( float _x, float _y, float _z ) -{ - mVec128 = (vec_float4){ _x, _y, _z, 0.0f }; -} - -inline Point3::Point3( Vector3 vec ) -{ - mVec128 = vec.get128(); -} - -inline Point3::Point3( float scalar ) -{ - mVec128 = spu_splats( scalar ); -} - -inline Point3::Point3( vec_float4 vf4 ) -{ - mVec128 = vf4; -} - -inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ) -{ - return ( pnt0 + ( ( pnt1 - pnt0 ) * t ) ); -} - -inline vec_float4 Point3::get128( ) const -{ - return mVec128; -} - -inline void storeXYZ( Point3 pnt, vec_float4 * quad ) -{ - vec_float4 dstVec = *quad; - vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); - dstVec = spu_sel(pnt.get128(), dstVec, mask); - *quad = dstVec; -} - -inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; - xyzx = threeQuads[0]; - yzxy = threeQuads[1]; - zxyz = threeQuads[2]; - xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); - xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); - xyz3 = spu_rlqwbyte( zxyz, 4 ); - pnt0 = Point3( xyzx ); - pnt1 = Point3( xyz1 ); - pnt2 = Point3( xyz2 ); - pnt3 = Point3( xyz3 ); -} - -inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ) -{ - vec_float4 xyzx, yzxy, zxyz; - xyzx = spu_shuffle( pnt0.get128(), pnt1.get128(), _VECTORMATH_SHUF_XYZA ); - yzxy = spu_shuffle( pnt1.get128(), pnt2.get128(), _VECTORMATH_SHUF_YZAB ); - zxyz = spu_shuffle( pnt2.get128(), pnt3.get128(), _VECTORMATH_SHUF_ZABC ); - threeQuads[0] = xyzx; - threeQuads[1] = yzxy; - threeQuads[2] = zxyz; -} - -inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ) -{ - vec_float4 xyz0[3]; - vec_float4 xyz1[3]; - storeXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); - storeXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); - threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); - threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); - threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); -} - -inline Point3 & Point3::operator =( Point3 pnt ) -{ - mVec128 = pnt.mVec128; - return *this; -} - -inline Point3 & Point3::setX( float _x ) -{ - mVec128 = spu_insert( _x, mVec128, 0 ); - return *this; -} - -inline float Point3::getX( ) const -{ - return spu_extract( mVec128, 0 ); -} - -inline Point3 & Point3::setY( float _y ) -{ - mVec128 = spu_insert( _y, mVec128, 1 ); - return *this; -} - -inline float Point3::getY( ) const -{ - return spu_extract( mVec128, 1 ); -} - -inline Point3 & Point3::setZ( float _z ) -{ - mVec128 = spu_insert( _z, mVec128, 2 ); - return *this; -} - -inline float Point3::getZ( ) const -{ - return spu_extract( mVec128, 2 ); -} - -inline Point3 & Point3::setElem( int idx, float value ) -{ - mVec128 = spu_insert( value, mVec128, idx ); - return *this; -} - -inline float Point3::getElem( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline VecIdx Point3::operator []( int idx ) -{ - return VecIdx( mVec128, idx ); -} - -inline float Point3::operator []( int idx ) const -{ - return spu_extract( mVec128, idx ); -} - -inline const Vector3 Point3::operator -( Point3 pnt ) const -{ - return Vector3( spu_sub( mVec128, pnt.mVec128 ) ); -} - -inline const Point3 Point3::operator +( Vector3 vec ) const -{ - return Point3( spu_add( mVec128, vec.get128() ) ); -} - -inline const Point3 Point3::operator -( Vector3 vec ) const -{ - return Point3( spu_sub( mVec128, vec.get128() ) ); -} - -inline Point3 & Point3::operator +=( Vector3 vec ) -{ - *this = *this + vec; - return *this; -} - -inline Point3 & Point3::operator -=( Vector3 vec ) -{ - *this = *this - vec; - return *this; -} - -inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( spu_mul( pnt0.get128(), pnt1.get128() ) ); -} - -inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( divf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const Point3 recipPerElem( Point3 pnt ) -{ - return Point3( recipf4( pnt.get128() ) ); -} - -inline const Point3 sqrtPerElem( Point3 pnt ) -{ - return Point3( sqrtf4( pnt.get128() ) ); -} - -inline const Point3 rsqrtPerElem( Point3 pnt ) -{ - return Point3( rsqrtf4( pnt.get128() ) ); -} - -inline const Point3 absPerElem( Point3 pnt ) -{ - return Point3( fabsf4( pnt.get128() ) ); -} - -inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( copysignf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( fmaxf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline float maxElem( Point3 pnt ) -{ - vec_float4 result; - result = fmaxf4( spu_promote( spu_extract( pnt.get128(), 1 ), 0 ), pnt.get128() ); - result = fmaxf4( spu_promote( spu_extract( pnt.get128(), 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ) -{ - return Point3( fminf4( pnt0.get128(), pnt1.get128() ) ); -} - -inline float minElem( Point3 pnt ) -{ - vec_float4 result; - result = fminf4( spu_promote( spu_extract( pnt.get128(), 1 ), 0 ), pnt.get128() ); - result = fminf4( spu_promote( spu_extract( pnt.get128(), 2 ), 0 ), result ); - return spu_extract( result, 0 ); -} - -inline float sum( Point3 pnt ) -{ - return - spu_extract( pnt.get128(), 0 ) + - spu_extract( pnt.get128(), 1 ) + - spu_extract( pnt.get128(), 2 ); -} - -inline const Point3 scale( Point3 pnt, float scaleVal ) -{ - return mulPerElem( pnt, Point3( scaleVal ) ); -} - -inline const Point3 scale( Point3 pnt, Vector3 scaleVec ) -{ - return mulPerElem( pnt, Point3( scaleVec ) ); -} - -inline float projection( Point3 pnt, Vector3 unitVec ) -{ - return spu_extract( _vmathVfDot3( pnt.get128(), unitVec.get128() ), 0 ); -} - -inline float distSqrFromOrigin( Point3 pnt ) -{ - return lengthSqr( Vector3( pnt ) ); -} - -inline float distFromOrigin( Point3 pnt ) -{ - return length( Vector3( pnt ) ); -} - -inline float distSqr( Point3 pnt0, Point3 pnt1 ) -{ - return lengthSqr( ( pnt1 - pnt0 ) ); -} - -inline float dist( Point3 pnt0, Point3 pnt1 ) -{ - return length( ( pnt1 - pnt0 ) ); -} - -inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ) -{ - return Point3( spu_sel( pnt0.get128(), pnt1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); -} - -#ifdef _VECTORMATH_DEBUG - -inline void print( Point3 pnt ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt.get128(); - printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -inline void print( Point3 pnt, const char * name ) -{ - union { vec_float4 v; float s[4]; } tmp; - tmp.v = pnt.get128(); - printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); -} - -#endif - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VEC_AOS_CPP_H +#define _VECTORMATH_VEC_AOS_CPP_H +//----------------------------------------------------------------------------- +// Constants +// for shuffles, words are labeled [x,y,z,w] [a,b,c,d] + +#define _VECTORMATH_SHUF_X 0x00010203 +#define _VECTORMATH_SHUF_Y 0x04050607 +#define _VECTORMATH_SHUF_Z 0x08090a0b +#define _VECTORMATH_SHUF_W 0x0c0d0e0f +#define _VECTORMATH_SHUF_A 0x10111213 +#define _VECTORMATH_SHUF_B 0x14151617 +#define _VECTORMATH_SHUF_C 0x18191a1b +#define _VECTORMATH_SHUF_D 0x1c1d1e1f +#define _VECTORMATH_SHUF_0 0x80808080 +#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } +#define _VECTORMATH_SHUF_ZXYW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_W } +#define _VECTORMATH_SHUF_YZXW (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_W } +#define _VECTORMATH_SHUF_WABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } +#define _VECTORMATH_SHUF_ZWAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_W, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } +#define _VECTORMATH_SHUF_XYZA (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_X, _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A } +#define _VECTORMATH_SHUF_YZAB (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Y, _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B } +#define _VECTORMATH_SHUF_ZABC (vec_uchar16)(vec_uint4){ _VECTORMATH_SHUF_Z, _VECTORMATH_SHUF_A, _VECTORMATH_SHUF_B, _VECTORMATH_SHUF_C } +#define _VECTORMATH_UNIT_1000 (vec_float4){ 1.0f, 0.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0100 (vec_float4){ 0.0f, 1.0f, 0.0f, 0.0f } +#define _VECTORMATH_UNIT_0010 (vec_float4){ 0.0f, 0.0f, 1.0f, 0.0f } +#define _VECTORMATH_UNIT_0001 (vec_float4){ 0.0f, 0.0f, 0.0f, 1.0f } +#define _VECTORMATH_SLERP_TOL 0.999f + +//----------------------------------------------------------------------------- +// Definitions + +#ifndef _VECTORMATH_INTERNAL_FUNCTIONS +#define _VECTORMATH_INTERNAL_FUNCTIONS + +static inline vec_float4 _vmathVfDot3( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = spu_mul( vec0, vec1 ); + result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); + return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); +} + +static inline vec_float4 _vmathVfDot4( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 result; + result = spu_mul( vec0, vec1 ); + result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); + return spu_add( spu_rlqwbyte( result, 8 ), result ); +} + +static inline vec_float4 _vmathVfCross( vec_float4 vec0, vec_float4 vec1 ) +{ + vec_float4 tmp0, tmp1, tmp2, tmp3, result; + tmp0 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_YZXW ); + tmp1 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_ZXYW ); + tmp2 = spu_shuffle( vec0, vec0, _VECTORMATH_SHUF_ZXYW ); + tmp3 = spu_shuffle( vec1, vec1, _VECTORMATH_SHUF_YZXW ); + result = spu_mul( tmp0, tmp1 ); + result = spu_nmsub( tmp2, tmp3, result ); + return result; +} + +static inline vec_uint4 _vmathVfToHalfFloatsUnpacked(vec_float4 v) +{ + vec_int4 bexp; + vec_uint4 mant, sign, hfloat; + vec_uint4 notZero, isInf; + const vec_uint4 hfloatInf = spu_splats(0x00007c00u); + const vec_uint4 mergeMant = spu_splats(0x000003ffu); + const vec_uint4 mergeSign = spu_splats(0x00008000u); + + sign = spu_rlmask((vec_uint4)v, -16); + mant = spu_rlmask((vec_uint4)v, -13); + bexp = spu_and(spu_rlmask((vec_int4)v, -23), 0xff); + + notZero = spu_cmpgt(bexp, 112); + isInf = spu_cmpgt(bexp, 142); + + bexp = spu_add(bexp, -112); + bexp = spu_sl(bexp, 10); + + hfloat = spu_sel((vec_uint4)bexp, mant, mergeMant); + hfloat = spu_sel(spu_splats(0u), hfloat, notZero); + hfloat = spu_sel(hfloat, hfloatInf, isInf); + hfloat = spu_sel(hfloat, sign, mergeSign); + + return hfloat; +} + +static inline vec_ushort8 _vmath2VfToHalfFloats(vec_float4 u, vec_float4 v) +{ + vec_uint4 hfloat_u, hfloat_v; + const vec_uchar16 pack = (vec_uchar16){2,3,6,7,10,11,14,15,18,19,22,23,26,27,30,31}; + hfloat_u = _vmathVfToHalfFloatsUnpacked(u); + hfloat_v = _vmathVfToHalfFloatsUnpacked(v); + return (vec_ushort8)spu_shuffle(hfloat_u, hfloat_v, pack); +} + +#endif + +namespace Vectormath { +namespace Aos { + +inline VecIdx::operator float() const +{ + return spu_extract( ref, i ); +} + +inline float VecIdx::operator =( float scalar ) +{ + ref = spu_insert( scalar, ref, i ); + return scalar; +} + +inline float VecIdx::operator =( const VecIdx& scalar ) +{ + return *this = float(scalar); +} + +inline float VecIdx::operator *=( float scalar ) +{ + float tmp = spu_extract( ref, i ) * scalar; + ref = spu_insert( tmp, ref, i ); + return tmp; +} + +inline float VecIdx::operator /=( float scalar ) +{ + float tmp = spu_extract( ref, i ) / scalar; + ref = spu_insert( tmp, ref, i ); + return tmp; +} + +inline float VecIdx::operator +=( float scalar ) +{ + float tmp = spu_extract( ref, i ) + scalar; + ref = spu_insert( tmp, ref, i ); + return tmp; +} + +inline float VecIdx::operator -=( float scalar ) +{ + float tmp = spu_extract( ref, i ) - scalar; + ref = spu_insert( tmp, ref, i ); + return tmp; +} + +inline Vector3::Vector3( float _x, float _y, float _z ) +{ + mVec128 = (vec_float4){ _x, _y, _z, 0.0f }; +} + +inline Vector3::Vector3( Point3 pnt ) +{ + mVec128 = pnt.get128(); +} + +inline Vector3::Vector3( float scalar ) +{ + mVec128 = spu_splats( scalar ); +} + +inline Vector3::Vector3( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Vector3 Vector3::xAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_1000 ); +} + +inline const Vector3 Vector3::yAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_0100 ); +} + +inline const Vector3 Vector3::zAxis( ) +{ + return Vector3( _VECTORMATH_UNIT_0010 ); +} + +inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ) +{ + return ( vec0 + ( ( vec1 - vec0 ) * t ) ); +} + +inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot3( unitVec0.get128(), unitVec1.get128() ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + return Vector3( spu_madd( unitVec0.get128(), scale0, spu_mul( unitVec1.get128(), scale1 ) ) ); +} + +inline vec_float4 Vector3::get128( ) const +{ + return mVec128; +} + +inline void loadXYZ( Vector3 & vec, const vec_float4 * quad ) +{ + vec = Vector3( *quad ); +} + +inline void loadXYZ( Vector3 & vec, const float * fptr ) +{ + const vec_float4 vfsrc0 = *((vec_float4*)((uintptr_t)fptr)); + const vec_float4 vfsrc1 = *((vec_float4*)(((uintptr_t)fptr) + 16)); + const vec_uchar16 vucpat = (vec_uchar16)spu_add((vec_ushort8)(spu_splats((unsigned char)(((int)fptr) & 0xf))),((vec_ushort8){0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F})); + const vec_float4 vfval = spu_shuffle(vfsrc0, vfsrc1, vucpat); + vec = Vector3( vfval ); +} + +inline void storeXYZ( Vector3 vec, vec_float4 * quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); + dstVec = spu_sel(vec.get128(), dstVec, mask); + *quad = dstVec; +} + +inline void storeXYZ( Vector3 vec, float * fptr ) +{ + vec_float4 * vptr0 = (vec_float4*)((uintptr_t)fptr); + vec_float4 * vptr1 = (vec_float4*)(((uintptr_t)fptr) + 16); + vec_float4 dstVec0 = *vptr0; + vec_float4 dstVec1 = *vptr1; + uint32_t offset = (uint32_t)fptr & 0xf; + vec_uint4 mask = (vec_uint4)spu_maskb(0xfff0); + vec_uint4 mask0 = (vec_uint4)spu_rlmaskqwbyte(mask, -offset); + vec_uint4 mask1 = (vec_uint4)spu_slqwbyte(mask, 16 - offset); + vec_float4 vec0 = spu_rlmaskqwbyte(vec.get128(), -offset); + vec_float4 vec1 = spu_slqwbyte(vec.get128(), 16 - offset); + dstVec0 = spu_sel(dstVec0, vec0, mask0); + dstVec1 = spu_sel(dstVec1, vec1, mask1); + *vptr0 = dstVec0; + *vptr1 = dstVec1; +} + +inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); + xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); + xyz3 = spu_rlqwbyte( zxyz, 4 ); + vec0 = Vector3( xyzx ); + vec1 = Vector3( xyz1 ); + vec2 = Vector3( xyz2 ); + vec3 = Vector3( xyz3 ); +} + +inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = spu_shuffle( vec0.get128(), vec1.get128(), _VECTORMATH_SHUF_XYZA ); + yzxy = spu_shuffle( vec1.get128(), vec2.get128(), _VECTORMATH_SHUF_YZAB ); + zxyz = spu_shuffle( vec2.get128(), vec3.get128(), _VECTORMATH_SHUF_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + storeXYZArray( vec0, vec1, vec2, vec3, xyz0 ); + storeXYZArray( vec4, vec5, vec6, vec7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +inline Vector3 & Vector3::operator =( Vector3 vec ) +{ + mVec128 = vec.mVec128; + return *this; +} + +inline Vector3 & Vector3::setX( float _x ) +{ + mVec128 = spu_insert( _x, mVec128, 0 ); + return *this; +} + +inline float Vector3::getX( ) const +{ + return spu_extract( mVec128, 0 ); +} + +inline Vector3 & Vector3::setY( float _y ) +{ + mVec128 = spu_insert( _y, mVec128, 1 ); + return *this; +} + +inline float Vector3::getY( ) const +{ + return spu_extract( mVec128, 1 ); +} + +inline Vector3 & Vector3::setZ( float _z ) +{ + mVec128 = spu_insert( _z, mVec128, 2 ); + return *this; +} + +inline float Vector3::getZ( ) const +{ + return spu_extract( mVec128, 2 ); +} + +inline Vector3 & Vector3::setElem( int idx, float value ) +{ + mVec128 = spu_insert( value, mVec128, idx ); + return *this; +} + +inline float Vector3::getElem( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline VecIdx Vector3::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline float Vector3::operator []( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline const Vector3 Vector3::operator +( Vector3 vec ) const +{ + return Vector3( spu_add( mVec128, vec.mVec128 ) ); +} + +inline const Vector3 Vector3::operator -( Vector3 vec ) const +{ + return Vector3( spu_sub( mVec128, vec.mVec128 ) ); +} + +inline const Point3 Vector3::operator +( Point3 pnt ) const +{ + return Point3( spu_add( mVec128, pnt.get128() ) ); +} + +inline const Vector3 Vector3::operator *( float scalar ) const +{ + return Vector3( spu_mul( mVec128, spu_splats(scalar) ) ); +} + +inline Vector3 & Vector3::operator +=( Vector3 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Vector3 & Vector3::operator -=( Vector3 vec ) +{ + *this = *this - vec; + return *this; +} + +inline Vector3 & Vector3::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Vector3 Vector3::operator /( float scalar ) const +{ + return Vector3( divf4( mVec128, spu_splats(scalar) ) ); +} + +inline Vector3 & Vector3::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline const Vector3 Vector3::operator -( ) const +{ + return Vector3( negatef4( mVec128 ) ); +} + +inline const Vector3 operator *( float scalar, Vector3 vec ) +{ + return vec * scalar; +} + +inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( spu_mul( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( divf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 recipPerElem( Vector3 vec ) +{ + return Vector3( recipf4( vec.get128() ) ); +} + +inline const Vector3 sqrtPerElem( Vector3 vec ) +{ + return Vector3( sqrtf4( vec.get128() ) ); +} + +inline const Vector3 rsqrtPerElem( Vector3 vec ) +{ + return Vector3( rsqrtf4( vec.get128() ) ); +} + +inline const Vector3 absPerElem( Vector3 vec ) +{ + return Vector3( fabsf4( vec.get128() ) ); +} + +inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( copysignf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( fmaxf4( vec0.get128(), vec1.get128() ) ); +} + +inline float maxElem( Vector3 vec ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); + result = fmaxf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( fminf4( vec0.get128(), vec1.get128() ) ); +} + +inline float minElem( Vector3 vec ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); + result = fminf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline float sum( Vector3 vec ) +{ + return + spu_extract( vec.get128(), 0 ) + + spu_extract( vec.get128(), 1 ) + + spu_extract( vec.get128(), 2 ); +} + +inline float dot( Vector3 vec0, Vector3 vec1 ) +{ + return spu_extract( _vmathVfDot3( vec0.get128(), vec1.get128() ), 0 ); +} + +inline float lengthSqr( Vector3 vec ) +{ + return spu_extract( _vmathVfDot3( vec.get128(), vec.get128() ), 0 ); +} + +inline float length( Vector3 vec ) +{ + return sqrtf( lengthSqr( vec ) ); +} + +inline const Vector3 normalize( Vector3 vec ) +{ + vec_float4 dot = _vmathVfDot3( vec.get128(), vec.get128() ); + dot = spu_shuffle( dot, dot, (vec_uchar16)spu_splats(0x00010203) ); + return Vector3( spu_mul( vec.get128(), rsqrtf4( dot ) ) ); +} + +inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ) +{ + return Vector3( _vmathVfCross( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ) +{ + return Vector3( spu_sel( vec0.get128(), vec1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Vector3 vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +inline void print( Vector3 vec, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +inline Vector4::Vector4( float _x, float _y, float _z, float _w ) +{ + mVec128 = (vec_float4){ _x, _y, _z, _w }; +} + +inline Vector4::Vector4( Vector3 xyz, float _w ) +{ + mVec128 = spu_shuffle( xyz.get128(), spu_promote( _w, 0 ), _VECTORMATH_SHUF_XYZA ); +} + +inline Vector4::Vector4( Vector3 vec ) +{ + mVec128 = spu_sel( vec.get128(), spu_splats(0.0f), (vec_uint4)spu_maskb(0x000f) ); +} + +inline Vector4::Vector4( Point3 pnt ) +{ + mVec128 = spu_sel( pnt.get128(), spu_splats(1.0f), (vec_uint4)spu_maskb(0x000f) ); +} + +inline Vector4::Vector4( Quat quat ) +{ + mVec128 = quat.get128(); +} + +inline Vector4::Vector4( float scalar ) +{ + mVec128 = spu_splats( scalar ); +} + +inline Vector4::Vector4( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Vector4 Vector4::xAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_1000 ); +} + +inline const Vector4 Vector4::yAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0100 ); +} + +inline const Vector4 Vector4::zAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0010 ); +} + +inline const Vector4 Vector4::wAxis( ) +{ + return Vector4( _VECTORMATH_UNIT_0001 ); +} + +inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ) +{ + return ( vec0 + ( ( vec1 - vec0 ) * t ) ); +} + +inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ) +{ + vec_float4 scales, scale0, scale1, cosAngle, angle, tttt, oneMinusT, angles, sines; + vec_uint4 selectMask; + vec_uchar16 shuffle_xxxx = (vec_uchar16)spu_splats((int)0x00010203); + vec_uchar16 shuffle_yyyy = (vec_uchar16)spu_splats((int)0x04050607); + vec_uchar16 shuffle_zzzz = (vec_uchar16)spu_splats((int)0x08090a0b); + cosAngle = _vmathVfDot4( unitVec0.get128(), unitVec1.get128() ); + cosAngle = spu_shuffle( cosAngle, cosAngle, shuffle_xxxx ); + selectMask = (vec_uint4)spu_cmpgt( spu_splats(_VECTORMATH_SLERP_TOL), cosAngle ); + angle = acosf4( cosAngle ); + tttt = spu_splats(t); + oneMinusT = spu_sub( spu_splats(1.0f), tttt ); + angles = spu_sel( spu_splats(1.0f), oneMinusT, (vec_uint4)spu_maskb(0x0f00) ); + angles = spu_sel( angles, tttt, (vec_uint4)spu_maskb(0x00f0) ); + angles = spu_mul( angles, angle ); + sines = sinf4( angles ); + scales = divf4( sines, spu_shuffle( sines, sines, shuffle_xxxx ) ); + scale0 = spu_sel( oneMinusT, spu_shuffle( scales, scales, shuffle_yyyy ), selectMask ); + scale1 = spu_sel( tttt, spu_shuffle( scales, scales, shuffle_zzzz ), selectMask ); + return Vector4( spu_madd( unitVec0.get128(), scale0, spu_mul( unitVec1.get128(), scale1 ) ) ); +} + +inline vec_float4 Vector4::get128( ) const +{ + return mVec128; +} + +inline void loadXYZW( Vector4 & vec, const vec_float4 * quad ) +{ + vec = Vector4( *quad ); +} + +inline void loadXYZW( Vector4 & vec, const float * fptr ) +{ + const vec_float4 vfsrc0 = *((vec_float4*)((uintptr_t)fptr)); + const vec_float4 vfsrc1 = *((vec_float4*)(((uintptr_t)fptr) + 16)); + const vec_uchar16 vucpat = (vec_uchar16)spu_add((vec_ushort8)(spu_splats((unsigned char)(((int)fptr) & 0xf))), ((vec_ushort8){0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F})); + const vec_float4 vfval = spu_shuffle(vfsrc0, vfsrc1, vucpat); + vec = Vector4( vfval ); +} + +inline void storeXYZW( Vector4 vec, float * fptr ) +{ + vec_float4 * vptr0 = (vec_float4*)((uintptr_t)fptr); + vec_float4 * vptr1 = (vec_float4*)(((uintptr_t)fptr) + 16); + vec_float4 dstVec0 = *vptr0; + vec_float4 dstVec1 = *vptr1; + uint32_t offset = (uint32_t)fptr & 0xf; + vec_uint4 mask = (vec_uint4)spu_splats(0xffffffff); + vec_uint4 mask0 = (vec_uint4)spu_rlmaskqwbyte(mask, -offset); + vec_uint4 mask1 = (vec_uint4)spu_slqwbyte(mask, 16 - offset); + vec_float4 vec0 = spu_rlmaskqwbyte(vec.get128(), -offset); + vec_float4 vec1 = spu_slqwbyte(vec.get128(), 16 - offset); + dstVec0 = spu_sel(dstVec0, vec0, mask0); + dstVec1 = spu_sel(dstVec1, vec1, mask1); + *vptr0 = dstVec0; + *vptr1 = dstVec1; +} + +inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ) +{ + twoQuads[0] = _vmath2VfToHalfFloats(vec0.get128(), vec1.get128()); + twoQuads[1] = _vmath2VfToHalfFloats(vec2.get128(), vec3.get128()); +} + +inline Vector4 & Vector4::operator =( Vector4 vec ) +{ + mVec128 = vec.mVec128; + return *this; +} + +inline Vector4 & Vector4::setXYZ( Vector3 vec ) +{ + mVec128 = spu_sel( vec.get128(), mVec128, (vec_uint4)spu_maskb(0x000f) ); + return *this; +} + +inline const Vector3 Vector4::getXYZ( ) const +{ + return Vector3( mVec128 ); +} + +inline Vector4 & Vector4::setX( float _x ) +{ + mVec128 = spu_insert( _x, mVec128, 0 ); + return *this; +} + +inline float Vector4::getX( ) const +{ + return spu_extract( mVec128, 0 ); +} + +inline Vector4 & Vector4::setY( float _y ) +{ + mVec128 = spu_insert( _y, mVec128, 1 ); + return *this; +} + +inline float Vector4::getY( ) const +{ + return spu_extract( mVec128, 1 ); +} + +inline Vector4 & Vector4::setZ( float _z ) +{ + mVec128 = spu_insert( _z, mVec128, 2 ); + return *this; +} + +inline float Vector4::getZ( ) const +{ + return spu_extract( mVec128, 2 ); +} + +inline Vector4 & Vector4::setW( float _w ) +{ + mVec128 = spu_insert( _w, mVec128, 3 ); + return *this; +} + +inline float Vector4::getW( ) const +{ + return spu_extract( mVec128, 3 ); +} + +inline Vector4 & Vector4::setElem( int idx, float value ) +{ + mVec128 = spu_insert( value, mVec128, idx ); + return *this; +} + +inline float Vector4::getElem( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline VecIdx Vector4::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline float Vector4::operator []( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline const Vector4 Vector4::operator +( Vector4 vec ) const +{ + return Vector4( spu_add( mVec128, vec.mVec128 ) ); +} + +inline const Vector4 Vector4::operator -( Vector4 vec ) const +{ + return Vector4( spu_sub( mVec128, vec.mVec128 ) ); +} + +inline const Vector4 Vector4::operator *( float scalar ) const +{ + return Vector4( spu_mul( mVec128, spu_splats(scalar) ) ); +} + +inline Vector4 & Vector4::operator +=( Vector4 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Vector4 & Vector4::operator -=( Vector4 vec ) +{ + *this = *this - vec; + return *this; +} + +inline Vector4 & Vector4::operator *=( float scalar ) +{ + *this = *this * scalar; + return *this; +} + +inline const Vector4 Vector4::operator /( float scalar ) const +{ + return Vector4( divf4( mVec128, spu_splats(scalar) ) ); +} + +inline Vector4 & Vector4::operator /=( float scalar ) +{ + *this = *this / scalar; + return *this; +} + +inline const Vector4 Vector4::operator -( ) const +{ + return Vector4( negatef4( mVec128 ) ); +} + +inline const Vector4 operator *( float scalar, Vector4 vec ) +{ + return vec * scalar; +} + +inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( spu_mul( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( divf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector4 recipPerElem( Vector4 vec ) +{ + return Vector4( recipf4( vec.get128() ) ); +} + +inline const Vector4 sqrtPerElem( Vector4 vec ) +{ + return Vector4( sqrtf4( vec.get128() ) ); +} + +inline const Vector4 rsqrtPerElem( Vector4 vec ) +{ + return Vector4( rsqrtf4( vec.get128() ) ); +} + +inline const Vector4 absPerElem( Vector4 vec ) +{ + return Vector4( fabsf4( vec.get128() ) ); +} + +inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( copysignf4( vec0.get128(), vec1.get128() ) ); +} + +inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( fmaxf4( vec0.get128(), vec1.get128() ) ); +} + +inline float maxElem( Vector4 vec ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); + result = fmaxf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); + result = fmaxf4( spu_promote( spu_extract( vec.get128(), 3 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ) +{ + return Vector4( fminf4( vec0.get128(), vec1.get128() ) ); +} + +inline float minElem( Vector4 vec ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( vec.get128(), 1 ), 0 ), vec.get128() ); + result = fminf4( spu_promote( spu_extract( vec.get128(), 2 ), 0 ), result ); + result = fminf4( spu_promote( spu_extract( vec.get128(), 3 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline float sum( Vector4 vec ) +{ + return + spu_extract( vec.get128(), 0 ) + + spu_extract( vec.get128(), 1 ) + + spu_extract( vec.get128(), 2 ) + + spu_extract( vec.get128(), 3 ); +} + +inline float dot( Vector4 vec0, Vector4 vec1 ) +{ + return spu_extract( _vmathVfDot4( vec0.get128(), vec1.get128() ), 0 ); +} + +inline float lengthSqr( Vector4 vec ) +{ + return spu_extract( _vmathVfDot4( vec.get128(), vec.get128() ), 0 ); +} + +inline float length( Vector4 vec ) +{ + return sqrtf( lengthSqr( vec ) ); +} + +inline const Vector4 normalize( Vector4 vec ) +{ + vec_float4 dot = _vmathVfDot4( vec.get128(), vec.get128() ); + return Vector4( spu_mul( vec.get128(), rsqrtf4( dot ) ) ); +} + +inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ) +{ + return Vector4( spu_sel( vec0.get128(), vec1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Vector4 vec ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "( %f %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +inline void print( Vector4 vec, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = vec.get128(); + printf( "%s: ( %f %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2], tmp.s[3] ); +} + +#endif + +inline Point3::Point3( float _x, float _y, float _z ) +{ + mVec128 = (vec_float4){ _x, _y, _z, 0.0f }; +} + +inline Point3::Point3( Vector3 vec ) +{ + mVec128 = vec.get128(); +} + +inline Point3::Point3( float scalar ) +{ + mVec128 = spu_splats( scalar ); +} + +inline Point3::Point3( vec_float4 vf4 ) +{ + mVec128 = vf4; +} + +inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ) +{ + return ( pnt0 + ( ( pnt1 - pnt0 ) * t ) ); +} + +inline vec_float4 Point3::get128( ) const +{ + return mVec128; +} + +inline void loadXYZ( Point3 & pnt, const vec_float4 * quad ) +{ + pnt = Point3( *quad ); +} + +inline void loadXYZ( Point3 & pnt, const float * fptr ) +{ + const vec_float4 vfsrc0 = *((vec_float4*)((uintptr_t)fptr)); + const vec_float4 vfsrc1 = *((vec_float4*)(((uintptr_t)fptr) + 16)); + const vec_uchar16 vucpat = (vec_uchar16)spu_add((vec_ushort8)(spu_splats((unsigned char)(((int)fptr) & 0xf))),((vec_ushort8){0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F})); + const vec_float4 vfval = spu_shuffle(vfsrc0, vfsrc1, vucpat); + pnt = Point3( vfval ); +} + +inline void storeXYZ( Point3 pnt, vec_float4 * quad ) +{ + vec_float4 dstVec = *quad; + vec_uint4 mask = (vec_uint4)spu_maskb(0x000f); + dstVec = spu_sel(pnt.get128(), dstVec, mask); + *quad = dstVec; +} + +inline void storeXYZ( Point3 pnt, float * fptr ) +{ + vec_float4 * vptr0 = (vec_float4*)((uintptr_t)fptr); + vec_float4 * vptr1 = (vec_float4*)(((uintptr_t)fptr) + 16); + vec_float4 dstVec0 = *vptr0; + vec_float4 dstVec1 = *vptr1; + uint32_t offset = (uint32_t)fptr & 0xf; + vec_uint4 mask = (vec_uint4)spu_maskb(0xfff0); + vec_uint4 mask0 = (vec_uint4)spu_rlmaskqwbyte(mask, -offset); + vec_uint4 mask1 = (vec_uint4)spu_slqwbyte(mask, 16 - offset); + vec_float4 vec0 = spu_rlmaskqwbyte(pnt.get128(), -offset); + vec_float4 vec1 = spu_slqwbyte(pnt.get128(), 16 - offset); + dstVec0 = spu_sel(dstVec0, vec0, mask0); + dstVec1 = spu_sel(dstVec1, vec1, mask1); + *vptr0 = dstVec0; + *vptr1 = dstVec1; +} + +inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz, xyz1, xyz2, xyz3; + xyzx = threeQuads[0]; + yzxy = threeQuads[1]; + zxyz = threeQuads[2]; + xyz1 = spu_shuffle( xyzx, yzxy, _VECTORMATH_SHUF_WABC ); + xyz2 = spu_shuffle( yzxy, zxyz, _VECTORMATH_SHUF_ZWAB ); + xyz3 = spu_rlqwbyte( zxyz, 4 ); + pnt0 = Point3( xyzx ); + pnt1 = Point3( xyz1 ); + pnt2 = Point3( xyz2 ); + pnt3 = Point3( xyz3 ); +} + +inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ) +{ + vec_float4 xyzx, yzxy, zxyz; + xyzx = spu_shuffle( pnt0.get128(), pnt1.get128(), _VECTORMATH_SHUF_XYZA ); + yzxy = spu_shuffle( pnt1.get128(), pnt2.get128(), _VECTORMATH_SHUF_YZAB ); + zxyz = spu_shuffle( pnt2.get128(), pnt3.get128(), _VECTORMATH_SHUF_ZABC ); + threeQuads[0] = xyzx; + threeQuads[1] = yzxy; + threeQuads[2] = zxyz; +} + +inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ) +{ + vec_float4 xyz0[3]; + vec_float4 xyz1[3]; + storeXYZArray( pnt0, pnt1, pnt2, pnt3, xyz0 ); + storeXYZArray( pnt4, pnt5, pnt6, pnt7, xyz1 ); + threeQuads[0] = _vmath2VfToHalfFloats(xyz0[0], xyz0[1]); + threeQuads[1] = _vmath2VfToHalfFloats(xyz0[2], xyz1[0]); + threeQuads[2] = _vmath2VfToHalfFloats(xyz1[1], xyz1[2]); +} + +inline Point3 & Point3::operator =( Point3 pnt ) +{ + mVec128 = pnt.mVec128; + return *this; +} + +inline Point3 & Point3::setX( float _x ) +{ + mVec128 = spu_insert( _x, mVec128, 0 ); + return *this; +} + +inline float Point3::getX( ) const +{ + return spu_extract( mVec128, 0 ); +} + +inline Point3 & Point3::setY( float _y ) +{ + mVec128 = spu_insert( _y, mVec128, 1 ); + return *this; +} + +inline float Point3::getY( ) const +{ + return spu_extract( mVec128, 1 ); +} + +inline Point3 & Point3::setZ( float _z ) +{ + mVec128 = spu_insert( _z, mVec128, 2 ); + return *this; +} + +inline float Point3::getZ( ) const +{ + return spu_extract( mVec128, 2 ); +} + +inline Point3 & Point3::setElem( int idx, float value ) +{ + mVec128 = spu_insert( value, mVec128, idx ); + return *this; +} + +inline float Point3::getElem( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline VecIdx Point3::operator []( int idx ) +{ + return VecIdx( mVec128, idx ); +} + +inline float Point3::operator []( int idx ) const +{ + return spu_extract( mVec128, idx ); +} + +inline const Vector3 Point3::operator -( Point3 pnt ) const +{ + return Vector3( spu_sub( mVec128, pnt.mVec128 ) ); +} + +inline const Point3 Point3::operator +( Vector3 vec ) const +{ + return Point3( spu_add( mVec128, vec.get128() ) ); +} + +inline const Point3 Point3::operator -( Vector3 vec ) const +{ + return Point3( spu_sub( mVec128, vec.get128() ) ); +} + +inline Point3 & Point3::operator +=( Vector3 vec ) +{ + *this = *this + vec; + return *this; +} + +inline Point3 & Point3::operator -=( Vector3 vec ) +{ + *this = *this - vec; + return *this; +} + +inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( spu_mul( pnt0.get128(), pnt1.get128() ) ); +} + +inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( divf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const Point3 recipPerElem( Point3 pnt ) +{ + return Point3( recipf4( pnt.get128() ) ); +} + +inline const Point3 sqrtPerElem( Point3 pnt ) +{ + return Point3( sqrtf4( pnt.get128() ) ); +} + +inline const Point3 rsqrtPerElem( Point3 pnt ) +{ + return Point3( rsqrtf4( pnt.get128() ) ); +} + +inline const Point3 absPerElem( Point3 pnt ) +{ + return Point3( fabsf4( pnt.get128() ) ); +} + +inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( copysignf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( fmaxf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline float maxElem( Point3 pnt ) +{ + vec_float4 result; + result = fmaxf4( spu_promote( spu_extract( pnt.get128(), 1 ), 0 ), pnt.get128() ); + result = fmaxf4( spu_promote( spu_extract( pnt.get128(), 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ) +{ + return Point3( fminf4( pnt0.get128(), pnt1.get128() ) ); +} + +inline float minElem( Point3 pnt ) +{ + vec_float4 result; + result = fminf4( spu_promote( spu_extract( pnt.get128(), 1 ), 0 ), pnt.get128() ); + result = fminf4( spu_promote( spu_extract( pnt.get128(), 2 ), 0 ), result ); + return spu_extract( result, 0 ); +} + +inline float sum( Point3 pnt ) +{ + return + spu_extract( pnt.get128(), 0 ) + + spu_extract( pnt.get128(), 1 ) + + spu_extract( pnt.get128(), 2 ); +} + +inline const Point3 scale( Point3 pnt, float scaleVal ) +{ + return mulPerElem( pnt, Point3( scaleVal ) ); +} + +inline const Point3 scale( Point3 pnt, Vector3 scaleVec ) +{ + return mulPerElem( pnt, Point3( scaleVec ) ); +} + +inline float projection( Point3 pnt, Vector3 unitVec ) +{ + return spu_extract( _vmathVfDot3( pnt.get128(), unitVec.get128() ), 0 ); +} + +inline float distSqrFromOrigin( Point3 pnt ) +{ + return lengthSqr( Vector3( pnt ) ); +} + +inline float distFromOrigin( Point3 pnt ) +{ + return length( Vector3( pnt ) ); +} + +inline float distSqr( Point3 pnt0, Point3 pnt1 ) +{ + return lengthSqr( ( pnt1 - pnt0 ) ); +} + +inline float dist( Point3 pnt0, Point3 pnt1 ) +{ + return length( ( pnt1 - pnt0 ) ); +} + +inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ) +{ + return Point3( spu_sel( pnt0.get128(), pnt1.get128(), spu_splats( (unsigned int)-(select1 > 0) ) ) ); +} + +#ifdef _VECTORMATH_DEBUG + +inline void print( Point3 pnt ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt.get128(); + printf( "( %f %f %f )\n", tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +inline void print( Point3 pnt, const char * name ) +{ + union { vec_float4 v; float s[4]; } tmp; + tmp.v = pnt.get128(); + printf( "%s: ( %f %f %f )\n", name, tmp.s[0], tmp.s[1], tmp.s[2] ); +} + +#endif + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/spu/cpp/vecidx_aos.h b/common/vectormath/spu/cpp/vecidx_aos.h index f5309153..e46578ad 100644 --- a/common/vectormath/spu/cpp/vecidx_aos.h +++ b/common/vectormath/spu/cpp/vecidx_aos.h @@ -1,64 +1,64 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_VECIDX_AOS_H -#define _VECTORMATH_VECIDX_AOS_H - -#include - -namespace Vectormath { -namespace Aos { - -//----------------------------------------------------------------------------- -// VecIdx -// Used in setting elements of Vector3, Vector4, Point3, or Quat with the -// subscripting operator. -// - -class VecIdx -{ -private: - typedef vec_float4 vec_float4_t; - vec_float4_t &ref __attribute__ ((aligned(16))); - int i __attribute__ ((aligned(16))); -public: - inline VecIdx( vec_float4& vec, int idx ): ref(vec) { i = idx; } - inline operator float() const; - inline float operator =( float scalar ); - inline float operator =( const VecIdx& scalar ); - inline float operator *=( float scalar ); - inline float operator /=( float scalar ); - inline float operator +=( float scalar ); - inline float operator -=( float scalar ); -}; - -} // namespace Aos -} // namespace Vectormath - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_VECIDX_AOS_H +#define _VECTORMATH_VECIDX_AOS_H + +#include + +namespace Vectormath { +namespace Aos { + +//----------------------------------------------------------------------------- +// VecIdx +// Used in setting elements of Vector3, Vector4, Point3, or Quat with the +// subscripting operator. +// + +class VecIdx +{ +private: + typedef vec_float4 vec_float4_t; + vec_float4_t &ref __attribute__ ((aligned(16))); + int i __attribute__ ((aligned(16))); +public: + inline VecIdx( vec_float4& vec, int idx ): ref(vec) { i = idx; } + inline operator float() const; + inline float operator =( float scalar ); + inline float operator =( const VecIdx& scalar ); + inline float operator *=( float scalar ); + inline float operator /=( float scalar ); + inline float operator +=( float scalar ); + inline float operator -=( float scalar ); +}; + +} // namespace Aos +} // namespace Vectormath + +#endif diff --git a/common/vectormath/spu/cpp/vectormath_aos.h b/common/vectormath/spu/cpp/vectormath_aos.h index f876c538..f7ab35ab 100644 --- a/common/vectormath/spu/cpp/vectormath_aos.h +++ b/common/vectormath/spu/cpp/vectormath_aos.h @@ -1,1851 +1,1901 @@ -/* - Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. - All rights reserved. - - Redistribution and use in source and binary forms, - with or without modification, are permitted provided that the - following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the Sony Computer Entertainment Inc nor the names - of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef _VECTORMATH_AOS_CPP_SPU_H -#define _VECTORMATH_AOS_CPP_SPU_H - -#include -#include -#include "floatInVec.h" -#include "boolInVec.h" -#include "vecidx_aos.h" -#include - -#ifdef _VECTORMATH_DEBUG -#endif - -namespace Vectormath { - -namespace Aos { - -//----------------------------------------------------------------------------- -// Forward Declarations -// - -class Vector3; -class Vector4; -class Point3; -class Quat; -class Matrix3; -class Matrix4; -class Transform3; - -// A 3-D vector in array-of-structures format -// -class Vector3 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Vector3( ) { }; - - // Construct a 3-D vector from x, y, and z elements - // - inline Vector3( float x, float y, float z ); - - // Copy elements from a 3-D point into a 3-D vector - // - explicit inline Vector3( Point3 pnt ); - - // Set all elements of a 3-D vector to the same scalar value - // - explicit inline Vector3( float scalar ); - - // Set vector float data in a 3-D vector - // - explicit inline Vector3( vec_float4 vf4 ); - - // Get vector float data from a 3-D vector - // - inline vec_float4 get128( ) const; - - // Assign one 3-D vector to another - // - inline Vector3 & operator =( Vector3 vec ); - - // Set the x element of a 3-D vector - // - inline Vector3 & setX( float x ); - - // Set the y element of a 3-D vector - // - inline Vector3 & setY( float y ); - - // Set the z element of a 3-D vector - // - inline Vector3 & setZ( float z ); - - // Get the x element of a 3-D vector - // - inline float getX( ) const; - - // Get the y element of a 3-D vector - // - inline float getY( ) const; - - // Get the z element of a 3-D vector - // - inline float getZ( ) const; - - // Set an x, y, or z element of a 3-D vector by index - // - inline Vector3 & setElem( int idx, float value ); - - // Get an x, y, or z element of a 3-D vector by index - // - inline float getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline float operator []( int idx ) const; - - // Add two 3-D vectors - // - inline const Vector3 operator +( Vector3 vec ) const; - - // Subtract a 3-D vector from another 3-D vector - // - inline const Vector3 operator -( Vector3 vec ) const; - - // Add a 3-D vector to a 3-D point - // - inline const Point3 operator +( Point3 pnt ) const; - - // Multiply a 3-D vector by a scalar - // - inline const Vector3 operator *( float scalar ) const; - - // Divide a 3-D vector by a scalar - // - inline const Vector3 operator /( float scalar ) const; - - // Perform compound assignment and addition with a 3-D vector - // - inline Vector3 & operator +=( Vector3 vec ); - - // Perform compound assignment and subtraction by a 3-D vector - // - inline Vector3 & operator -=( Vector3 vec ); - - // Perform compound assignment and multiplication by a scalar - // - inline Vector3 & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Vector3 & operator /=( float scalar ); - - // Negate all elements of a 3-D vector - // - inline const Vector3 operator -( ) const; - - // Construct x axis - // - static inline const Vector3 xAxis( ); - - // Construct y axis - // - static inline const Vector3 yAxis( ); - - // Construct z axis - // - static inline const Vector3 zAxis( ); - -}; - -// Multiply a 3-D vector by a scalar -// -inline const Vector3 operator *( float scalar, Vector3 vec ); - -// Multiply two 3-D vectors per element -// -inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ); - -// Divide two 3-D vectors per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ); - -// Compute the reciprocal of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Vector3 recipPerElem( Vector3 vec ); - -// Compute the square root of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Vector3 sqrtPerElem( Vector3 vec ); - -// Compute the reciprocal square root of a 3-D vector per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Vector3 rsqrtPerElem( Vector3 vec ); - -// Compute the absolute value of a 3-D vector per element -// -inline const Vector3 absPerElem( Vector3 vec ); - -// Copy sign from one 3-D vector to another, per element -// -inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ); - -// Maximum of two 3-D vectors per element -// -inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ); - -// Minimum of two 3-D vectors per element -// -inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ); - -// Maximum element of a 3-D vector -// -inline float maxElem( Vector3 vec ); - -// Minimum element of a 3-D vector -// -inline float minElem( Vector3 vec ); - -// Compute the sum of all elements of a 3-D vector -// -inline float sum( Vector3 vec ); - -// Compute the dot product of two 3-D vectors -// -inline float dot( Vector3 vec0, Vector3 vec1 ); - -// Compute the square of the length of a 3-D vector -// -inline float lengthSqr( Vector3 vec ); - -// Compute the length of a 3-D vector -// -inline float length( Vector3 vec ); - -// Normalize a 3-D vector -// NOTE: -// The result is unpredictable when all elements of vec are at or near zero. -// -inline const Vector3 normalize( Vector3 vec ); - -// Compute cross product of two 3-D vectors -// -inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ); - -// Outer product of two 3-D vectors -// -inline const Matrix3 outer( Vector3 vec0, Vector3 vec1 ); - -// Pre-multiply a row vector by a 3x3 matrix -// NOTE: -// Slower than column post-multiply. -// -inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ); - -// Cross-product matrix of a 3-D vector -// -inline const Matrix3 crossMatrix( Vector3 vec ); - -// Create cross-product matrix and multiply -// NOTE: -// Faster than separately creating a cross-product matrix and multiplying. -// -inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ); - -// Linear interpolation between two 3-D vectors -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ); - -// Spherical linear interpolation between two 3-D vectors -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ); - -// Conditionally select between two 3-D vectors -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ); - -// Store x, y, and z elements of a 3-D vector in the first three words of a quadword. -// The value of the fourth word (the word with the highest address) remains unchanged -// -inline void storeXYZ( Vector3 vec, vec_float4 * quad ); - -// Load four three-float 3-D vectors, stored in three quadwords -// -inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ); - -// Store four 3-D vectors in three quadwords -// -inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ); - -// Store eight 3-D vectors as half-floats -// -inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3-D vector -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector3 vec ); - -// Print a 3-D vector and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector3 vec, const char * name ); - -#endif - -// A 4-D vector in array-of-structures format -// -class Vector4 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Vector4( ) { }; - - // Construct a 4-D vector from x, y, z, and w elements - // - inline Vector4( float x, float y, float z, float w ); - - // Construct a 4-D vector from a 3-D vector and a scalar - // - inline Vector4( Vector3 xyz, float w ); - - // Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 - // - explicit inline Vector4( Vector3 vec ); - - // Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 - // - explicit inline Vector4( Point3 pnt ); - - // Copy elements from a quaternion into a 4-D vector - // - explicit inline Vector4( Quat quat ); - - // Set all elements of a 4-D vector to the same scalar value - // - explicit inline Vector4( float scalar ); - - // Set vector float data in a 4-D vector - // - explicit inline Vector4( vec_float4 vf4 ); - - // Get vector float data from a 4-D vector - // - inline vec_float4 get128( ) const; - - // Assign one 4-D vector to another - // - inline Vector4 & operator =( Vector4 vec ); - - // Set the x, y, and z elements of a 4-D vector - // NOTE: - // This function does not change the w element. - // - inline Vector4 & setXYZ( Vector3 vec ); - - // Get the x, y, and z elements of a 4-D vector - // - inline const Vector3 getXYZ( ) const; - - // Set the x element of a 4-D vector - // - inline Vector4 & setX( float x ); - - // Set the y element of a 4-D vector - // - inline Vector4 & setY( float y ); - - // Set the z element of a 4-D vector - // - inline Vector4 & setZ( float z ); - - // Set the w element of a 4-D vector - // - inline Vector4 & setW( float w ); - - // Get the x element of a 4-D vector - // - inline float getX( ) const; - - // Get the y element of a 4-D vector - // - inline float getY( ) const; - - // Get the z element of a 4-D vector - // - inline float getZ( ) const; - - // Get the w element of a 4-D vector - // - inline float getW( ) const; - - // Set an x, y, z, or w element of a 4-D vector by index - // - inline Vector4 & setElem( int idx, float value ); - - // Get an x, y, z, or w element of a 4-D vector by index - // - inline float getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline float operator []( int idx ) const; - - // Add two 4-D vectors - // - inline const Vector4 operator +( Vector4 vec ) const; - - // Subtract a 4-D vector from another 4-D vector - // - inline const Vector4 operator -( Vector4 vec ) const; - - // Multiply a 4-D vector by a scalar - // - inline const Vector4 operator *( float scalar ) const; - - // Divide a 4-D vector by a scalar - // - inline const Vector4 operator /( float scalar ) const; - - // Perform compound assignment and addition with a 4-D vector - // - inline Vector4 & operator +=( Vector4 vec ); - - // Perform compound assignment and subtraction by a 4-D vector - // - inline Vector4 & operator -=( Vector4 vec ); - - // Perform compound assignment and multiplication by a scalar - // - inline Vector4 & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Vector4 & operator /=( float scalar ); - - // Negate all elements of a 4-D vector - // - inline const Vector4 operator -( ) const; - - // Construct x axis - // - static inline const Vector4 xAxis( ); - - // Construct y axis - // - static inline const Vector4 yAxis( ); - - // Construct z axis - // - static inline const Vector4 zAxis( ); - - // Construct w axis - // - static inline const Vector4 wAxis( ); - -}; - -// Multiply a 4-D vector by a scalar -// -inline const Vector4 operator *( float scalar, Vector4 vec ); - -// Multiply two 4-D vectors per element -// -inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ); - -// Divide two 4-D vectors per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ); - -// Compute the reciprocal of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Vector4 recipPerElem( Vector4 vec ); - -// Compute the square root of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Vector4 sqrtPerElem( Vector4 vec ); - -// Compute the reciprocal square root of a 4-D vector per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Vector4 rsqrtPerElem( Vector4 vec ); - -// Compute the absolute value of a 4-D vector per element -// -inline const Vector4 absPerElem( Vector4 vec ); - -// Copy sign from one 4-D vector to another, per element -// -inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ); - -// Maximum of two 4-D vectors per element -// -inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ); - -// Minimum of two 4-D vectors per element -// -inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ); - -// Maximum element of a 4-D vector -// -inline float maxElem( Vector4 vec ); - -// Minimum element of a 4-D vector -// -inline float minElem( Vector4 vec ); - -// Compute the sum of all elements of a 4-D vector -// -inline float sum( Vector4 vec ); - -// Compute the dot product of two 4-D vectors -// -inline float dot( Vector4 vec0, Vector4 vec1 ); - -// Compute the square of the length of a 4-D vector -// -inline float lengthSqr( Vector4 vec ); - -// Compute the length of a 4-D vector -// -inline float length( Vector4 vec ); - -// Normalize a 4-D vector -// NOTE: -// The result is unpredictable when all elements of vec are at or near zero. -// -inline const Vector4 normalize( Vector4 vec ); - -// Outer product of two 4-D vectors -// -inline const Matrix4 outer( Vector4 vec0, Vector4 vec1 ); - -// Linear interpolation between two 4-D vectors -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ); - -// Spherical linear interpolation between two 4-D vectors -// NOTE: -// The result is unpredictable if the vectors point in opposite directions. -// Does not clamp t between 0 and 1. -// -inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ); - -// Conditionally select between two 4-D vectors -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ); - -// Store four 4-D vectors as half-floats -// -inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 4-D vector -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector4 vec ); - -// Print a 4-D vector and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Vector4 vec, const char * name ); - -#endif - -// A 3-D point in array-of-structures format -// -class Point3 -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Point3( ) { }; - - // Construct a 3-D point from x, y, and z elements - // - inline Point3( float x, float y, float z ); - - // Copy elements from a 3-D vector into a 3-D point - // - explicit inline Point3( Vector3 vec ); - - // Set all elements of a 3-D point to the same scalar value - // - explicit inline Point3( float scalar ); - - // Set vector float data in a 3-D point - // - explicit inline Point3( vec_float4 vf4 ); - - // Get vector float data from a 3-D point - // - inline vec_float4 get128( ) const; - - // Assign one 3-D point to another - // - inline Point3 & operator =( Point3 pnt ); - - // Set the x element of a 3-D point - // - inline Point3 & setX( float x ); - - // Set the y element of a 3-D point - // - inline Point3 & setY( float y ); - - // Set the z element of a 3-D point - // - inline Point3 & setZ( float z ); - - // Get the x element of a 3-D point - // - inline float getX( ) const; - - // Get the y element of a 3-D point - // - inline float getY( ) const; - - // Get the z element of a 3-D point - // - inline float getZ( ) const; - - // Set an x, y, or z element of a 3-D point by index - // - inline Point3 & setElem( int idx, float value ); - - // Get an x, y, or z element of a 3-D point by index - // - inline float getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline float operator []( int idx ) const; - - // Subtract a 3-D point from another 3-D point - // - inline const Vector3 operator -( Point3 pnt ) const; - - // Add a 3-D point to a 3-D vector - // - inline const Point3 operator +( Vector3 vec ) const; - - // Subtract a 3-D vector from a 3-D point - // - inline const Point3 operator -( Vector3 vec ) const; - - // Perform compound assignment and addition with a 3-D vector - // - inline Point3 & operator +=( Vector3 vec ); - - // Perform compound assignment and subtraction by a 3-D vector - // - inline Point3 & operator -=( Vector3 vec ); - -}; - -// Multiply two 3-D points per element -// -inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ); - -// Divide two 3-D points per element -// NOTE: -// Floating-point behavior matches standard library function divf4. -// -inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ); - -// Compute the reciprocal of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function recipf4. -// -inline const Point3 recipPerElem( Point3 pnt ); - -// Compute the square root of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function sqrtf4. -// -inline const Point3 sqrtPerElem( Point3 pnt ); - -// Compute the reciprocal square root of a 3-D point per element -// NOTE: -// Floating-point behavior matches standard library function rsqrtf4. -// -inline const Point3 rsqrtPerElem( Point3 pnt ); - -// Compute the absolute value of a 3-D point per element -// -inline const Point3 absPerElem( Point3 pnt ); - -// Copy sign from one 3-D point to another, per element -// -inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ); - -// Maximum of two 3-D points per element -// -inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ); - -// Minimum of two 3-D points per element -// -inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ); - -// Maximum element of a 3-D point -// -inline float maxElem( Point3 pnt ); - -// Minimum element of a 3-D point -// -inline float minElem( Point3 pnt ); - -// Compute the sum of all elements of a 3-D point -// -inline float sum( Point3 pnt ); - -// Apply uniform scale to a 3-D point -// -inline const Point3 scale( Point3 pnt, float scaleVal ); - -// Apply non-uniform scale to a 3-D point -// -inline const Point3 scale( Point3 pnt, Vector3 scaleVec ); - -// Scalar projection of a 3-D point on a unit-length 3-D vector -// -inline float projection( Point3 pnt, Vector3 unitVec ); - -// Compute the square of the distance of a 3-D point from the coordinate-system origin -// -inline float distSqrFromOrigin( Point3 pnt ); - -// Compute the distance of a 3-D point from the coordinate-system origin -// -inline float distFromOrigin( Point3 pnt ); - -// Compute the square of the distance between two 3-D points -// -inline float distSqr( Point3 pnt0, Point3 pnt1 ); - -// Compute the distance between two 3-D points -// -inline float dist( Point3 pnt0, Point3 pnt1 ); - -// Linear interpolation between two 3-D points -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ); - -// Conditionally select between two 3-D points -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ); - -// Store x, y, and z elements of a 3-D point in the first three words of a quadword. -// The value of the fourth word (the word with the highest address) remains unchanged -// -inline void storeXYZ( Point3 pnt, vec_float4 * quad ); - -// Load four three-float 3-D points, stored in three quadwords -// -inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ); - -// Store four 3-D points in three quadwords -// -inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ); - -// Store eight 3-D points as half-floats -// -inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3-D point -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Point3 pnt ); - -// Print a 3-D point and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Point3 pnt, const char * name ); - -#endif - -// A quaternion in array-of-structures format -// -class Quat -{ - vec_float4 mVec128; - -public: - // Default constructor; does no initialization - // - inline Quat( ) { }; - - // Construct a quaternion from x, y, z, and w elements - // - inline Quat( float x, float y, float z, float w ); - - // Construct a quaternion from a 3-D vector and a scalar - // - inline Quat( Vector3 xyz, float w ); - - // Copy elements from a 4-D vector into a quaternion - // - explicit inline Quat( Vector4 vec ); - - // Convert a rotation matrix to a unit-length quaternion - // - explicit inline Quat( const Matrix3 & rotMat ); - - // Set all elements of a quaternion to the same scalar value - // - explicit inline Quat( float scalar ); - - // Set vector float data in a quaternion - // - explicit inline Quat( vec_float4 vf4 ); - - // Get vector float data from a quaternion - // - inline vec_float4 get128( ) const; - - // Assign one quaternion to another - // - inline Quat & operator =( Quat quat ); - - // Set the x, y, and z elements of a quaternion - // NOTE: - // This function does not change the w element. - // - inline Quat & setXYZ( Vector3 vec ); - - // Get the x, y, and z elements of a quaternion - // - inline const Vector3 getXYZ( ) const; - - // Set the x element of a quaternion - // - inline Quat & setX( float x ); - - // Set the y element of a quaternion - // - inline Quat & setY( float y ); - - // Set the z element of a quaternion - // - inline Quat & setZ( float z ); - - // Set the w element of a quaternion - // - inline Quat & setW( float w ); - - // Get the x element of a quaternion - // - inline float getX( ) const; - - // Get the y element of a quaternion - // - inline float getY( ) const; - - // Get the z element of a quaternion - // - inline float getZ( ) const; - - // Get the w element of a quaternion - // - inline float getW( ) const; - - // Set an x, y, z, or w element of a quaternion by index - // - inline Quat & setElem( int idx, float value ); - - // Get an x, y, z, or w element of a quaternion by index - // - inline float getElem( int idx ) const; - - // Subscripting operator to set or get an element - // - inline VecIdx operator []( int idx ); - - // Subscripting operator to get an element - // - inline float operator []( int idx ) const; - - // Add two quaternions - // - inline const Quat operator +( Quat quat ) const; - - // Subtract a quaternion from another quaternion - // - inline const Quat operator -( Quat quat ) const; - - // Multiply two quaternions - // - inline const Quat operator *( Quat quat ) const; - - // Multiply a quaternion by a scalar - // - inline const Quat operator *( float scalar ) const; - - // Divide a quaternion by a scalar - // - inline const Quat operator /( float scalar ) const; - - // Perform compound assignment and addition with a quaternion - // - inline Quat & operator +=( Quat quat ); - - // Perform compound assignment and subtraction by a quaternion - // - inline Quat & operator -=( Quat quat ); - - // Perform compound assignment and multiplication by a quaternion - // - inline Quat & operator *=( Quat quat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Quat & operator *=( float scalar ); - - // Perform compound assignment and division by a scalar - // - inline Quat & operator /=( float scalar ); - - // Negate all elements of a quaternion - // - inline const Quat operator -( ) const; - - // Construct an identity quaternion - // - static inline const Quat identity( ); - - // Construct a quaternion to rotate between two unit-length 3-D vectors - // NOTE: - // The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. - // - static inline const Quat rotation( Vector3 unitVec0, Vector3 unitVec1 ); - - // Construct a quaternion to rotate around a unit-length 3-D vector - // - static inline const Quat rotation( float radians, Vector3 unitVec ); - - // Construct a quaternion to rotate around the x axis - // - static inline const Quat rotationX( float radians ); - - // Construct a quaternion to rotate around the y axis - // - static inline const Quat rotationY( float radians ); - - // Construct a quaternion to rotate around the z axis - // - static inline const Quat rotationZ( float radians ); - -}; - -// Multiply a quaternion by a scalar -// -inline const Quat operator *( float scalar, Quat quat ); - -// Compute the conjugate of a quaternion -// -inline const Quat conj( Quat quat ); - -// Use a unit-length quaternion to rotate a 3-D vector -// -inline const Vector3 rotate( Quat unitQuat, Vector3 vec ); - -// Compute the dot product of two quaternions -// -inline float dot( Quat quat0, Quat quat1 ); - -// Compute the norm of a quaternion -// -inline float norm( Quat quat ); - -// Compute the length of a quaternion -// -inline float length( Quat quat ); - -// Normalize a quaternion -// NOTE: -// The result is unpredictable when all elements of quat are at or near zero. -// -inline const Quat normalize( Quat quat ); - -// Linear interpolation between two quaternions -// NOTE: -// Does not clamp t between 0 and 1. -// -inline const Quat lerp( float t, Quat quat0, Quat quat1 ); - -// Spherical linear interpolation between two quaternions -// NOTE: -// Interpolates along the shortest path between orientations. -// Does not clamp t between 0 and 1. -// -inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ); - -// Spherical quadrangle interpolation -// -inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); - -// Conditionally select between two quaternions -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Quat select( Quat quat0, Quat quat1, bool select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a quaternion -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Quat quat ); - -// Print a quaternion and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( Quat quat, const char * name ); - -#endif - -// A 3x3 matrix in array-of-structures format -// -class Matrix3 -{ - Vector3 mCol0; - Vector3 mCol1; - Vector3 mCol2; - -public: - // Default constructor; does no initialization - // - inline Matrix3( ) { }; - - // Copy a 3x3 matrix - // - inline Matrix3( const Matrix3 & mat ); - - // Construct a 3x3 matrix containing the specified columns - // - inline Matrix3( Vector3 col0, Vector3 col1, Vector3 col2 ); - - // Construct a 3x3 rotation matrix from a unit-length quaternion - // - explicit inline Matrix3( Quat unitQuat ); - - // Set all elements of a 3x3 matrix to the same scalar value - // - explicit inline Matrix3( float scalar ); - - // Assign one 3x3 matrix to another - // - inline Matrix3 & operator =( const Matrix3 & mat ); - - // Set column 0 of a 3x3 matrix - // - inline Matrix3 & setCol0( Vector3 col0 ); - - // Set column 1 of a 3x3 matrix - // - inline Matrix3 & setCol1( Vector3 col1 ); - - // Set column 2 of a 3x3 matrix - // - inline Matrix3 & setCol2( Vector3 col2 ); - - // Get column 0 of a 3x3 matrix - // - inline const Vector3 getCol0( ) const; - - // Get column 1 of a 3x3 matrix - // - inline const Vector3 getCol1( ) const; - - // Get column 2 of a 3x3 matrix - // - inline const Vector3 getCol2( ) const; - - // Set the column of a 3x3 matrix referred to by the specified index - // - inline Matrix3 & setCol( int col, Vector3 vec ); - - // Set the row of a 3x3 matrix referred to by the specified index - // - inline Matrix3 & setRow( int row, Vector3 vec ); - - // Get the column of a 3x3 matrix referred to by the specified index - // - inline const Vector3 getCol( int col ) const; - - // Get the row of a 3x3 matrix referred to by the specified index - // - inline const Vector3 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector3 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector3 operator []( int col ) const; - - // Set the element of a 3x3 matrix referred to by column and row indices - // - inline Matrix3 & setElem( int col, int row, float val ); - - // Get the element of a 3x3 matrix referred to by column and row indices - // - inline float getElem( int col, int row ) const; - - // Add two 3x3 matrices - // - inline const Matrix3 operator +( const Matrix3 & mat ) const; - - // Subtract a 3x3 matrix from another 3x3 matrix - // - inline const Matrix3 operator -( const Matrix3 & mat ) const; - - // Negate all elements of a 3x3 matrix - // - inline const Matrix3 operator -( ) const; - - // Multiply a 3x3 matrix by a scalar - // - inline const Matrix3 operator *( float scalar ) const; - - // Multiply a 3x3 matrix by a 3-D vector - // - inline const Vector3 operator *( Vector3 vec ) const; - - // Multiply two 3x3 matrices - // - inline const Matrix3 operator *( const Matrix3 & mat ) const; - - // Perform compound assignment and addition with a 3x3 matrix - // - inline Matrix3 & operator +=( const Matrix3 & mat ); - - // Perform compound assignment and subtraction by a 3x3 matrix - // - inline Matrix3 & operator -=( const Matrix3 & mat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Matrix3 & operator *=( float scalar ); - - // Perform compound assignment and multiplication by a 3x3 matrix - // - inline Matrix3 & operator *=( const Matrix3 & mat ); - - // Construct an identity 3x3 matrix - // - static inline const Matrix3 identity( ); - - // Construct a 3x3 matrix to rotate around the x axis - // - static inline const Matrix3 rotationX( float radians ); - - // Construct a 3x3 matrix to rotate around the y axis - // - static inline const Matrix3 rotationY( float radians ); - - // Construct a 3x3 matrix to rotate around the z axis - // - static inline const Matrix3 rotationZ( float radians ); - - // Construct a 3x3 matrix to rotate around the x, y, and z axes - // - static inline const Matrix3 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 3x3 matrix to rotate around a unit-length 3-D vector - // - static inline const Matrix3 rotation( float radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Matrix3 rotation( Quat unitQuat ); - - // Construct a 3x3 matrix to perform scaling - // - static inline const Matrix3 scale( Vector3 scaleVec ); - -}; -// Multiply a 3x3 matrix by a scalar -// -inline const Matrix3 operator *( float scalar, const Matrix3 & mat ); - -// Append (post-multiply) a scale transformation to a 3x3 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 3x3 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ); - -// Multiply two 3x3 matrices per element -// -inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ); - -// Compute the absolute value of a 3x3 matrix per element -// -inline const Matrix3 absPerElem( const Matrix3 & mat ); - -// Transpose of a 3x3 matrix -// -inline const Matrix3 transpose( const Matrix3 & mat ); - -// Compute the inverse of a 3x3 matrix -// NOTE: -// Result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix3 inverse( const Matrix3 & mat ); - -// Determinant of a 3x3 matrix -// -inline float determinant( const Matrix3 & mat ); - -// Conditionally select between two 3x3 matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3x3 matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix3 & mat ); - -// Print a 3x3 matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix3 & mat, const char * name ); - -#endif - -// A 4x4 matrix in array-of-structures format -// -class Matrix4 -{ - Vector4 mCol0; - Vector4 mCol1; - Vector4 mCol2; - Vector4 mCol3; - -public: - // Default constructor; does no initialization - // - inline Matrix4( ) { }; - - // Copy a 4x4 matrix - // - inline Matrix4( const Matrix4 & mat ); - - // Construct a 4x4 matrix containing the specified columns - // - inline Matrix4( Vector4 col0, Vector4 col1, Vector4 col2, Vector4 col3 ); - - // Construct a 4x4 matrix from a 3x4 transformation matrix - // - explicit inline Matrix4( const Transform3 & mat ); - - // Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector - // - inline Matrix4( const Matrix3 & mat, Vector3 translateVec ); - - // Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector - // - inline Matrix4( Quat unitQuat, Vector3 translateVec ); - - // Set all elements of a 4x4 matrix to the same scalar value - // - explicit inline Matrix4( float scalar ); - - // Assign one 4x4 matrix to another - // - inline Matrix4 & operator =( const Matrix4 & mat ); - - // Set the upper-left 3x3 submatrix - // NOTE: - // This function does not change the bottom row elements. - // - inline Matrix4 & setUpper3x3( const Matrix3 & mat3 ); - - // Get the upper-left 3x3 submatrix of a 4x4 matrix - // - inline const Matrix3 getUpper3x3( ) const; - - // Set translation component - // NOTE: - // This function does not change the bottom row elements. - // - inline Matrix4 & setTranslation( Vector3 translateVec ); - - // Get the translation component of a 4x4 matrix - // - inline const Vector3 getTranslation( ) const; - - // Set column 0 of a 4x4 matrix - // - inline Matrix4 & setCol0( Vector4 col0 ); - - // Set column 1 of a 4x4 matrix - // - inline Matrix4 & setCol1( Vector4 col1 ); - - // Set column 2 of a 4x4 matrix - // - inline Matrix4 & setCol2( Vector4 col2 ); - - // Set column 3 of a 4x4 matrix - // - inline Matrix4 & setCol3( Vector4 col3 ); - - // Get column 0 of a 4x4 matrix - // - inline const Vector4 getCol0( ) const; - - // Get column 1 of a 4x4 matrix - // - inline const Vector4 getCol1( ) const; - - // Get column 2 of a 4x4 matrix - // - inline const Vector4 getCol2( ) const; - - // Get column 3 of a 4x4 matrix - // - inline const Vector4 getCol3( ) const; - - // Set the column of a 4x4 matrix referred to by the specified index - // - inline Matrix4 & setCol( int col, Vector4 vec ); - - // Set the row of a 4x4 matrix referred to by the specified index - // - inline Matrix4 & setRow( int row, Vector4 vec ); - - // Get the column of a 4x4 matrix referred to by the specified index - // - inline const Vector4 getCol( int col ) const; - - // Get the row of a 4x4 matrix referred to by the specified index - // - inline const Vector4 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector4 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector4 operator []( int col ) const; - - // Set the element of a 4x4 matrix referred to by column and row indices - // - inline Matrix4 & setElem( int col, int row, float val ); - - // Get the element of a 4x4 matrix referred to by column and row indices - // - inline float getElem( int col, int row ) const; - - // Add two 4x4 matrices - // - inline const Matrix4 operator +( const Matrix4 & mat ) const; - - // Subtract a 4x4 matrix from another 4x4 matrix - // - inline const Matrix4 operator -( const Matrix4 & mat ) const; - - // Negate all elements of a 4x4 matrix - // - inline const Matrix4 operator -( ) const; - - // Multiply a 4x4 matrix by a scalar - // - inline const Matrix4 operator *( float scalar ) const; - - // Multiply a 4x4 matrix by a 4-D vector - // - inline const Vector4 operator *( Vector4 vec ) const; - - // Multiply a 4x4 matrix by a 3-D vector - // - inline const Vector4 operator *( Vector3 vec ) const; - - // Multiply a 4x4 matrix by a 3-D point - // - inline const Vector4 operator *( Point3 pnt ) const; - - // Multiply two 4x4 matrices - // - inline const Matrix4 operator *( const Matrix4 & mat ) const; - - // Multiply a 4x4 matrix by a 3x4 transformation matrix - // - inline const Matrix4 operator *( const Transform3 & tfrm ) const; - - // Perform compound assignment and addition with a 4x4 matrix - // - inline Matrix4 & operator +=( const Matrix4 & mat ); - - // Perform compound assignment and subtraction by a 4x4 matrix - // - inline Matrix4 & operator -=( const Matrix4 & mat ); - - // Perform compound assignment and multiplication by a scalar - // - inline Matrix4 & operator *=( float scalar ); - - // Perform compound assignment and multiplication by a 4x4 matrix - // - inline Matrix4 & operator *=( const Matrix4 & mat ); - - // Perform compound assignment and multiplication by a 3x4 transformation matrix - // - inline Matrix4 & operator *=( const Transform3 & tfrm ); - - // Construct an identity 4x4 matrix - // - static inline const Matrix4 identity( ); - - // Construct a 4x4 matrix to rotate around the x axis - // - static inline const Matrix4 rotationX( float radians ); - - // Construct a 4x4 matrix to rotate around the y axis - // - static inline const Matrix4 rotationY( float radians ); - - // Construct a 4x4 matrix to rotate around the z axis - // - static inline const Matrix4 rotationZ( float radians ); - - // Construct a 4x4 matrix to rotate around the x, y, and z axes - // - static inline const Matrix4 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 4x4 matrix to rotate around a unit-length 3-D vector - // - static inline const Matrix4 rotation( float radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Matrix4 rotation( Quat unitQuat ); - - // Construct a 4x4 matrix to perform scaling - // - static inline const Matrix4 scale( Vector3 scaleVec ); - - // Construct a 4x4 matrix to perform translation - // - static inline const Matrix4 translation( Vector3 translateVec ); - - // Construct viewing matrix based on eye position, position looked at, and up direction - // - static inline const Matrix4 lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ); - - // Construct a perspective projection matrix - // - static inline const Matrix4 perspective( float fovyRadians, float aspect, float zNear, float zFar ); - - // Construct a perspective projection matrix based on frustum - // - static inline const Matrix4 frustum( float left, float right, float bottom, float top, float zNear, float zFar ); - - // Construct an orthographic projection matrix - // - static inline const Matrix4 orthographic( float left, float right, float bottom, float top, float zNear, float zFar ); - -}; -// Multiply a 4x4 matrix by a scalar -// -inline const Matrix4 operator *( float scalar, const Matrix4 & mat ); - -// Append (post-multiply) a scale transformation to a 4x4 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 4x4 matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ); - -// Multiply two 4x4 matrices per element -// -inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ); - -// Compute the absolute value of a 4x4 matrix per element -// -inline const Matrix4 absPerElem( const Matrix4 & mat ); - -// Transpose of a 4x4 matrix -// -inline const Matrix4 transpose( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix -// NOTE: -// Result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix4 inverse( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. -// -inline const Matrix4 affineInverse( const Matrix4 & mat ); - -// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. -// -inline const Matrix4 orthoInverse( const Matrix4 & mat ); - -// Determinant of a 4x4 matrix -// -inline float determinant( const Matrix4 & mat ); - -// Conditionally select between two 4x4 matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 4x4 matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix4 & mat ); - -// Print a 4x4 matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Matrix4 & mat, const char * name ); - -#endif - -// A 3x4 transformation matrix in array-of-structures format -// -class Transform3 -{ - Vector3 mCol0; - Vector3 mCol1; - Vector3 mCol2; - Vector3 mCol3; - -public: - // Default constructor; does no initialization - // - inline Transform3( ) { }; - - // Copy a 3x4 transformation matrix - // - inline Transform3( const Transform3 & tfrm ); - - // Construct a 3x4 transformation matrix containing the specified columns - // - inline Transform3( Vector3 col0, Vector3 col1, Vector3 col2, Vector3 col3 ); - - // Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector - // - inline Transform3( const Matrix3 & tfrm, Vector3 translateVec ); - - // Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector - // - inline Transform3( Quat unitQuat, Vector3 translateVec ); - - // Set all elements of a 3x4 transformation matrix to the same scalar value - // - explicit inline Transform3( float scalar ); - - // Assign one 3x4 transformation matrix to another - // - inline Transform3 & operator =( const Transform3 & tfrm ); - - // Set the upper-left 3x3 submatrix - // - inline Transform3 & setUpper3x3( const Matrix3 & mat3 ); - - // Get the upper-left 3x3 submatrix of a 3x4 transformation matrix - // - inline const Matrix3 getUpper3x3( ) const; - - // Set translation component - // - inline Transform3 & setTranslation( Vector3 translateVec ); - - // Get the translation component of a 3x4 transformation matrix - // - inline const Vector3 getTranslation( ) const; - - // Set column 0 of a 3x4 transformation matrix - // - inline Transform3 & setCol0( Vector3 col0 ); - - // Set column 1 of a 3x4 transformation matrix - // - inline Transform3 & setCol1( Vector3 col1 ); - - // Set column 2 of a 3x4 transformation matrix - // - inline Transform3 & setCol2( Vector3 col2 ); - - // Set column 3 of a 3x4 transformation matrix - // - inline Transform3 & setCol3( Vector3 col3 ); - - // Get column 0 of a 3x4 transformation matrix - // - inline const Vector3 getCol0( ) const; - - // Get column 1 of a 3x4 transformation matrix - // - inline const Vector3 getCol1( ) const; - - // Get column 2 of a 3x4 transformation matrix - // - inline const Vector3 getCol2( ) const; - - // Get column 3 of a 3x4 transformation matrix - // - inline const Vector3 getCol3( ) const; - - // Set the column of a 3x4 transformation matrix referred to by the specified index - // - inline Transform3 & setCol( int col, Vector3 vec ); - - // Set the row of a 3x4 transformation matrix referred to by the specified index - // - inline Transform3 & setRow( int row, Vector4 vec ); - - // Get the column of a 3x4 transformation matrix referred to by the specified index - // - inline const Vector3 getCol( int col ) const; - - // Get the row of a 3x4 transformation matrix referred to by the specified index - // - inline const Vector4 getRow( int row ) const; - - // Subscripting operator to set or get a column - // - inline Vector3 & operator []( int col ); - - // Subscripting operator to get a column - // - inline const Vector3 operator []( int col ) const; - - // Set the element of a 3x4 transformation matrix referred to by column and row indices - // - inline Transform3 & setElem( int col, int row, float val ); - - // Get the element of a 3x4 transformation matrix referred to by column and row indices - // - inline float getElem( int col, int row ) const; - - // Multiply a 3x4 transformation matrix by a 3-D vector - // - inline const Vector3 operator *( Vector3 vec ) const; - - // Multiply a 3x4 transformation matrix by a 3-D point - // - inline const Point3 operator *( Point3 pnt ) const; - - // Multiply two 3x4 transformation matrices - // - inline const Transform3 operator *( const Transform3 & tfrm ) const; - - // Perform compound assignment and multiplication by a 3x4 transformation matrix - // - inline Transform3 & operator *=( const Transform3 & tfrm ); - - // Construct an identity 3x4 transformation matrix - // - static inline const Transform3 identity( ); - - // Construct a 3x4 transformation matrix to rotate around the x axis - // - static inline const Transform3 rotationX( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the y axis - // - static inline const Transform3 rotationY( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the z axis - // - static inline const Transform3 rotationZ( float radians ); - - // Construct a 3x4 transformation matrix to rotate around the x, y, and z axes - // - static inline const Transform3 rotationZYX( Vector3 radiansXYZ ); - - // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector - // - static inline const Transform3 rotation( float radians, Vector3 unitVec ); - - // Construct a rotation matrix from a unit-length quaternion - // - static inline const Transform3 rotation( Quat unitQuat ); - - // Construct a 3x4 transformation matrix to perform scaling - // - static inline const Transform3 scale( Vector3 scaleVec ); - - // Construct a 3x4 transformation matrix to perform translation - // - static inline const Transform3 translation( Vector3 translateVec ); - -}; -// Append (post-multiply) a scale transformation to a 3x4 transformation matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ); - -// Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix -// NOTE: -// Faster than creating and multiplying a scale transformation matrix. -// -inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ); - -// Multiply two 3x4 transformation matrices per element -// -inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ); - -// Compute the absolute value of a 3x4 transformation matrix per element -// -inline const Transform3 absPerElem( const Transform3 & tfrm ); - -// Inverse of a 3x4 transformation matrix -// NOTE: -// Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. -// -inline const Transform3 inverse( const Transform3 & tfrm ); - -// Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix -// NOTE: -// This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. -// -inline const Transform3 orthoInverse( const Transform3 & tfrm ); - -// Conditionally select between two 3x4 transformation matrices -// NOTE: -// This function uses a conditional select instruction to avoid a branch. -// -inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ); - -#ifdef _VECTORMATH_DEBUG - -// Print a 3x4 transformation matrix -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Transform3 & tfrm ); - -// Print a 3x4 transformation matrix and an associated string identifier -// NOTE: -// Function is only defined when _VECTORMATH_DEBUG is defined. -// -inline void print( const Transform3 & tfrm, const char * name ); - -#endif - -} // namespace Aos -} // namespace Vectormath - -#include "vec_aos.h" -#include "quat_aos.h" -#include "mat_aos.h" - -#endif +/* + Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. + All rights reserved. + + Redistribution and use in source and binary forms, + with or without modification, are permitted provided that the + following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Sony Computer Entertainment Inc nor the names + of its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _VECTORMATH_AOS_CPP_SPU_H +#define _VECTORMATH_AOS_CPP_SPU_H + +#include +#include +#include "floatInVec.h" +#include "boolInVec.h" +#include "vecidx_aos.h" +#include + +#ifdef _VECTORMATH_DEBUG +#endif + +namespace Vectormath { + +namespace Aos { + +//----------------------------------------------------------------------------- +// Forward Declarations +// + +class Vector3; +class Vector4; +class Point3; +class Quat; +class Matrix3; +class Matrix4; +class Transform3; + +// A 3-D vector in array-of-structures format +// +class Vector3 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Vector3( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 3-D vector from x, y, and z elements + // + inline Vector3( float x, float y, float z ); + + // Copy elements from a 3-D point into a 3-D vector + // + explicit inline Vector3( Point3 pnt ); + + // Set all elements of a 3-D vector to the same scalar value + // + explicit inline Vector3( float scalar ); + + // Set vector float data in a 3-D vector + // + explicit inline Vector3( vec_float4 vf4 ); + + // Get vector float data from a 3-D vector + // + inline vec_float4 get128( ) const; + + // Assign one 3-D vector to another + // + inline Vector3 & operator =( Vector3 vec ); + + // Set the x element of a 3-D vector + // + inline Vector3 & setX( float x ); + + // Set the y element of a 3-D vector + // + inline Vector3 & setY( float y ); + + // Set the z element of a 3-D vector + // + inline Vector3 & setZ( float z ); + + // Get the x element of a 3-D vector + // + inline float getX( ) const; + + // Get the y element of a 3-D vector + // + inline float getY( ) const; + + // Get the z element of a 3-D vector + // + inline float getZ( ) const; + + // Set an x, y, or z element of a 3-D vector by index + // + inline Vector3 & setElem( int idx, float value ); + + // Get an x, y, or z element of a 3-D vector by index + // + inline float getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline float operator []( int idx ) const; + + // Add two 3-D vectors + // + inline const Vector3 operator +( Vector3 vec ) const; + + // Subtract a 3-D vector from another 3-D vector + // + inline const Vector3 operator -( Vector3 vec ) const; + + // Add a 3-D vector to a 3-D point + // + inline const Point3 operator +( Point3 pnt ) const; + + // Multiply a 3-D vector by a scalar + // + inline const Vector3 operator *( float scalar ) const; + + // Divide a 3-D vector by a scalar + // + inline const Vector3 operator /( float scalar ) const; + + // Perform compound assignment and addition with a 3-D vector + // + inline Vector3 & operator +=( Vector3 vec ); + + // Perform compound assignment and subtraction by a 3-D vector + // + inline Vector3 & operator -=( Vector3 vec ); + + // Perform compound assignment and multiplication by a scalar + // + inline Vector3 & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Vector3 & operator /=( float scalar ); + + // Negate all elements of a 3-D vector + // + inline const Vector3 operator -( ) const; + + // Construct x axis + // + static inline const Vector3 xAxis( ); + + // Construct y axis + // + static inline const Vector3 yAxis( ); + + // Construct z axis + // + static inline const Vector3 zAxis( ); + +}; + +// Multiply a 3-D vector by a scalar +// +inline const Vector3 operator *( float scalar, Vector3 vec ); + +// Multiply two 3-D vectors per element +// +inline const Vector3 mulPerElem( Vector3 vec0, Vector3 vec1 ); + +// Divide two 3-D vectors per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Vector3 divPerElem( Vector3 vec0, Vector3 vec1 ); + +// Compute the reciprocal of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Vector3 recipPerElem( Vector3 vec ); + +// Compute the square root of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Vector3 sqrtPerElem( Vector3 vec ); + +// Compute the reciprocal square root of a 3-D vector per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Vector3 rsqrtPerElem( Vector3 vec ); + +// Compute the absolute value of a 3-D vector per element +// +inline const Vector3 absPerElem( Vector3 vec ); + +// Copy sign from one 3-D vector to another, per element +// +inline const Vector3 copySignPerElem( Vector3 vec0, Vector3 vec1 ); + +// Maximum of two 3-D vectors per element +// +inline const Vector3 maxPerElem( Vector3 vec0, Vector3 vec1 ); + +// Minimum of two 3-D vectors per element +// +inline const Vector3 minPerElem( Vector3 vec0, Vector3 vec1 ); + +// Maximum element of a 3-D vector +// +inline float maxElem( Vector3 vec ); + +// Minimum element of a 3-D vector +// +inline float minElem( Vector3 vec ); + +// Compute the sum of all elements of a 3-D vector +// +inline float sum( Vector3 vec ); + +// Compute the dot product of two 3-D vectors +// +inline float dot( Vector3 vec0, Vector3 vec1 ); + +// Compute the square of the length of a 3-D vector +// +inline float lengthSqr( Vector3 vec ); + +// Compute the length of a 3-D vector +// +inline float length( Vector3 vec ); + +// Normalize a 3-D vector +// NOTE: +// The result is unpredictable when all elements of vec are at or near zero. +// +inline const Vector3 normalize( Vector3 vec ); + +// Compute cross product of two 3-D vectors +// +inline const Vector3 cross( Vector3 vec0, Vector3 vec1 ); + +// Outer product of two 3-D vectors +// +inline const Matrix3 outer( Vector3 vec0, Vector3 vec1 ); + +// Pre-multiply a row vector by a 3x3 matrix +// NOTE: +// Slower than column post-multiply. +// +inline const Vector3 rowMul( Vector3 vec, const Matrix3 & mat ); + +// Cross-product matrix of a 3-D vector +// +inline const Matrix3 crossMatrix( Vector3 vec ); + +// Create cross-product matrix and multiply +// NOTE: +// Faster than separately creating a cross-product matrix and multiplying. +// +inline const Matrix3 crossMatrixMul( Vector3 vec, const Matrix3 & mat ); + +// Linear interpolation between two 3-D vectors +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector3 lerp( float t, Vector3 vec0, Vector3 vec1 ); + +// Spherical linear interpolation between two 3-D vectors +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector3 slerp( float t, Vector3 unitVec0, Vector3 unitVec1 ); + +// Conditionally select between two 3-D vectors +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Vector3 select( Vector3 vec0, Vector3 vec1, bool select1 ); + +// Load x, y, and z elements from the first three words of a quadword. +// +// +inline void loadXYZ( Vector3 & vec, const vec_float4 * quad ); + +// Load x, y, and z elements from the first three words of a float array. +// +// +inline void loadXYZ( Vector3 & vec, const float * fptr ); + +// Store x, y, and z elements of a 3-D vector in the first three words of a quadword. +// The value of the fourth word (the word with the highest address) remains unchanged +// +inline void storeXYZ( Vector3 vec, vec_float4 * quad ); + +// Store x, y, and z elements of a 3-D vector in the first three words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZ( Vector3 vec, float * fptr ); + +// Load four three-float 3-D vectors, stored in three quadwords +// +inline void loadXYZArray( Vector3 & vec0, Vector3 & vec1, Vector3 & vec2, Vector3 & vec3, const vec_float4 * threeQuads ); + +// Store four 3-D vectors in three quadwords +// +inline void storeXYZArray( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, vec_float4 * threeQuads ); + +// Store eight 3-D vectors as half-floats +// +inline void storeHalfFloats( Vector3 vec0, Vector3 vec1, Vector3 vec2, Vector3 vec3, Vector3 vec4, Vector3 vec5, Vector3 vec6, Vector3 vec7, vec_ushort8 * threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3-D vector +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector3 vec ); + +// Print a 3-D vector and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector3 vec, const char * name ); + +#endif + +// A 4-D vector in array-of-structures format +// +class Vector4 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Vector4( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 4-D vector from x, y, z, and w elements + // + inline Vector4( float x, float y, float z, float w ); + + // Construct a 4-D vector from a 3-D vector and a scalar + // + inline Vector4( Vector3 xyz, float w ); + + // Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 + // + explicit inline Vector4( Vector3 vec ); + + // Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 + // + explicit inline Vector4( Point3 pnt ); + + // Copy elements from a quaternion into a 4-D vector + // + explicit inline Vector4( Quat quat ); + + // Set all elements of a 4-D vector to the same scalar value + // + explicit inline Vector4( float scalar ); + + // Set vector float data in a 4-D vector + // + explicit inline Vector4( vec_float4 vf4 ); + + // Get vector float data from a 4-D vector + // + inline vec_float4 get128( ) const; + + // Assign one 4-D vector to another + // + inline Vector4 & operator =( Vector4 vec ); + + // Set the x, y, and z elements of a 4-D vector + // NOTE: + // This function does not change the w element. + // + inline Vector4 & setXYZ( Vector3 vec ); + + // Get the x, y, and z elements of a 4-D vector + // + inline const Vector3 getXYZ( ) const; + + // Set the x element of a 4-D vector + // + inline Vector4 & setX( float x ); + + // Set the y element of a 4-D vector + // + inline Vector4 & setY( float y ); + + // Set the z element of a 4-D vector + // + inline Vector4 & setZ( float z ); + + // Set the w element of a 4-D vector + // + inline Vector4 & setW( float w ); + + // Get the x element of a 4-D vector + // + inline float getX( ) const; + + // Get the y element of a 4-D vector + // + inline float getY( ) const; + + // Get the z element of a 4-D vector + // + inline float getZ( ) const; + + // Get the w element of a 4-D vector + // + inline float getW( ) const; + + // Set an x, y, z, or w element of a 4-D vector by index + // + inline Vector4 & setElem( int idx, float value ); + + // Get an x, y, z, or w element of a 4-D vector by index + // + inline float getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline float operator []( int idx ) const; + + // Add two 4-D vectors + // + inline const Vector4 operator +( Vector4 vec ) const; + + // Subtract a 4-D vector from another 4-D vector + // + inline const Vector4 operator -( Vector4 vec ) const; + + // Multiply a 4-D vector by a scalar + // + inline const Vector4 operator *( float scalar ) const; + + // Divide a 4-D vector by a scalar + // + inline const Vector4 operator /( float scalar ) const; + + // Perform compound assignment and addition with a 4-D vector + // + inline Vector4 & operator +=( Vector4 vec ); + + // Perform compound assignment and subtraction by a 4-D vector + // + inline Vector4 & operator -=( Vector4 vec ); + + // Perform compound assignment and multiplication by a scalar + // + inline Vector4 & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Vector4 & operator /=( float scalar ); + + // Negate all elements of a 4-D vector + // + inline const Vector4 operator -( ) const; + + // Construct x axis + // + static inline const Vector4 xAxis( ); + + // Construct y axis + // + static inline const Vector4 yAxis( ); + + // Construct z axis + // + static inline const Vector4 zAxis( ); + + // Construct w axis + // + static inline const Vector4 wAxis( ); + +}; + +// Multiply a 4-D vector by a scalar +// +inline const Vector4 operator *( float scalar, Vector4 vec ); + +// Multiply two 4-D vectors per element +// +inline const Vector4 mulPerElem( Vector4 vec0, Vector4 vec1 ); + +// Divide two 4-D vectors per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Vector4 divPerElem( Vector4 vec0, Vector4 vec1 ); + +// Compute the reciprocal of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Vector4 recipPerElem( Vector4 vec ); + +// Compute the square root of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Vector4 sqrtPerElem( Vector4 vec ); + +// Compute the reciprocal square root of a 4-D vector per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Vector4 rsqrtPerElem( Vector4 vec ); + +// Compute the absolute value of a 4-D vector per element +// +inline const Vector4 absPerElem( Vector4 vec ); + +// Copy sign from one 4-D vector to another, per element +// +inline const Vector4 copySignPerElem( Vector4 vec0, Vector4 vec1 ); + +// Maximum of two 4-D vectors per element +// +inline const Vector4 maxPerElem( Vector4 vec0, Vector4 vec1 ); + +// Minimum of two 4-D vectors per element +// +inline const Vector4 minPerElem( Vector4 vec0, Vector4 vec1 ); + +// Maximum element of a 4-D vector +// +inline float maxElem( Vector4 vec ); + +// Minimum element of a 4-D vector +// +inline float minElem( Vector4 vec ); + +// Compute the sum of all elements of a 4-D vector +// +inline float sum( Vector4 vec ); + +// Compute the dot product of two 4-D vectors +// +inline float dot( Vector4 vec0, Vector4 vec1 ); + +// Compute the square of the length of a 4-D vector +// +inline float lengthSqr( Vector4 vec ); + +// Compute the length of a 4-D vector +// +inline float length( Vector4 vec ); + +// Normalize a 4-D vector +// NOTE: +// The result is unpredictable when all elements of vec are at or near zero. +// +inline const Vector4 normalize( Vector4 vec ); + +// Outer product of two 4-D vectors +// +inline const Matrix4 outer( Vector4 vec0, Vector4 vec1 ); + +// Linear interpolation between two 4-D vectors +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Vector4 lerp( float t, Vector4 vec0, Vector4 vec1 ); + +// Spherical linear interpolation between two 4-D vectors +// NOTE: +// The result is unpredictable if the vectors point in opposite directions. +// Does not clamp t between 0 and 1. +// +inline const Vector4 slerp( float t, Vector4 unitVec0, Vector4 unitVec1 ); + +// Conditionally select between two 4-D vectors +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Vector4 select( Vector4 vec0, Vector4 vec1, bool select1 ); + +// Load x, y, z, and w elements from the first four words of a float array. +// +// +inline void loadXYZW( Vector4 & vec, const float * fptr ); + +// Store x, y, z, and w elements of a 4-D vector in the first four words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZW( Vector4 vec, float * fptr ); + +// Store four 4-D vectors as half-floats +// +inline void storeHalfFloats( Vector4 vec0, Vector4 vec1, Vector4 vec2, Vector4 vec3, vec_ushort8 * twoQuads ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 4-D vector +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector4 vec ); + +// Print a 4-D vector and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Vector4 vec, const char * name ); + +#endif + +// A 3-D point in array-of-structures format +// +class Point3 +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Point3( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a 3-D point from x, y, and z elements + // + inline Point3( float x, float y, float z ); + + // Copy elements from a 3-D vector into a 3-D point + // + explicit inline Point3( Vector3 vec ); + + // Set all elements of a 3-D point to the same scalar value + // + explicit inline Point3( float scalar ); + + // Set vector float data in a 3-D point + // + explicit inline Point3( vec_float4 vf4 ); + + // Get vector float data from a 3-D point + // + inline vec_float4 get128( ) const; + + // Assign one 3-D point to another + // + inline Point3 & operator =( Point3 pnt ); + + // Set the x element of a 3-D point + // + inline Point3 & setX( float x ); + + // Set the y element of a 3-D point + // + inline Point3 & setY( float y ); + + // Set the z element of a 3-D point + // + inline Point3 & setZ( float z ); + + // Get the x element of a 3-D point + // + inline float getX( ) const; + + // Get the y element of a 3-D point + // + inline float getY( ) const; + + // Get the z element of a 3-D point + // + inline float getZ( ) const; + + // Set an x, y, or z element of a 3-D point by index + // + inline Point3 & setElem( int idx, float value ); + + // Get an x, y, or z element of a 3-D point by index + // + inline float getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline float operator []( int idx ) const; + + // Subtract a 3-D point from another 3-D point + // + inline const Vector3 operator -( Point3 pnt ) const; + + // Add a 3-D point to a 3-D vector + // + inline const Point3 operator +( Vector3 vec ) const; + + // Subtract a 3-D vector from a 3-D point + // + inline const Point3 operator -( Vector3 vec ) const; + + // Perform compound assignment and addition with a 3-D vector + // + inline Point3 & operator +=( Vector3 vec ); + + // Perform compound assignment and subtraction by a 3-D vector + // + inline Point3 & operator -=( Vector3 vec ); + +}; + +// Multiply two 3-D points per element +// +inline const Point3 mulPerElem( Point3 pnt0, Point3 pnt1 ); + +// Divide two 3-D points per element +// NOTE: +// Floating-point behavior matches standard library function divf4. +// +inline const Point3 divPerElem( Point3 pnt0, Point3 pnt1 ); + +// Compute the reciprocal of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function recipf4. +// +inline const Point3 recipPerElem( Point3 pnt ); + +// Compute the square root of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function sqrtf4. +// +inline const Point3 sqrtPerElem( Point3 pnt ); + +// Compute the reciprocal square root of a 3-D point per element +// NOTE: +// Floating-point behavior matches standard library function rsqrtf4. +// +inline const Point3 rsqrtPerElem( Point3 pnt ); + +// Compute the absolute value of a 3-D point per element +// +inline const Point3 absPerElem( Point3 pnt ); + +// Copy sign from one 3-D point to another, per element +// +inline const Point3 copySignPerElem( Point3 pnt0, Point3 pnt1 ); + +// Maximum of two 3-D points per element +// +inline const Point3 maxPerElem( Point3 pnt0, Point3 pnt1 ); + +// Minimum of two 3-D points per element +// +inline const Point3 minPerElem( Point3 pnt0, Point3 pnt1 ); + +// Maximum element of a 3-D point +// +inline float maxElem( Point3 pnt ); + +// Minimum element of a 3-D point +// +inline float minElem( Point3 pnt ); + +// Compute the sum of all elements of a 3-D point +// +inline float sum( Point3 pnt ); + +// Apply uniform scale to a 3-D point +// +inline const Point3 scale( Point3 pnt, float scaleVal ); + +// Apply non-uniform scale to a 3-D point +// +inline const Point3 scale( Point3 pnt, Vector3 scaleVec ); + +// Scalar projection of a 3-D point on a unit-length 3-D vector +// +inline float projection( Point3 pnt, Vector3 unitVec ); + +// Compute the square of the distance of a 3-D point from the coordinate-system origin +// +inline float distSqrFromOrigin( Point3 pnt ); + +// Compute the distance of a 3-D point from the coordinate-system origin +// +inline float distFromOrigin( Point3 pnt ); + +// Compute the square of the distance between two 3-D points +// +inline float distSqr( Point3 pnt0, Point3 pnt1 ); + +// Compute the distance between two 3-D points +// +inline float dist( Point3 pnt0, Point3 pnt1 ); + +// Linear interpolation between two 3-D points +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Point3 lerp( float t, Point3 pnt0, Point3 pnt1 ); + +// Conditionally select between two 3-D points +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Point3 select( Point3 pnt0, Point3 pnt1, bool select1 ); + +// Load x, y, and z elements from the first three words of a quadword. +// +// +inline void loadXYZ( Point3 & pnt, const vec_float4 * quad ); + +// Load x, y, and z elements from the first three words of a float array. +// +// +inline void loadXYZ( Point3 & pnt, const float * fptr ); + +// Store x, y, and z elements of a 3-D point in the first three words of a quadword. +// The value of the fourth word (the word with the highest address) remains unchanged +// +inline void storeXYZ( Point3 pnt, vec_float4 * quad ); + +// Store x, y, and z elements of a 3-D point in the first three words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZ( Point3 pnt, float * fptr ); + +// Load four three-float 3-D points, stored in three quadwords +// +inline void loadXYZArray( Point3 & pnt0, Point3 & pnt1, Point3 & pnt2, Point3 & pnt3, const vec_float4 * threeQuads ); + +// Store four 3-D points in three quadwords +// +inline void storeXYZArray( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, vec_float4 * threeQuads ); + +// Store eight 3-D points as half-floats +// +inline void storeHalfFloats( Point3 pnt0, Point3 pnt1, Point3 pnt2, Point3 pnt3, Point3 pnt4, Point3 pnt5, Point3 pnt6, Point3 pnt7, vec_ushort8 * threeQuads ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3-D point +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Point3 pnt ); + +// Print a 3-D point and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Point3 pnt, const char * name ); + +#endif + +// A quaternion in array-of-structures format +// +class Quat +{ + vec_float4 mVec128; + +public: + // Default constructor; does no initialization + // + inline Quat( ) : mVec128((vec_float4){0.0f, 0.0f, 0.0f, 0.0f}) { }; + + // Construct a quaternion from x, y, z, and w elements + // + inline Quat( float x, float y, float z, float w ); + + // Construct a quaternion from a 3-D vector and a scalar + // + inline Quat( Vector3 xyz, float w ); + + // Copy elements from a 4-D vector into a quaternion + // + explicit inline Quat( Vector4 vec ); + + // Convert a rotation matrix to a unit-length quaternion + // + explicit inline Quat( const Matrix3 & rotMat ); + + // Set all elements of a quaternion to the same scalar value + // + explicit inline Quat( float scalar ); + + // Set vector float data in a quaternion + // + explicit inline Quat( vec_float4 vf4 ); + + // Get vector float data from a quaternion + // + inline vec_float4 get128( ) const; + + // Assign one quaternion to another + // + inline Quat & operator =( Quat quat ); + + // Set the x, y, and z elements of a quaternion + // NOTE: + // This function does not change the w element. + // + inline Quat & setXYZ( Vector3 vec ); + + // Get the x, y, and z elements of a quaternion + // + inline const Vector3 getXYZ( ) const; + + // Set the x element of a quaternion + // + inline Quat & setX( float x ); + + // Set the y element of a quaternion + // + inline Quat & setY( float y ); + + // Set the z element of a quaternion + // + inline Quat & setZ( float z ); + + // Set the w element of a quaternion + // + inline Quat & setW( float w ); + + // Get the x element of a quaternion + // + inline float getX( ) const; + + // Get the y element of a quaternion + // + inline float getY( ) const; + + // Get the z element of a quaternion + // + inline float getZ( ) const; + + // Get the w element of a quaternion + // + inline float getW( ) const; + + // Set an x, y, z, or w element of a quaternion by index + // + inline Quat & setElem( int idx, float value ); + + // Get an x, y, z, or w element of a quaternion by index + // + inline float getElem( int idx ) const; + + // Subscripting operator to set or get an element + // + inline VecIdx operator []( int idx ); + + // Subscripting operator to get an element + // + inline float operator []( int idx ) const; + + // Add two quaternions + // + inline const Quat operator +( Quat quat ) const; + + // Subtract a quaternion from another quaternion + // + inline const Quat operator -( Quat quat ) const; + + // Multiply two quaternions + // + inline const Quat operator *( Quat quat ) const; + + // Multiply a quaternion by a scalar + // + inline const Quat operator *( float scalar ) const; + + // Divide a quaternion by a scalar + // + inline const Quat operator /( float scalar ) const; + + // Perform compound assignment and addition with a quaternion + // + inline Quat & operator +=( Quat quat ); + + // Perform compound assignment and subtraction by a quaternion + // + inline Quat & operator -=( Quat quat ); + + // Perform compound assignment and multiplication by a quaternion + // + inline Quat & operator *=( Quat quat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Quat & operator *=( float scalar ); + + // Perform compound assignment and division by a scalar + // + inline Quat & operator /=( float scalar ); + + // Negate all elements of a quaternion + // + inline const Quat operator -( ) const; + + // Construct an identity quaternion + // + static inline const Quat identity( ); + + // Construct a quaternion to rotate between two unit-length 3-D vectors + // NOTE: + // The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. + // + static inline const Quat rotation( Vector3 unitVec0, Vector3 unitVec1 ); + + // Construct a quaternion to rotate around a unit-length 3-D vector + // + static inline const Quat rotation( float radians, Vector3 unitVec ); + + // Construct a quaternion to rotate around the x axis + // + static inline const Quat rotationX( float radians ); + + // Construct a quaternion to rotate around the y axis + // + static inline const Quat rotationY( float radians ); + + // Construct a quaternion to rotate around the z axis + // + static inline const Quat rotationZ( float radians ); + +}; + +// Multiply a quaternion by a scalar +// +inline const Quat operator *( float scalar, Quat quat ); + +// Compute the conjugate of a quaternion +// +inline const Quat conj( Quat quat ); + +// Use a unit-length quaternion to rotate a 3-D vector +// +inline const Vector3 rotate( Quat unitQuat, Vector3 vec ); + +// Compute the dot product of two quaternions +// +inline float dot( Quat quat0, Quat quat1 ); + +// Compute the norm of a quaternion +// +inline float norm( Quat quat ); + +// Compute the length of a quaternion +// +inline float length( Quat quat ); + +// Normalize a quaternion +// NOTE: +// The result is unpredictable when all elements of quat are at or near zero. +// +inline const Quat normalize( Quat quat ); + +// Linear interpolation between two quaternions +// NOTE: +// Does not clamp t between 0 and 1. +// +inline const Quat lerp( float t, Quat quat0, Quat quat1 ); + +// Spherical linear interpolation between two quaternions +// NOTE: +// Interpolates along the shortest path between orientations. +// Does not clamp t between 0 and 1. +// +inline const Quat slerp( float t, Quat unitQuat0, Quat unitQuat1 ); + +// Spherical quadrangle interpolation +// +inline const Quat squad( float t, Quat unitQuat0, Quat unitQuat1, Quat unitQuat2, Quat unitQuat3 ); + +// Conditionally select between two quaternions +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Quat select( Quat quat0, Quat quat1, bool select1 ); + +// Load x, y, z, and w elements from the first four words of a float array. +// +// +inline void loadXYZW( Quat & quat, const float * fptr ); + +// Store x, y, z, and w elements of a quaternion in the first four words of a float array. +// Memory area of previous 16 bytes and next 32 bytes from fptr might be accessed +// +inline void storeXYZW( Quat quat, float * fptr ); + +#ifdef _VECTORMATH_DEBUG + +// Print a quaternion +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Quat quat ); + +// Print a quaternion and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( Quat quat, const char * name ); + +#endif + +// A 3x3 matrix in array-of-structures format +// +class Matrix3 +{ + Vector3 mCol0; + Vector3 mCol1; + Vector3 mCol2; + +public: + // Default constructor; does no initialization + // + inline Matrix3( ) { }; + + // Copy a 3x3 matrix + // + inline Matrix3( const Matrix3 & mat ); + + // Construct a 3x3 matrix containing the specified columns + // + inline Matrix3( Vector3 col0, Vector3 col1, Vector3 col2 ); + + // Construct a 3x3 rotation matrix from a unit-length quaternion + // + explicit inline Matrix3( Quat unitQuat ); + + // Set all elements of a 3x3 matrix to the same scalar value + // + explicit inline Matrix3( float scalar ); + + // Assign one 3x3 matrix to another + // + inline Matrix3 & operator =( const Matrix3 & mat ); + + // Set column 0 of a 3x3 matrix + // + inline Matrix3 & setCol0( Vector3 col0 ); + + // Set column 1 of a 3x3 matrix + // + inline Matrix3 & setCol1( Vector3 col1 ); + + // Set column 2 of a 3x3 matrix + // + inline Matrix3 & setCol2( Vector3 col2 ); + + // Get column 0 of a 3x3 matrix + // + inline const Vector3 getCol0( ) const; + + // Get column 1 of a 3x3 matrix + // + inline const Vector3 getCol1( ) const; + + // Get column 2 of a 3x3 matrix + // + inline const Vector3 getCol2( ) const; + + // Set the column of a 3x3 matrix referred to by the specified index + // + inline Matrix3 & setCol( int col, Vector3 vec ); + + // Set the row of a 3x3 matrix referred to by the specified index + // + inline Matrix3 & setRow( int row, Vector3 vec ); + + // Get the column of a 3x3 matrix referred to by the specified index + // + inline const Vector3 getCol( int col ) const; + + // Get the row of a 3x3 matrix referred to by the specified index + // + inline const Vector3 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector3 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector3 operator []( int col ) const; + + // Set the element of a 3x3 matrix referred to by column and row indices + // + inline Matrix3 & setElem( int col, int row, float val ); + + // Get the element of a 3x3 matrix referred to by column and row indices + // + inline float getElem( int col, int row ) const; + + // Add two 3x3 matrices + // + inline const Matrix3 operator +( const Matrix3 & mat ) const; + + // Subtract a 3x3 matrix from another 3x3 matrix + // + inline const Matrix3 operator -( const Matrix3 & mat ) const; + + // Negate all elements of a 3x3 matrix + // + inline const Matrix3 operator -( ) const; + + // Multiply a 3x3 matrix by a scalar + // + inline const Matrix3 operator *( float scalar ) const; + + // Multiply a 3x3 matrix by a 3-D vector + // + inline const Vector3 operator *( Vector3 vec ) const; + + // Multiply two 3x3 matrices + // + inline const Matrix3 operator *( const Matrix3 & mat ) const; + + // Perform compound assignment and addition with a 3x3 matrix + // + inline Matrix3 & operator +=( const Matrix3 & mat ); + + // Perform compound assignment and subtraction by a 3x3 matrix + // + inline Matrix3 & operator -=( const Matrix3 & mat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Matrix3 & operator *=( float scalar ); + + // Perform compound assignment and multiplication by a 3x3 matrix + // + inline Matrix3 & operator *=( const Matrix3 & mat ); + + // Construct an identity 3x3 matrix + // + static inline const Matrix3 identity( ); + + // Construct a 3x3 matrix to rotate around the x axis + // + static inline const Matrix3 rotationX( float radians ); + + // Construct a 3x3 matrix to rotate around the y axis + // + static inline const Matrix3 rotationY( float radians ); + + // Construct a 3x3 matrix to rotate around the z axis + // + static inline const Matrix3 rotationZ( float radians ); + + // Construct a 3x3 matrix to rotate around the x, y, and z axes + // + static inline const Matrix3 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 3x3 matrix to rotate around a unit-length 3-D vector + // + static inline const Matrix3 rotation( float radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Matrix3 rotation( Quat unitQuat ); + + // Construct a 3x3 matrix to perform scaling + // + static inline const Matrix3 scale( Vector3 scaleVec ); + +}; +// Multiply a 3x3 matrix by a scalar +// +inline const Matrix3 operator *( float scalar, const Matrix3 & mat ); + +// Append (post-multiply) a scale transformation to a 3x3 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix3 appendScale( const Matrix3 & mat, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 3x3 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix3 prependScale( Vector3 scaleVec, const Matrix3 & mat ); + +// Multiply two 3x3 matrices per element +// +inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ); + +// Compute the absolute value of a 3x3 matrix per element +// +inline const Matrix3 absPerElem( const Matrix3 & mat ); + +// Transpose of a 3x3 matrix +// +inline const Matrix3 transpose( const Matrix3 & mat ); + +// Compute the inverse of a 3x3 matrix +// NOTE: +// Result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix3 inverse( const Matrix3 & mat ); + +// Determinant of a 3x3 matrix +// +inline float determinant( const Matrix3 & mat ); + +// Conditionally select between two 3x3 matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3x3 matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix3 & mat ); + +// Print a 3x3 matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix3 & mat, const char * name ); + +#endif + +// A 4x4 matrix in array-of-structures format +// +class Matrix4 +{ + Vector4 mCol0; + Vector4 mCol1; + Vector4 mCol2; + Vector4 mCol3; + +public: + // Default constructor; does no initialization + // + inline Matrix4( ) { }; + + // Copy a 4x4 matrix + // + inline Matrix4( const Matrix4 & mat ); + + // Construct a 4x4 matrix containing the specified columns + // + inline Matrix4( Vector4 col0, Vector4 col1, Vector4 col2, Vector4 col3 ); + + // Construct a 4x4 matrix from a 3x4 transformation matrix + // + explicit inline Matrix4( const Transform3 & mat ); + + // Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector + // + inline Matrix4( const Matrix3 & mat, Vector3 translateVec ); + + // Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector + // + inline Matrix4( Quat unitQuat, Vector3 translateVec ); + + // Set all elements of a 4x4 matrix to the same scalar value + // + explicit inline Matrix4( float scalar ); + + // Assign one 4x4 matrix to another + // + inline Matrix4 & operator =( const Matrix4 & mat ); + + // Set the upper-left 3x3 submatrix + // NOTE: + // This function does not change the bottom row elements. + // + inline Matrix4 & setUpper3x3( const Matrix3 & mat3 ); + + // Get the upper-left 3x3 submatrix of a 4x4 matrix + // + inline const Matrix3 getUpper3x3( ) const; + + // Set translation component + // NOTE: + // This function does not change the bottom row elements. + // + inline Matrix4 & setTranslation( Vector3 translateVec ); + + // Get the translation component of a 4x4 matrix + // + inline const Vector3 getTranslation( ) const; + + // Set column 0 of a 4x4 matrix + // + inline Matrix4 & setCol0( Vector4 col0 ); + + // Set column 1 of a 4x4 matrix + // + inline Matrix4 & setCol1( Vector4 col1 ); + + // Set column 2 of a 4x4 matrix + // + inline Matrix4 & setCol2( Vector4 col2 ); + + // Set column 3 of a 4x4 matrix + // + inline Matrix4 & setCol3( Vector4 col3 ); + + // Get column 0 of a 4x4 matrix + // + inline const Vector4 getCol0( ) const; + + // Get column 1 of a 4x4 matrix + // + inline const Vector4 getCol1( ) const; + + // Get column 2 of a 4x4 matrix + // + inline const Vector4 getCol2( ) const; + + // Get column 3 of a 4x4 matrix + // + inline const Vector4 getCol3( ) const; + + // Set the column of a 4x4 matrix referred to by the specified index + // + inline Matrix4 & setCol( int col, Vector4 vec ); + + // Set the row of a 4x4 matrix referred to by the specified index + // + inline Matrix4 & setRow( int row, Vector4 vec ); + + // Get the column of a 4x4 matrix referred to by the specified index + // + inline const Vector4 getCol( int col ) const; + + // Get the row of a 4x4 matrix referred to by the specified index + // + inline const Vector4 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector4 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector4 operator []( int col ) const; + + // Set the element of a 4x4 matrix referred to by column and row indices + // + inline Matrix4 & setElem( int col, int row, float val ); + + // Get the element of a 4x4 matrix referred to by column and row indices + // + inline float getElem( int col, int row ) const; + + // Add two 4x4 matrices + // + inline const Matrix4 operator +( const Matrix4 & mat ) const; + + // Subtract a 4x4 matrix from another 4x4 matrix + // + inline const Matrix4 operator -( const Matrix4 & mat ) const; + + // Negate all elements of a 4x4 matrix + // + inline const Matrix4 operator -( ) const; + + // Multiply a 4x4 matrix by a scalar + // + inline const Matrix4 operator *( float scalar ) const; + + // Multiply a 4x4 matrix by a 4-D vector + // + inline const Vector4 operator *( Vector4 vec ) const; + + // Multiply a 4x4 matrix by a 3-D vector + // + inline const Vector4 operator *( Vector3 vec ) const; + + // Multiply a 4x4 matrix by a 3-D point + // + inline const Vector4 operator *( Point3 pnt ) const; + + // Multiply two 4x4 matrices + // + inline const Matrix4 operator *( const Matrix4 & mat ) const; + + // Multiply a 4x4 matrix by a 3x4 transformation matrix + // + inline const Matrix4 operator *( const Transform3 & tfrm ) const; + + // Perform compound assignment and addition with a 4x4 matrix + // + inline Matrix4 & operator +=( const Matrix4 & mat ); + + // Perform compound assignment and subtraction by a 4x4 matrix + // + inline Matrix4 & operator -=( const Matrix4 & mat ); + + // Perform compound assignment and multiplication by a scalar + // + inline Matrix4 & operator *=( float scalar ); + + // Perform compound assignment and multiplication by a 4x4 matrix + // + inline Matrix4 & operator *=( const Matrix4 & mat ); + + // Perform compound assignment and multiplication by a 3x4 transformation matrix + // + inline Matrix4 & operator *=( const Transform3 & tfrm ); + + // Construct an identity 4x4 matrix + // + static inline const Matrix4 identity( ); + + // Construct a 4x4 matrix to rotate around the x axis + // + static inline const Matrix4 rotationX( float radians ); + + // Construct a 4x4 matrix to rotate around the y axis + // + static inline const Matrix4 rotationY( float radians ); + + // Construct a 4x4 matrix to rotate around the z axis + // + static inline const Matrix4 rotationZ( float radians ); + + // Construct a 4x4 matrix to rotate around the x, y, and z axes + // + static inline const Matrix4 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 4x4 matrix to rotate around a unit-length 3-D vector + // + static inline const Matrix4 rotation( float radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Matrix4 rotation( Quat unitQuat ); + + // Construct a 4x4 matrix to perform scaling + // + static inline const Matrix4 scale( Vector3 scaleVec ); + + // Construct a 4x4 matrix to perform translation + // + static inline const Matrix4 translation( Vector3 translateVec ); + + // Construct viewing matrix based on eye position, position looked at, and up direction + // + static inline const Matrix4 lookAt( Point3 eyePos, Point3 lookAtPos, Vector3 upVec ); + + // Construct a perspective projection matrix + // + static inline const Matrix4 perspective( float fovyRadians, float aspect, float zNear, float zFar ); + + // Construct a perspective projection matrix based on frustum + // + static inline const Matrix4 frustum( float left, float right, float bottom, float top, float zNear, float zFar ); + + // Construct an orthographic projection matrix + // + static inline const Matrix4 orthographic( float left, float right, float bottom, float top, float zNear, float zFar ); + +}; +// Multiply a 4x4 matrix by a scalar +// +inline const Matrix4 operator *( float scalar, const Matrix4 & mat ); + +// Append (post-multiply) a scale transformation to a 4x4 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix4 appendScale( const Matrix4 & mat, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 4x4 matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Matrix4 prependScale( Vector3 scaleVec, const Matrix4 & mat ); + +// Multiply two 4x4 matrices per element +// +inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ); + +// Compute the absolute value of a 4x4 matrix per element +// +inline const Matrix4 absPerElem( const Matrix4 & mat ); + +// Transpose of a 4x4 matrix +// +inline const Matrix4 transpose( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix +// NOTE: +// Result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix4 inverse( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. +// +inline const Matrix4 affineInverse( const Matrix4 & mat ); + +// Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. +// +inline const Matrix4 orthoInverse( const Matrix4 & mat ); + +// Determinant of a 4x4 matrix +// +inline float determinant( const Matrix4 & mat ); + +// Conditionally select between two 4x4 matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 4x4 matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix4 & mat ); + +// Print a 4x4 matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Matrix4 & mat, const char * name ); + +#endif + +// A 3x4 transformation matrix in array-of-structures format +// +class Transform3 +{ + Vector3 mCol0; + Vector3 mCol1; + Vector3 mCol2; + Vector3 mCol3; + +public: + // Default constructor; does no initialization + // + inline Transform3( ) { }; + + // Copy a 3x4 transformation matrix + // + inline Transform3( const Transform3 & tfrm ); + + // Construct a 3x4 transformation matrix containing the specified columns + // + inline Transform3( Vector3 col0, Vector3 col1, Vector3 col2, Vector3 col3 ); + + // Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector + // + inline Transform3( const Matrix3 & tfrm, Vector3 translateVec ); + + // Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector + // + inline Transform3( Quat unitQuat, Vector3 translateVec ); + + // Set all elements of a 3x4 transformation matrix to the same scalar value + // + explicit inline Transform3( float scalar ); + + // Assign one 3x4 transformation matrix to another + // + inline Transform3 & operator =( const Transform3 & tfrm ); + + // Set the upper-left 3x3 submatrix + // + inline Transform3 & setUpper3x3( const Matrix3 & mat3 ); + + // Get the upper-left 3x3 submatrix of a 3x4 transformation matrix + // + inline const Matrix3 getUpper3x3( ) const; + + // Set translation component + // + inline Transform3 & setTranslation( Vector3 translateVec ); + + // Get the translation component of a 3x4 transformation matrix + // + inline const Vector3 getTranslation( ) const; + + // Set column 0 of a 3x4 transformation matrix + // + inline Transform3 & setCol0( Vector3 col0 ); + + // Set column 1 of a 3x4 transformation matrix + // + inline Transform3 & setCol1( Vector3 col1 ); + + // Set column 2 of a 3x4 transformation matrix + // + inline Transform3 & setCol2( Vector3 col2 ); + + // Set column 3 of a 3x4 transformation matrix + // + inline Transform3 & setCol3( Vector3 col3 ); + + // Get column 0 of a 3x4 transformation matrix + // + inline const Vector3 getCol0( ) const; + + // Get column 1 of a 3x4 transformation matrix + // + inline const Vector3 getCol1( ) const; + + // Get column 2 of a 3x4 transformation matrix + // + inline const Vector3 getCol2( ) const; + + // Get column 3 of a 3x4 transformation matrix + // + inline const Vector3 getCol3( ) const; + + // Set the column of a 3x4 transformation matrix referred to by the specified index + // + inline Transform3 & setCol( int col, Vector3 vec ); + + // Set the row of a 3x4 transformation matrix referred to by the specified index + // + inline Transform3 & setRow( int row, Vector4 vec ); + + // Get the column of a 3x4 transformation matrix referred to by the specified index + // + inline const Vector3 getCol( int col ) const; + + // Get the row of a 3x4 transformation matrix referred to by the specified index + // + inline const Vector4 getRow( int row ) const; + + // Subscripting operator to set or get a column + // + inline Vector3 & operator []( int col ); + + // Subscripting operator to get a column + // + inline const Vector3 operator []( int col ) const; + + // Set the element of a 3x4 transformation matrix referred to by column and row indices + // + inline Transform3 & setElem( int col, int row, float val ); + + // Get the element of a 3x4 transformation matrix referred to by column and row indices + // + inline float getElem( int col, int row ) const; + + // Multiply a 3x4 transformation matrix by a 3-D vector + // + inline const Vector3 operator *( Vector3 vec ) const; + + // Multiply a 3x4 transformation matrix by a 3-D point + // + inline const Point3 operator *( Point3 pnt ) const; + + // Multiply two 3x4 transformation matrices + // + inline const Transform3 operator *( const Transform3 & tfrm ) const; + + // Perform compound assignment and multiplication by a 3x4 transformation matrix + // + inline Transform3 & operator *=( const Transform3 & tfrm ); + + // Construct an identity 3x4 transformation matrix + // + static inline const Transform3 identity( ); + + // Construct a 3x4 transformation matrix to rotate around the x axis + // + static inline const Transform3 rotationX( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the y axis + // + static inline const Transform3 rotationY( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the z axis + // + static inline const Transform3 rotationZ( float radians ); + + // Construct a 3x4 transformation matrix to rotate around the x, y, and z axes + // + static inline const Transform3 rotationZYX( Vector3 radiansXYZ ); + + // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector + // + static inline const Transform3 rotation( float radians, Vector3 unitVec ); + + // Construct a rotation matrix from a unit-length quaternion + // + static inline const Transform3 rotation( Quat unitQuat ); + + // Construct a 3x4 transformation matrix to perform scaling + // + static inline const Transform3 scale( Vector3 scaleVec ); + + // Construct a 3x4 transformation matrix to perform translation + // + static inline const Transform3 translation( Vector3 translateVec ); + +}; +// Append (post-multiply) a scale transformation to a 3x4 transformation matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Transform3 appendScale( const Transform3 & tfrm, Vector3 scaleVec ); + +// Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix +// NOTE: +// Faster than creating and multiplying a scale transformation matrix. +// +inline const Transform3 prependScale( Vector3 scaleVec, const Transform3 & tfrm ); + +// Multiply two 3x4 transformation matrices per element +// +inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ); + +// Compute the absolute value of a 3x4 transformation matrix per element +// +inline const Transform3 absPerElem( const Transform3 & tfrm ); + +// Inverse of a 3x4 transformation matrix +// NOTE: +// Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. +// +inline const Transform3 inverse( const Transform3 & tfrm ); + +// Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix +// NOTE: +// This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. +// +inline const Transform3 orthoInverse( const Transform3 & tfrm ); + +// Conditionally select between two 3x4 transformation matrices +// NOTE: +// This function uses a conditional select instruction to avoid a branch. +// +inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ); + +#ifdef _VECTORMATH_DEBUG + +// Print a 3x4 transformation matrix +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Transform3 & tfrm ); + +// Print a 3x4 transformation matrix and an associated string identifier +// NOTE: +// Function is only defined when _VECTORMATH_DEBUG is defined. +// +inline void print( const Transform3 & tfrm, const char * name ); + +#endif + +} // namespace Aos +} // namespace Vectormath + +#include "vec_aos.h" +#include "quat_aos.h" +#include "mat_aos.h" + +#endif diff --git a/ppu/include/font/font.h b/ppu/include/font/font.h new file mode 100644 index 00000000..fa188f35 --- /dev/null +++ b/ppu/include/font/font.h @@ -0,0 +1,266 @@ +#ifndef __LV2_FONT_H__ +#define __LV2_FONT_H__ + +#include + +#include + +#define FONT_LIBRARY_TYPE_NONE 0 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* (*fontMallocCallback)(void *object,u32 size); +typedef void (*fontFreeCallback)(void *object,void *ptr); +typedef void* (*fontReallocCallback)(void *object,void *p,u32 reallocSize); +typedef void* (*fontCallocCallback)(void *object,u32 num,u32 size); + +typedef struct _font_memory_interface +{ + void *object ATTRIBUTE_PRXPTR; + fontMallocCallback malloc_func ATTRIBUTE_PRXPTR; + fontFreeCallback free_func ATTRIBUTE_PRXPTR; + fontReallocCallback realloc_func ATTRIBUTE_PRXPTR; + fontCallocCallback calloc_func ATTRIBUTE_PRXPTR; +} fontMemoryInterface; + +typedef struct _font_entry +{ + u32 lock; + u32 uniqueId; + const void* fontLib ATTRIBUTE_PRXPTR; + void* fontH ATTRIBUTE_PRXPTR; +} fontEntry; + +typedef struct _font_config +{ + struct { + u32 *buffer ATTRIBUTE_PRXPTR; + u32 size; + } fileCache; + + u32 userFontEntryMax; + fontEntry *userFontEntries ATTRIBUTE_PRXPTR; + u32 flags; +} fontConfig; + +typedef struct _font_library +{ + u32 libraryType, libraryVersion; + u32 systemClosed[]; +} fontLibrary; + +typedef struct _font_type +{ + u32 type; + u32 map; +} fontType; + +typedef struct _font +{ + void* ATTRIBUTE_PRXPTR systemReserved[64]; +} font; + +typedef struct _font_renderer +{ + void* ATTRIBUTE_PRXPTR systemReserved[64]; +} fontRenderer; + +typedef struct _font_renderer_config +{ + struct { + void* buffer ATTRIBUTE_PRXPTR; + u32 initSize; + u32 maxSize; + u32 expandSize; + u32 resetSize; + } bufferingPolicy; +} fontRendererConfig; + +typedef struct _font_horizontal_layout +{ + f32 baseLineY; + f32 lineHeight; + f32 effectHeight; +} fontHorizontalLayout; + +typedef struct _font_vertical_layout +{ + f32 baseLineX; + f32 lineWidth; + f32 effectWidth; +} fontVerticalLayout; + +typedef struct _font_glyph_metrics +{ + f32 width; + f32 height; + + struct { + f32 bearingX; + f32 bearingY; + f32 advance; + } horizontal; + struct { + f32 bearingX; + f32 bearingY; + f32 advance; + } vertical; +} fontGlyphMetrics; + +typedef struct _font_glyph_outline +{ + s16 contoursCount; + s16 pointsCount; + + struct { + f32 x, y; + } *Points ATTRIBUTE_PRXPTR; + + u8 * pointTags ATTRIBUTE_PRXPTR; + u16* contourIndexs ATTRIBUTE_PRXPTR; + u32 flags; + void* generateEnv ATTRIBUTE_PRXPTR; +} fontGlyphOutline; + +typedef struct _font_glyph +{ + u16 cf_type, type; + u32 size; + fontGlyphMetrics metrics; + fontGlyphOutline outline; +} fontGlyph; + +typedef struct _font_kerning +{ + f32 offsetX; + f32 offsetY; +} fontKerning; + +typedef struct _font_glyph_style +{ + struct { + f32 widthPixel; + f32 heightPixel; + } Scale; + struct { + f32 weight; + f32 slant; + } Effect; +} fontGlyphStyle; + +typedef struct _font_render_surface +{ + void* buffer ATTRIBUTE_PRXPTR; + s32 widthByte; + s32 pixelSizeByte; + s32 width, height; + struct { + u32 x0, y0; + u32 x1, y1; + } Scissor; +} fontRenderSurface; + +typedef struct _font_image_trans_info +{ + u8 *image ATTRIBUTE_PRXPTR; + u32 imageWidthByte; + u32 imageWidth; + u32 imageHeight; + void *surface ATTRIBUTE_PRXPTR; + u32 surfWidthByte; +} fontImageTransInfo; + +static inline void fontMemoryInterface_initialize(fontMemoryInterface *mIF) +{ + mIF->object = NULL; + mIF->malloc_func = NULL; + mIF->free_func = NULL; + mIF->realloc_func = NULL; + mIF->calloc_func = NULL; +} + +static inline void fontConfig_initialize(fontConfig *config) +{ + config->fileCache.buffer = NULL; + config->fileCache.size = 0; + config->userFontEntryMax = 0; + config->userFontEntries = NULL; + config->flags = 0x00000000; +} + +static inline s32 fontInit(fontConfig *config) +{ + extern void fontGetStubRevisionFlags(u64 *revisionFlags); + extern s32 fontInitializeWithRevision(u64 revision, fontConfig *config); + u64 revisionFlags = 0LL; + + fontGetStubRevisionFlags(&revisionFlags); + return fontInitializeWithRevision(revisionFlags, config); +} + +s32 fontOpenFontset(const fontLibrary *lib,fontType *type,font *f); +s32 fontOpenFontsetOnMemory(const fontLibrary *lib,fontType *type,font *f); +s32 fontOpenFontFile(const fontLibrary *lib,const char *fontPath,u32 subNum,s32 uniqueID,font *f); +s32 fontOpenFontMemory(const fontLibrary *lib,void *fontAddr,u32 fontSize,u32 subNum,s32 uniqueID,font *f); +s32 fontOpenFontInstance(font *openedFont,font *f); +s32 fontGetLibrary(font *f,const fontLibrary **lib,u32 *type); +s32 fontAdjustGlyphExpandBuffer(font *f,s32 pointN,s32 contourN); +s32 fontGetGlyphExpandBufferInfo(font *f,s32 *pointN,s32 *contourN); +s32 fontAdjustFontScaling(font *f,f32 fontScale); +s32 fontSetResolutionDpi(font *f,u32 hDpi,u32 vDpi); +s32 fontSetScalePoint(font *f,f32 w,f32 h); +s32 fontontSetScalePixel(font *f,f32 w,f32 h); +s32 fontSetEffectWeight(font *f,f32 effectWeight); +s32 fontSetEffectSlant(font *f,f32 effectSlant); +s32 fontGetResolutionDpi(font *f,u32 *hDpi,u32 *vDpi); +s32 fontGetScalePoint(font *f,f32 *w,f32 *h); +s32 fontGetScalePixel(font *f,f32 *w,f32 *h); +s32 fontGetEffectWeight(font *f,f32 *effectWeight); +s32 fontGetEffectSlant(font *f,f32 *effectSlant); +s32 fontGetHorizontalLayout(font *f,fontHorizontalLayout *layout); +s32 fontGetVerticalLayout(font *f,fontVerticalLayout *layout); +s32 fontGetFontIdCode(font *f,u32 code,u32 *fontId,u32 *fontcode); +s32 fontGetCharGlyphMetrics(font *f,u32 code,fontGlyphMetrics *metrics); +s32 fontGetCharGlyphMetricsVertical(font *f,u32 code,fontGlyphMetrics *metrics); +s32 fontGetKerning(font *f,u32 preCode,u32 code,fontKerning *kerning); +s32 fontCreateRenderer(const fontLibrary *lib,fontRendererConfig *confing,fontRenderer *renderer); +s32 fontBindRenderer(font *f,fontRenderer *renderer); +s32 fontGetBindingRenderer(font *f,fontRenderer **renderer); +s32 fontSetupRenderScalePoint(font *f,f32 w,f32 h); +s32 fontSetupRenderScalePixel(font *f,f32 w,f32 h); +s32 fontSetupRenderEffectWeight(font *f,f32 additionalWeight); +s32 fontSetupRenderEffectSlant(font *f,f32 effectSlant); +s32 fontGetRenderScalePoint(font *f,f32 *w,f32 *h); +s32 fontGetRenderScalePixel(font *f,f32 *w,f32 *h); +s32 fontGetRenderEffectWeight(font *f,f32 *effectWeight); +s32 fontGetRenderEffectSlant(font *f,f32 *effectSlant); +s32 fontGetRenderCharGlyphMetrics(font *f,u32 code,fontGlyphMetrics *metrics); +s32 fontGetRenderCharGlyphMetricsVertical(font *cfEx,u32 code,fontGlyphMetrics *metrics); +s32 fontGetRenderScaledKerning(font *f,u32 preCode,u32 code,fontKerning *kerning); +s32 fontGenerateCharGlyph(font *f,u32 code,fontGlyph **glyph); +s32 fontGenerateCharGlyphVertical(font *f,u32 code,fontGlyph **glyph); +s32 fontDeleteGlyph(font *f,fontGlyph *glyph); +s32 fontDelete(const fontLibrary *library,void *p); +void fontRenderSurfaceInit(fontRenderSurface *surface,void *buffer,s32 bufWidthByte,s32 pixelSizeByte,s32 w,s32 h); +void fontRenderSurfaceSetScissor(fontRenderSurface *surface,s32 x0,s32 y0,u32 w,u32 h); +s32 fontRenderCharGlyphImage(font *f,u32 code,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontRenderCharGlyphImageHorizontal(font *f,u32 code,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontRenderCharGlyphImageVertical(font *f,u32 code,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontUnbindRenderer(font *f); +s32 fontGlyphRenderImage(fontGlyph *glyph,fontGlyphStyle *style,fontRenderer *renderer,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontGlyphRenderImageHorizontal(fontGlyph *glyph,fontGlyphStyle *style,fontRenderer *renderer,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontGlyphRenderImageVertical(fontGlyph *glyph,fontGlyphStyle *style,fontRenderer *renderer,fontRenderSurface *surface,f32 x,f32 y,fontGlyphMetrics *metrics,fontImageTransInfo *transInfo); +s32 fontGlyphGetHorizontalShift(fontGlyph *glyph,f32 *shiftX,f32 *shiftY); +s32 fontGlyphGetVerticalShift(fontGlyph *glyph,f32 *shiftX,f32 *shiftY); +s32 fontDestroyRenderer(fontRenderer *renderer); +s32 fontCloseFont(font *cf); +s32 fontEndLibrary(const fontLibrary *lib); +s32 fontEnd(); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ppu/include/font/fontFT.h b/ppu/include/font/fontFT.h new file mode 100644 index 00000000..735e734b --- /dev/null +++ b/ppu/include/font/fontFT.h @@ -0,0 +1,43 @@ +#ifndef __LV2_FONTFT_H__ +#define __LV2_FONTFT_H__ + +#include + +#include + +#define FONT_LIBRARY_TYPE_FREETYPE 2 + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _font_library_configFT +{ + void *library ATTRIBUTE_PRXPTR; + fontMemoryInterface memoryIF; +} fontLibraryConfigFT; + +typedef struct _font_renderer_configFT +{ + struct { + void *buffer ATTRIBUTE_PRXPTR; + u32 initSize; + u32 maxSize; + u32 expandSize; + u32 resetSize; + } bufferingPolicy; +} fontRendererConfigFT; + +static inline void fontLibraryConfigFT_initialize(fontLibraryConfigFT *config) +{ + config->library = NULL; + fontMemoryInterface_initialize(&config->memoryIF); +} + +s32 fontInitLibraryFreeType(fontLibraryConfigFT *config,const fontLibrary **lib); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ppu/include/font/fontset.h b/ppu/include/font/fontset.h new file mode 100644 index 00000000..ae435091 --- /dev/null +++ b/ppu/include/font/fontset.h @@ -0,0 +1,41 @@ +#ifndef __LV2_FONTSET_H__ +#define __LV2_FONTSET_H__ + +#define FONT_TYPE_RODIN_SANS_SERIF_LATIN 0x00000000 +#define FONT_TYPE_MATISSE_SERIF_LATIN 0x00000020 +#define FONT_TYPE_NEWRODIN_GOTHIC_JAPANESE 0x00000008 +#define FONT_TYPE_YD_GOTHIC_KOREAN 0x0000000c + +#define FONT_TYPE_NEWRODIN_GOTHIC_JP_SET 0x00000100 +#define FONT_TYPE_NEWRODIN_GOTHIC_LATIN_SET 0x00000101 +#define FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_SET 0x00000108 //SDK1.60- +#define FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN_SET 0x00000109 //SDK1.60- +#define FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_TCH_SET 0x0000010a //SDK1.60- +#define FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_TCH_SET 0x0000010b //SDK1.60- +#define FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_SCH_SET 0x0000010c //SDK1.60- +#define FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_SCH_SET 0x0000010d //SDK1.60- + +//SDK1.00- +// ========================================================================================================== +#define FONT_TYPE_DEFAULT_GOTHIC_SET FONT_TYPE_NEWRODIN_GOTHIC_LATIN_SET +#define FONT_TYPE_DEFAULT_GOTHIC_LATIN_SET FONT_TYPE_NEWRODIN_GOTHIC_LATIN_SET +#define FONT_TYPE_DEFAULT_GOTHIC_JP_SET FONT_TYPE_NEWRODIN_GOTHIC_JP_SET +#define FONT_TYPE_DEFAULT_SANS_SERIF FONT_TYPE_RODIN_SANS_SERIF_LATIN +#define FONT_TYPE_DEFAULT_SERIF FONT_TYPE_MATISSE_SERIF_LATIN + +//SDK1.60- +// ========================================================================================================== +#define FONT_TYPE_GOTHIC_JAPANESE_CJK_JP_SET FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_SET +#define FONT_TYPE_GOTHIC_JAPANESE_CJK_LATIN_SET FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN_SET +#define FONT_TYPE_GOTHIC_TCHINESE_CJK_JP_SET FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_TCH_SET +#define FONT_TYPE_GOTHIC_TCHINESE_CJK_LATIN_SET FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_TCH_SET +#define FONT_TYPE_GOTHIC_SCHINESE_CJK_JP_SET FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_SCH_SET +#define FONT_TYPE_GOTHIC_SCHINESE_CJK_LATIN_SET FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_SCH_SET +// ---------------------------------------------------------------------------------------------------------- + +//----------------------------------- +#define FONT_MAP_FONT 0x0 +#define FONT_MAP_UNICODE 0x1 +//----------------------------------- + +#endif diff --git a/ppu/include/http/http.h b/ppu/include/http/http.h old mode 100755 new mode 100644 index b768b008..0d29554e --- a/ppu/include/http/http.h +++ b/ppu/include/http/http.h @@ -100,13 +100,10 @@ static const char HTTP_METHOD_TRACE[] = "TRACE"; * structures */ -struct httpClient; -struct httpTransaction; +typedef s32 httpClientId; +typedef s32 httpTransId; -typedef struct httpClient* httpClientId; -typedef struct httpTransaction* httpTransId; - -typedef const void* httpSslId; +typedef s32 httpSslId; /* @@ -125,41 +122,44 @@ typedef int (*httpCookieRecvCallback)(httpTransId tid,const httpUri *uri,const c */ /* initialization */ -s32 httpInit(void *pool,size_t poolSize); +s32 httpInit(void *pool,u32 poolSize); s32 httpEnd(void); /* transaction request */ -s32 httpSendRequest(httpTransId tid,const char *buf,size_t size,size_t *sent); -s32 httpRecvResponse(httpTransId tid,char *buf,size_t size,size_t *recvd); +s32 httpSendRequest(httpTransId tid,const char *buf,u32 size,u32 *sent); +s32 httpRecvResponse(httpTransId tid,char *buf,u32 size,u32 *recvd); /* proxy */ s32 httpSetProxy(const httpUri *proxy); -s32 httpGetProxy(httpUri *proxy,void *pool,size_t poolSize,size_t *required); +s32 httpGetProxy(httpUri *proxy,void *pool,u32 poolSize,u32 *required); /* request content length */ s32 httpRequestSetContentLength(httpTransId tid,u64 totalSize); s32 httpRequestGetContentLength(httpTransId tid,u64 *totalSize); /* request headers */ -s32 httpRequestGetAllHeaders(httpTransId tid,httpHeader **headers,size_t *items,void *pool,size_t poolSize,size_t *required); +s32 httpRequestGetAllHeaders(httpTransId tid,httpHeader **headers,u32 *items,void *pool,u32 poolSize,u32 *required); s32 httpRequestSetHeader(httpTransId tid,const httpHeader *header); -s32 httpRequestGetHeader(httpTransId tid,httpHeader *header,const char *name,void *pool,size_t poolSize,size_t *required); +s32 httpRequestGetHeader(httpTransId tid,httpHeader *header,const char *name,void *pool,u32 poolSize,u32 *required); s32 httpRequestAddHeader(httpTransId tid,const httpHeader *header); s32 httpRequestDeleteHeader(httpTransId tid,const char *name); /* response status code */ s32 httpResponseGetStatusCode(httpTransId tid,int32_t *code); +/* response content length */ +s32 httpResponseGetContentLength(httpTransId tid,u64 *totalSize); + /* response status line */ -s32 httpResponseGetStatusLine(httpTransId tid,httpStatusLine *status,void *pool,size_t poolSize,size_t *required); +s32 httpResponseGetStatusLine(httpTransId tid,httpStatusLine *status,void *pool,u32 poolSize,u32 *required); /* cookies */ -s32 httpInitCookie(void *pool,size_t poolSize); +s32 httpInitCookie(void *pool,u32 poolSize); s32 httpEndCookie(void); s32 httpAddCookieWithClientId(const httpUri *uri,const char *cookie,httpClientId cid); s32 httpSessionCookieFlush(httpClientId cid); -s32 httpCookieExportWithClientId(void *buf,size_t size,size_t *exportSize,httpClientId cid); -s32 httpCookieImportWithClientId(const void *buf,size_t size,httpClientId cid); +s32 httpCookieExportWithClientId(void *buf,u32 size,u32 *exportSize,httpClientId cid); +s32 httpCookieImportWithClientId(const void *buf,u32 size,httpClientId cid); /* cookie callbacks */ s32 httpClientSetCookieSendCallback(httpClientId cid,httpCookieSendCallback cb,void *arg); @@ -176,7 +176,7 @@ s32 httpDestroyClient(httpClientId cid); /* proxy */ s32 httpClientSetProxy(httpClientId cid,const httpUri *proxy); -s32 httpClientGetProxy(httpClientId cid,httpUri *proxy,void *pool,size_t poolSize,size_t *required); +s32 httpClientGetProxy(httpClientId cid,httpUri *proxy,void *pool,u32 poolSize,u32 *required); /* version */ s32 httpClientSetVersion(httpClientId cid,u32 major,u32 minor); @@ -208,11 +208,11 @@ s32 httpClientGetCookieStatus(httpClientId cid,u32 *enable); /* user agent */ s32 httpClientSetUserAgent(httpClientId cid,const char *userAgent); -s32 httpClientGetUserAgent(httpClientId cid,char *userAgent,size_t size,size_t *required); +s32 httpClientGetUserAgent(httpClientId cid,char *userAgent,u32 size,u32 *required); /* buffer max */ -s32 httpClientSetResponseBufferMax(httpClientId cid,size_t max); -s32 httpClientGetResponseBufferMax(httpClientId cid,size_t *max); +s32 httpClientSetResponseBufferMax(httpClientId cid,u32 max); +s32 httpClientGetResponseBufferMax(httpClientId cid,u32 *max); /* close connections */ s32 httpClientCloseAllConnections(httpClientId cid); @@ -234,24 +234,24 @@ s32 httpClientSetConnTimeout(httpClientId cid,s64 usec); s32 httpClientGetConnTimeout(httpClientId cid,s64 *usec); /* pool size */ -s32 httpClientSetTotalPoolSize(httpClientId cid,size_t poolSize); -s32 httpClientGetTotalPoolSize(httpClientId cid,size_t *poolSize); -s32 httpClientSetPerHostPoolSize(httpClientId cid,size_t poolSize); -s32 httpClientGetPerHostPoolSize(httpClientId cid,size_t *poolSize); +s32 httpClientSetTotalPoolSize(httpClientId cid,u32 poolSize); +s32 httpClientGetTotalPoolSize(httpClientId cid,u32 *poolSize); +s32 httpClientSetPerHostPoolSize(httpClientId cid,u32 poolSize); +s32 httpClientGetPerHostPoolSize(httpClientId cid,u32 *poolSize); /* keep alive */ -s32 httpClientSetPerHostKeepAliveMax(httpClientId cid,size_t maxSize); -s32 httpClientGetPerHostKeepAliveMax(httpClientId cid,size_t *maxSize); +s32 httpClientSetPerHostKeepAliveMax(httpClientId cid,u32 maxSize); +s32 httpClientGetPerHostKeepAliveMax(httpClientId cid,u32 *maxSize); /* pipeline */ -s32 httpClientSetPerPipelineMax(httpClientId cid,size_t pipeMax); -s32 httpClientGetPerPipelineMax(httpClientId cid,size_t *pipeMax); +s32 httpClientSetPerPipelineMax(httpClientId cid,u32 pipeMax); +s32 httpClientGetPerPipelineMax(httpClientId cid,u32 *pipeMax); /* client headers */ -s32 httpClientGetAllHeaders(httpClientId cid,httpHeader **headers,size_t *items,void *pool,size_t poolSize,size_t *required); +s32 httpClientGetAllHeaders(httpClientId cid,httpHeader **headers,u32 *items,void *pool,u32 poolSize,u32 *required); s32 httpClientSetHeader(httpClientId cid,const httpHeader *header); -s32 httpClientGetHeader(httpClientId cid,httpHeader *header,const char *name,void *pool,size_t poolSize,size_t *required); +s32 httpClientGetHeader(httpClientId cid,httpHeader *header,const char *name,void *pool,u32 poolSize,u32 *required); s32 httpClientAddHeader(httpClientId cid,const httpHeader *header); s32 httpClientDeleteHeader(httpClientId cid,const char *name); @@ -267,17 +267,17 @@ s32 httpClientSetRedirectCallback(httpClientId cid,httpRedirectCallback cb,void /* general transactions */ s32 httpCreateTransaction(httpTransId *tid,httpClientId cid,const char *method,const httpUri *uri); s32 httpDestroyTransaction(httpTransId tid); -s32 httpTransactionGetUri(httpTransId tid,httpUri *uri,void *pool,size_t poolSize,size_t *required); +s32 httpTransactionGetUri(httpTransId tid,httpUri *uri,void *pool,u32 poolSize,u32 *required); s32 httpTransactionCloseConnection(httpTransId tid); s32 httpTransactionReleaseConnection(httpTransId tid,int *sid); s32 httpTransactionAbortConnection(httpTransId tid); /* SSL transactions */ -s32 httpTransactionGetSslCipherName(httpTransId tid,char *name,size_t size,size_t *required); +s32 httpTransactionGetSslCipherName(httpTransId tid,char *name,u32 size,u32 *required); s32 httpTransactionGetSslCipherId(httpTransId tid,int32_t *id); -s32 httpTransactionGetSslCipherVersion(httpTransId tid,char *version,size_t size,size_t *required); +s32 httpTransactionGetSslCipherVersion(httpTransId tid,char *version,u32 size,u32 *required); s32 httpTransactionGetSslCipherBits(httpTransId tid,int32_t *effectiveBits,int32_t *algorithmBits); -s32 httpTransactionGetSslCipherString(httpTransId tid,char *buffer,size_t size); +s32 httpTransactionGetSslCipherString(httpTransId tid,char *buffer,u32 size); s32 httpTransactionGetSslVersion(httpTransId tid,int32_t *version); s32 httpTransactionGetSslId(httpTransId tid,httpSslId *id); diff --git a/ppu/include/http/https.h b/ppu/include/http/https.h index 5158d8aa..17517ab0 100644 --- a/ppu/include/http/https.h +++ b/ppu/include/http/https.h @@ -18,7 +18,7 @@ extern "C" { typedef struct _https_data { char *ptr ATTRIBUTE_PRXPTR; - size_t size; + u32 size; } httpsData; @@ -34,14 +34,14 @@ typedef int (*httpsSslCallback)(s32 verErr,sslCert const sslCerts[],int certNum, */ /* initialization */ -s32 httpsInit(size_t caCertNum,const httpsData *caList); +s32 httpsInit(u32 caCertNum,const httpsData *caList); s32 httpsEnd(void); /* SSL certificate */ -s32 httpsClientSetSslClientCertificate(httpClientId cid,const httpsData *cert,const httpsData *privKey); +s32 httpClientSetSslClientCertificate(httpClientId cid,const httpsData *cert,const httpsData *privKey); /* SSL callback */ -s32 httpsClientSetSslCallback(httpClientId cid,httpsSslCallback cb,void *arg); +s32 httpClientSetSslCallback(httpClientId cid,httpsSslCallback cb,void *arg); #ifdef __cplusplus diff --git a/ppu/include/http/util.h b/ppu/include/http/util.h index 922417fc..1f49ee94 100644 --- a/ppu/include/http/util.h +++ b/ppu/include/http/util.h @@ -73,32 +73,32 @@ typedef struct _http_header */ /* build */ -s32 httpUtilBuildRequestLine(const httpRequestLine *req,char *buf,size_t len,size_t *required); -s32 httpUtilBuildHeader(const httpHeader *header,char *buf,size_t len,size_t *required); -s32 httpUtilBuildUri(const httpUri *uri,char *buf,size_t len,size_t *required,int32_t flags); -s32 httpUtilSweepPath(char *dst,const char *src,size_t srcSize); +s32 httpUtilBuildRequestLine(const httpRequestLine *req,char *buf,u32 len,u32 *required); +s32 httpUtilBuildHeader(const httpHeader *header,char *buf,u32 len,u32 *required); +s32 httpUtilBuildUri(const httpUri *uri,char *buf,u32 len,u32 *required,int32_t flags); +s32 httpUtilSweepPath(char *dst,const char *src,u32 srcSize); /* encode */ -s32 httpUtilEscapeUri(char *out,size_t outSize,const unsigned char *in,size_t inSize,size_t *required); -s32 httpUtilUnescapeUri(unsigned char *out,size_t size,const char *in,size_t *required); -s32 httpUtilFormUrlEncode(char *out,size_t outSize,const unsigned char *in,size_t inSize,size_t *required); -s32 httpUtilFormUrlDecode(unsigned char *out,size_t size,const char *in,size_t *required); -s32 httpUtilBase64Encoder(char *out,const void *in,size_t len); -s32 httpUtilBase64Decoder(char *out,const void *in,size_t len); +s32 httpUtilEscapeUri(char *out,u32 outSize,const unsigned char *in,u32 inSize,u32 *required); +s32 httpUtilUnescapeUri(unsigned char *out,u32 size,const char *in,u32 *required); +s32 httpUtilFormUrlEncode(char *out,u32 outSize,const unsigned char *in,u32 inSize,u32 *required); +s32 httpUtilFormUrlDecode(unsigned char *out,u32 size,const char *in,u32 *required); +s32 httpUtilBase64Encoder(char *out,const void *in,u32 len); +s32 httpUtilBase64Decoder(char *out,const void *in,u32 len); /* copy */ -s32 httpUtilCopyUri(httpUri *dest,const httpUri *src,void *pool,size_t poolSize,size_t *required); -s32 httpUtilCopyHeader(httpHeader *dest,const httpHeader *src,void *pool,size_t poolSize,size_t *required); -s32 httpUtilCopyStatusLine(httpStatusLine *dest,const httpStatusLine *src,void *pool,size_t poolSize,size_t *required); -s32 httpUtilMergeUriPath(httpUri *uri,const httpUri *src,const char *path,void *pool,size_t poolSize,size_t *required); -s32 httpUtilAppendHeaderValue(httpHeader *dest,const httpHeader *src,const char *value,void *pool,size_t poolSize,size_t *required); +s32 httpUtilCopyUri(httpUri *dest,const httpUri *src,void *pool,u32 poolSize,u32 *required); +s32 httpUtilCopyHeader(httpHeader *dest,const httpHeader *src,void *pool,u32 poolSize,u32 *required); +s32 httpUtilCopyStatusLine(httpStatusLine *dest,const httpStatusLine *src,void *pool,u32 poolSize,u32 *required); +s32 httpUtilMergeUriPath(httpUri *uri,const httpUri *src,const char *path,void *pool,u32 poolSize,u32 *required); +s32 httpUtilAppendHeaderValue(httpHeader *dest,const httpHeader *src,const char *value,void *pool,u32 poolSize,u32 *required); /* parse */ -s32 httpUtilParseUri(httpUri *uri,const char *str,void *pool,size_t size,size_t *required); -s32 httpUtilParseUriPath(httpUriPath *path,const char *str,void *pool,size_t size,size_t *required); -s32 httpUtilParseProxy(httpUri *uri,const char *str,void *pool,size_t size,size_t *required); -s32 httpUtilParseStatusLine(httpStatusLine *resp,const char *str,size_t len,void *pool,size_t size,size_t *required,size_t *parsedLength); -s32 httpUtilParseHeader(httpHeader *header,const char *str,size_t len,void *pool,size_t size,size_t *required,size_t *parsedLength); +s32 httpUtilParseUri(httpUri *uri,const char *str,void *pool,u32 size,u32 *required); +s32 httpUtilParseUriPath(httpUriPath *path,const char *str,void *pool,u32 size,u32 *required); +s32 httpUtilParseProxy(httpUri *uri,const char *str,void *pool,u32 size,u32 *required); +s32 httpUtilParseStatusLine(httpStatusLine *resp,const char *str,u32 len,void *pool,u32 size,u32 *required,u32 *parsedLength); +s32 httpUtilParseHeader(httpHeader *header,const char *str,u32 len,void *pool,u32 size,u32 *required,u32 *parsedLength); #ifdef __cplusplus diff --git a/ppu/include/io/pad.h b/ppu/include/io/pad.h index 8deca0d1..61fabda6 100644 --- a/ppu/include/io/pad.h +++ b/ppu/include/io/pad.h @@ -17,6 +17,16 @@ #define PAD_TYPE_REMOTE (4) /*!< BD Remote Controller */ #define PAD_TYPE_LDD (5) /*!< Custom Controller */ +#define PAD_PRESS_MODE_ON (1) +#define PAD_PRESS_MODE_OFF (0) + +#define PAD_INFO_SUPPORTED_PRESS_MODE (1) + +#define PAD_SENSOR_MODE_ON (1) +#define PAD_SENSOR_MODE_OFF (0) + +#define PAD_INFO_SUPPORTED_SENSOR_MODE (1) + #ifdef __cplusplus extern "C" { #endif diff --git a/ppu/include/jpgdec/jpgdec.h b/ppu/include/jpgdec/jpgdec.h index 8a5d189e..04d1a40f 100644 --- a/ppu/include/jpgdec/jpgdec.h +++ b/ppu/include/jpgdec/jpgdec.h @@ -3,25 +3,44 @@ #include -#define JPGDEC_DISABLE 0 -#define JPGDEC_ENABLE 1 - -#define JPGDEC_TOP_TO_BOTTOM 0 -#define JPGDEC_BOTTOM_TO_TOP 1 - -#define JPGDEC_HIGH_QUALITY 0 -#define JPGDEC_LOW_QUALITY 5 +#define JPGDEC_ERROR_OK 0 +#define JPGDEC_ERROR_HEADER 0x80611101 +#define JPGDEC_ERROR_STREAM_FORMAT 0x80611102 +#define JPGDEC_ERROR_ARG 0x80611103 +#define JPGDEC_ERROR_SEQ 0x80611104 +#define JPGDEC_ERROR_BUSY 0x80611105 +#define JPGDEC_ERROR_FATAL 0x80611106 +#define JPGDEC_ERROR_OPEN_FILE 0x80611107 +#define JPGDEC_ERROR_SPU_UNSUPPORT 0x80611108 +#define JPGDEC_ERROR_CB_PARAM 0x80611109 #ifdef __cplusplus extern "C" { #endif +typedef struct _jpgdec_strm_info jpgDecStrmInfo; +typedef struct _jpgdec_strm_param jpgDecStrmParam; +typedef struct _jpgdec_disp_info jpgDecDispInfo; +typedef struct _jpgdec_disp_param jpgDecDispParam; + +typedef void* (*jpgCbCtrlMalloc)(u32 size,void *cbCtrlArg); +typedef void (*jpgCbCtrlFree)(void *ptr,void *cbCtrlArg); + +typedef s32 (*jpgCbCtrlStrm)(jpgDecStrmInfo *strmInfo,jpgDecStrmParam *strmParam,void *cbCtrlArg); +typedef s32 (*jpgCbCtrlDisp)(jpgDecDispInfo *dispInfo,jpgDecDispParam *dispParam,void *cbDispArg); + typedef enum { JPGDEC_FILE = 0, JPGDEC_BUFFER = 1 } jpgStreamSel; +typedef enum +{ + JPGDEC_SPU_THREAD_DISABLE = 0, + JPGDEC_SPU_THREAD_ENABLE = 1 +} jpgSpuThreadEna; + typedef enum { JPGDEC_GRAYSCALE = 1, @@ -32,15 +51,51 @@ typedef enum JPGDEC_ARGB = 20, } jpgColorSpace; +typedef enum +{ + JPGDEC_STATUS_FINISH = 0, + JPGDEC_STATUS_STOP = 1 +} jpgDecodeStatus; + +typedef enum +{ + JPGDEC_CONTINUE = 0, + JPGDEC_STOP = 1 +} jpgCommand; + +typedef enum +{ + JPGDEC_QUALITY = 0, + JPGDEC_FAST = 5 +} jpgMethod; + +typedef enum +{ + JPGDEC_TOP_TO_BOTTOM = 0, + JPGDEC_BOTTOM_TO_TOP = 1 +} jpgOutputMode; + +typedef enum +{ + JPGDEC_MCU_MODE = 0, + JPGDEC_LINE_MODE = 1 +} jpgBufferMode; + +typedef enum +{ + JPGDEC_RECEIVE_EVENT = 0, + JPGDEC_TRYRECEIVE_EVENT = 1 +} jpgSpuMode; + typedef struct _jpgdec_thread_in_param { - s32 enable; + u32 spu_enable; u32 ppu_prio; u32 spu_prio; - u32 malloc_func; - u32 malloc_arg; - u32 free_func; - u32 free_arg; + jpgCbCtrlMalloc malloc_func ATTRIBUTE_PRXPTR; + void *malloc_arg ATTRIBUTE_PRXPTR; + jpgCbCtrlFree free_func ATTRIBUTE_PRXPTR; + void *free_arg ATTRIBUTE_PRXPTR; } jpgDecThreadInParam; typedef struct _jpgdec_thread_out_param @@ -50,13 +105,13 @@ typedef struct _jpgdec_thread_out_param typedef struct _jpgdec_src { - jpgStreamSel stream; - u32 file_name; + u32 stream_sel; + const char *file_name ATTRIBUTE_PRXPTR; s64 file_offset; u32 file_size; - u32 stream_ptr; + void *stream_ptr ATTRIBUTE_PRXPTR; u32 stream_size; - s32 enable; + u32 spu_enable; } jpgDecSource; typedef struct _jpgdec_info @@ -64,23 +119,28 @@ typedef struct _jpgdec_info u32 width; u32 height; u32 num_comp; - jpgColorSpace space; + u32 color_space; } jpgDecInfo; typedef struct _jpgdec_data_info { f32 value; u32 output_lines; - s32 status; + u32 decode_status; } jpgDecDataInfo; +typedef struct _jpgdec_opn_info +{ + u32 init_space_allocated; +} jpgDecOpnInfo; + typedef struct _jpgdec_in_param { - u32 cmd_ptr; + vu32 *cmd_ptr ATTRIBUTE_PRXPTR; u32 down_scale; - s32 quality; - s32 mode; - jpgColorSpace space; + u32 quality_mode; + u32 output_mode; + u32 color_space; u8 alpha; u8 pad[3]; } jpgDecInParam; @@ -91,12 +151,79 @@ typedef struct _jpgdec_out_param u32 width; u32 height; u32 num_comp; - s32 mode; - jpgColorSpace space; + u32 output_mode; + u32 color_space; u32 down_scale; u32 use_memory_space; } jpgDecOutParam; +typedef struct _jpgdec_datactrl_param +{ + u64 output_bytes_per_line; +} jpgDecDataCtrlParam; + +typedef struct _jpgdec_ctrl_strm +{ + jpgCbCtrlStrm strm_func ATTRIBUTE_PRXPTR; + void *strm_arg ATTRIBUTE_PRXPTR; +} jpgDecCtrlStrm; + +typedef struct _jpgdec_ext_info +{ + u64 coeff_buffer_size; + u32 mcu_width; +} jpgDecExtInfo; + +typedef struct _jpgdec_extin_param +{ + void *coeff_buffer ATTRIBUTE_PRXPTR; + u32 buffer_mode; + u32 output_counts; + u32 spu_mode; +} jpgDecExtInParam; + +typedef struct _jpgdec_extout_param +{ + u64 output_width_byte; + u32 output_height; + u32 one_mcu_width; + u32 one_mcu_height; +} jpgDecExtOutParam; + +typedef struct _jpgdec_ctrl_disp +{ + jpgCbCtrlDisp disp_func ATTRIBUTE_PRXPTR; + void *disp_arg ATTRIBUTE_PRXPTR; +} jpgDecCtrlDisp; + +struct _jpgdec_strm_info +{ + u32 decoded_strm_size; +}; + +struct _jpgdec_strm_param +{ + void *strm_ptr ATTRIBUTE_PRXPTR; + u32 strm_size; +}; + +struct _jpgdec_disp_info +{ + u64 output_frame_width_byte; + u32 output_frame_height; + u64 output_start_xbyte; + u32 output_start_y; + u64 output_width_byte; + u32 output_height; + u32 output_components; + void *output_image ATTRIBUTE_PRXPTR; +}; + +struct _jpgdec_disp_param +{ + void *next_output_image ATTRIBUTE_PRXPTR; +}; + typedef struct _jpg_data { void *bmp_out; @@ -107,13 +234,18 @@ typedef struct _jpg_data } jpgData; s32 jpgDecCreate(s32 *handle,jpgDecThreadInParam *in,jpgDecThreadOutParam *out); -s32 jpgDecOpen(s32 handle,s32 *subhandle,const jpgDecSource *src,u32 *space_allocated); +s32 jpgDecOpen(s32 handle,s32 *subhandle,const jpgDecSource *src,jpgDecOpnInfo *openInfo); s32 jpgDecReadHeader(s32 handle,s32 subhandle,jpgDecInfo *info); s32 jpgDecSetParameter(s32 handle,s32 subhandle,const jpgDecInParam *in,jpgDecOutParam *out); -s32 jpgDecDecodeData(s32 handle,s32 subhandle,u8 *data,const u64 *bytes_per_line,jpgDecDataInfo *info); +s32 jpgDecDecodeData(s32 handle,s32 subhandle,u8 *data,const jpgDecDataCtrlParam *dataCtrlParam,jpgDecDataInfo *info); s32 jpgDecClose(s32 handle,s32 subhandle); s32 jpgDecDestroy(s32 handle); +s32 jpgDecExtOpen(s32 handle,s32 *subhandle,const jpgDecSource *src,jpgDecOpnInfo *openInfo,const jpgDecCtrlStrm *cbCtrlStrm); +s32 jpgDecExtReadHeader(s32 handle,s32 subhandle,jpgDecInfo *info,jpgDecExtInfo *extInfo); +s32 jpgDecExtSetParameter(s32 handle,s32 subhandle,const jpgDecInParam *inParam,jpgDecOutParam *outParam,const jpgDecExtInParam *extInParam,jpgDecExtOutParam *extOutParam); +s32 jpgDecExtDecodeData(s32 handle,s32 subhandle,u8 *data,const jpgDecDataCtrlParam *dataCtrlParam,jpgDecDataInfo *info,const jpgDecCtrlDisp *cbCtrlDisp,jpgDecDispParam *dispParam); + s32 jpgLoadFromFile(const char *filename,jpgData *out); s32 jpgLoadFromBuffer(const void *buffer,u32 size,jpgData *out); diff --git a/ppu/include/lv2/spu.h b/ppu/include/lv2/spu.h index 04357a63..2a3e1515 100644 --- a/ppu/include/lv2/spu.h +++ b/ppu/include/lv2/spu.h @@ -145,7 +145,7 @@ s32 sysSpuPrintfAttachThread(sys_spu_thread_t thread); \return zero if no error occured, nonzero otherwise. */ -s32 sysSpuPrintfDetach_Tread(sys_spu_thread_t thread); +s32 sysSpuPrintfDetachThread(sys_spu_thread_t thread); /*! \brief Terminate Spu printf service \param none @@ -154,6 +154,8 @@ s32 sysSpuPrintfDetach_Tread(sys_spu_thread_t thread); */ s32 sysSpuPrintfFinalize(); +s32 sysSpuImageOpenELF(sysSpuImage* image, const char* path); + #ifdef __cplusplus } #endif diff --git a/ppu/include/pngdec/pngdec.h b/ppu/include/pngdec/pngdec.h index 7db0cd7e..6d238086 100644 --- a/ppu/include/pngdec/pngdec.h +++ b/ppu/include/pngdec/pngdec.h @@ -3,16 +3,40 @@ #include -#define PNGDEC_DISABLE 0 -#define PNGDEC_ENABLE 1 - -#define PNGDEC_TOP_TO_BOTTOM 0 -#define PNGDEC_BOTTOM_TO_TOP 1 +#define PNGDEC_ERROR_OK 0 +#define PNGDEC_ERROR_HEADER 0x80611201 +#define PNGDEC_ERROR_STREAM_FORMAT 0x80611202 +#define PNGDEC_ERROR_ARG 0x80611203 +#define PNGDEC_ERROR_SEQ 0x80611204 +#define PNGDEC_ERROR_BUSY 0x80611205 +#define PNGDEC_ERROR_FATAL 0x80611206 +#define PNGDEC_ERROR_OPEN_FILE 0x80611207 +#define PNGDEC_ERROR_SPU_UNSUPPORT 0x80611208 +#define PNGDEC_ERROR_SPU_ERROR 0x80611209 +#define PNGDEC_ERROR_CB_PARAM 0x8061120a #ifdef __cplusplus extern "C" { #endif +typedef struct _pngdec_stream_info pngDecStreamInfo; +typedef struct _pngdec_stream_param pngDecStreamParam; +typedef struct _pngdec_disp_info pngDecDispInfo; +typedef struct _pngdec_disp_param pngDecDispParam; + +typedef void* (*pngCbCtrlMalloc)(u32 size,void *cbCtrlArg); +typedef void (*pngCbCtrlFree)(void *ptr,void *cbCtrlArg); + +typedef s32 (*pngCbCtrlStrm)(pngDecStreamInfo *strmInfo,pngDecStreamParam *strmParam,void *cbStrmArg); + +typedef s32 (*pngCbCtrlDisp)(pngDecDispInfo *dispInfo,pngDecDispParam *dispParam,void *cbDispArg); + +typedef enum +{ + PNGDEC_SPU_THREAD_DISABLE = 0, + PNGDEC_SPU_THREAD_ENABLE = 1 +} pngSpuThreadEna; + typedef enum { PNGDEC_FILE = 0, @@ -29,15 +53,62 @@ typedef enum PNGDEC_ARGB = 20 } pngColorSpace; +typedef enum +{ + PNGDEC_NO_INTERLACE = 0, + PNGDEC_ADAM7_INTERLACE = 1 +} pngInterlaceMode; + +typedef enum +{ + PNGDEC_STATUS_FINISH = 0, + PNGDEC_STATUS_STOP = 1 +} pngDecodeStatus; + +typedef enum +{ + PNGDEC_CONTINUE = 0, + PNGDEC_STOP = 1 +} pngCommand; + +typedef enum +{ + PNGDEC_TOP_TO_BOTTOM = 0, + PNGDEC_BOTTOM_TO_TOP = 1 +} pngOutputMode; + +typedef enum +{ + PNGDEC_1BYTE_PER_NPIXEL = 0, + PNGDEC_1BYTE_PER_1PIXEL = 1 +} pngPackFlag; + +typedef enum +{ + PNGDEC_STREAM_ALPHA = 0, + PNGDEC_FIX_ALPHA = 1 +} pngAlphaSelect; + +typedef enum +{ + PNGDEC_LINE_MODE = 1 /*! \brief LINE mode.
Decode the number of lines specified with output_counts at one time. */ +} pngBufferMode; + +typedef enum +{ + PNGDEC_RECEIVE_EVENT = 0, /*! \brief Decoder uses \ref spursQueuePopBegin to wait for termination of Disp callback function.
Transistion to WAITING state and may be affected by the behavior of other SPU threads. */ + PNGDEC_TRYRECEIVE_EVENT = 1 /*! \brief Decoder uses \ref spursQueueTryPopBegin to wait for termination of Disp callback function.
Since there is no state transistion, it is not affected by the behavior of other SPU threads. */ +} pngSpuMode; + typedef struct _pngdec_thread_in_param { - s32 enable; + u32 spu_enable; u32 ppu_prio; u32 spu_prio; - u32 malloc_func; - u32 malloc_arg; - u32 free_func; - u32 free_arg; + pngCbCtrlMalloc malloc_func ATTRIBUTE_PRXPTR; + void *malloc_arg ATTRIBUTE_PRXPTR; + pngCbCtrlFree free_func ATTRIBUTE_PRXPTR; + void *free_arg ATTRIBUTE_PRXPTR; } pngDecThreadInParam; typedef struct _pngdec_thread_out_param @@ -47,13 +118,17 @@ typedef struct _pngdec_thread_out_param typedef struct _pngdec_src { - pngStreamSel stream; - u32 file_name; + /*! \brief Input stream selection. Possible values: + - \ref PNGDEC_FILE + - \ref PNGDEC_BUFFER + */ + u32 stream_sel; + const char *file_name ATTRIBUTE_PRXPTR; s64 file_offset; u32 file_size; - u32 stream_ptr; + void *stream_ptr ATTRIBUTE_PRXPTR; u32 stream_size; - s32 enable; + u32 spu_enable; } pngDecSource; typedef struct _pngdec_info @@ -61,9 +136,9 @@ typedef struct _pngdec_info u32 width; u32 height; u32 num_comp; - pngColorSpace space; + u32 color_space; u32 bit_depth; - s32 interlaced; + u32 interlace_mode; u32 chunk_info; } pngDecInfo; @@ -72,17 +147,17 @@ typedef struct _pngdec_data_info u32 chunk_info; u32 num_text; u32 num_unk_chunk; - s32 status; + u32 decode_status; } pngDecDataInfo; typedef struct _pngdec_in_param { - u32 cmd_ptr; - s32 mode; - pngColorSpace space; + vu32 *cmd_ptr ATTRIBUTE_PRXPTR; + u32 output_mode; + u32 color_space; u32 bit_depth; - s32 pack_flag; - s32 alpha_select; + u32 pack_flag; + u32 alpha_select; u32 alpha; } pngDecInParam; @@ -93,11 +168,90 @@ typedef struct _pngdec_out_param u32 height; u32 num_comp; u32 bit_depth; - s32 mode; - pngColorSpace space; + u32 output_mode; + u32 color_space; u32 use_memory_space; } pngDecOutParam; +typedef struct _pngdec_datactrl_param +{ + u64 output_bytes_per_line; +} pngDecDataCtrlParam; + +typedef struct _pngdec_opn_info +{ + u32 init_space_allocated; +} pngDecOpnInfo; + +typedef struct _pngdec_opn_param +{ + u32 select_chunk; +} pngDecOpnParam; + +typedef struct _pngdec_ctrl_strm +{ + pngCbCtrlStrm stream_func ATTRIBUTE_PRXPTR; + void *stream_arg ATTRIBUTE_PRXPTR; +} pngDecCtrlStrm; + +typedef struct _pngdec_ext_info +{ + u64 reserved; +} pngDecExtInfo; + +typedef struct _pngdec_extin_param +{ + /*! \brief Mode of output of partial images. Possible values: + - \ref PNGDEC_LINE_MODE + */ + u32 buffer_mode; + u32 output_counts; + u32 spu_mode; +} pngDecExtInParam; + +typedef struct _pngdec_extout_param +{ + u64 output_width_bytes; + u32 output_height; +} pngDecExtOutParam; + +typedef struct _pngdec_ctrl_disp +{ + pngCbCtrlDisp disp_func ATTRIBUTE_PRXPTR; + void *disp_arg ATTRIBUTE_PRXPTR; +} pngDecCtrlDisp; + +struct _pngdec_stream_info +{ + u32 decoded_stream_size; +}; + +struct _pngdec_stream_param +{ + void *strm_ptr ATTRIBUTE_PRXPTR; + u32 strm_size; +}; + +struct _pngdec_disp_param +{ + void *next_output_image ATTRIBUTE_PRXPTR; +}; + +struct _pngdec_disp_info +{ + u64 output_frame_width_bytes; + u32 output_frame_height; + u64 output_start_xbyte; + u32 output_start_y; + u64 output_width_byte; + u32 output_height; + u32 output_bit_depth; + u32 output_components; + u32 next_output_start_y; + u32 scan_pass_count; + void *output_image ATTRIBUTE_PRXPTR; +}; + typedef struct _png_data { void *bmp_out; @@ -108,13 +262,18 @@ typedef struct _png_data } pngData; s32 pngDecCreate(s32 *handle,pngDecThreadInParam *in,pngDecThreadOutParam *out); -s32 pngDecOpen(s32 handle,s32 *subhandle,const pngDecSource *src,u32 *space_allocated); +s32 pngDecOpen(s32 handle,s32 *subhandle,const pngDecSource *src,pngDecOpnInfo *open_info); s32 pngDecReadHeader(s32 handle,s32 subhandle,pngDecInfo *info); s32 pngDecSetParameter(s32 handle,s32 subhandle,const pngDecInParam *in,pngDecOutParam *out); -s32 pngDecDecodeData(s32 handle,s32 subhandle,u8 *data,const u64 *bytes_per_line,pngDecDataInfo *info); +s32 pngDecDecodeData(s32 handle,s32 subhandle,u8 *data,const pngDecDataCtrlParam *dataCtrlParam,pngDecDataInfo *info); s32 pngDecClose(s32 handle,s32 subhandle); s32 pngDecDestroy(s32 handle); +s32 pngDecExtOpen(s32 handle,s32 *subhandle,const pngDecSource *src,pngDecOpnInfo *open_info,const pngDecCtrlStrm *cbCtrlStrm,const pngDecOpnParam *opnParam); +s32 pngDecExtReadHeader(s32 handle,s32 subhandle,pngDecInfo *info,pngDecExtInfo *extInfo); +s32 pngDecExtSetParameter(s32 handle,s32 subhandle,const pngDecInParam *inParam,pngDecOutParam *outParam,const pngDecExtInParam *extInParam,pngDecExtOutParam *extOutParam); +s32 pngDecExtDecodeData(s32 handle,s32 subhandle,u8 *data,const pngDecDataCtrlParam *dataCtrlParam,pngDecDataInfo *dataOutInfo,const pngDecCtrlDisp *cbCtrlDisp,pngDecDispParam *dispParam); + s32 pngLoadFromFile(const char *filename,pngData *out); s32 pngLoadFromBuffer(const void *buffer,u32 size,pngData *out); diff --git a/ppu/include/ppu-asm.h b/ppu/include/ppu-asm.h index 1eea0c6a..eb34a1e0 100644 --- a/ppu/include/ppu-asm.h +++ b/ppu/include/ppu-asm.h @@ -5,7 +5,7 @@ #define PPU_ALIGNMENT 8 -#define __get_opd32(opd64) ((unsigned long long)((opd64) + 16)) +#define __get_opd32(opd64) ((unsigned long long)((intptr_t)(opd64) ? (((intptr_t)(opd64)) + 16) : 0L)) #define __get_addr32(addr) (unsigned int)((unsigned long long)(addr)) @@ -52,4 +52,30 @@ asm volatile("1: mftb %[current_tb]; cmpwi 7,%[current_tb],0; beq- 7,1b" : [current_tb] "=r"(tb) : : "cr7"); \ tb;}) +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +static inline unsigned short bswap16(unsigned short val) +{ + unsigned short tmp = val; + return __lhbrx(&tmp); +} + +static inline unsigned int bswap32(unsigned int val) +{ + unsigned int tmp = val; + return __lwbrx(&tmp); +} + +static inline unsigned long long bswap64(unsigned long long val) +{ + unsigned long long tmp = val; + return __ldbrx(&tmp); +} + +#ifdef __cplusplus + } +#endif /* __cplusplus */ + #endif diff --git a/ppu/include/rsx/commands.h b/ppu/include/rsx/commands.h index 2e1a29e1..84e0e3a1 100644 --- a/ppu/include/rsx/commands.h +++ b/ppu/include/rsx/commands.h @@ -14,590 +14,25 @@ These are functions to enqueue commands into the RSX's command buffer. extern "C" { #endif -/*! \brief Set drawing direction of front face. -\param context Pointer to the context object. -\param dir Drawing direction of front face. Possible values are: -- \ref GCM_FRONTFACE_CW -- \ref GCM_FRONTFACE_CCW -*/ -void rsxSetFrontFace(gcmContextData *context,u32 dir); - -/*! \brief Set culling mode. -\param context Pointer to context object. -\param cull Type of cull mode. Possible values are: -- \ref GCM_CULL_FRONT -- \ref GCM_CULL_BACK -- \ref GCM_CULL_ALL -*/ -void rsxSetCullFace(gcmContextData *context,u32 cull); - -/*! \brief Enable/Disable face culling. -\param context Pointer to the context object. -\param enable Enable flag. Possible values are: - - \ref GCM_TRUE - - \ref GCM_FALSE - */ -void rsxSetCullFaceEnable(gcmContextData *context,u32 enable); - -/*! \brief Enable/Disable write to depth buffer. -\param context Pointer to the context object. -\param enable Enable flag. Possible values are: -- \ref GCM_TRUE -- \ref GCM_FALSE -*/ -void rsxSetDepthWriteEnable(gcmContextData *context,u32 enable); - -/*! \brief Stop the render sequence. - -Stops the rendering for a primitive, started by \ref rsxDrawVertexBegin. -\param context Pointer to the context object. -*/ -void rsxDrawVertexEnd(gcmContextData *context); - -/*! \brief Set the shading model for the render sequence. -\param context Pointer to the context object. -\param shadeModel Type of shading model. Possible values are: -- \ref GCM_SHADE_MODEL_FLAT -- \ref GCM_SHADE_MODEL_SMOOTH -*/ -void rsxSetShadeModel(gcmContextData *context,u32 shadeModel); - -/*! \brief Start the render sequence. - -Starts the rendering for a primitive. -\param context Pointer to the context object. -\param type Type of primitive to render. Possible values are: -- \ref GCM_TYPE_POINTS -- \ref GCM_TYPE_LINES -- \ref GCM_TYPE_LINE_LOOP -- \ref GCM_TYPE_LINE_STRIP -- \ref GCM_TYPE_TRIANGLES -- \ref GCM_TYPE_TRIANGLE_STRIP -- \ref GCM_TYPE_TRIANGLE_FAN -- \ref GCM_TYPE_QUADS -- \ref GCM_TYPE_QUAD_STRIP -- \ref GCM_TYPE_POLYGON -*/ -void rsxDrawVertexBegin(gcmContextData *context,u32 type); - -void rsxDrawVertex2f(gcmContextData *context,u8 idx,f32 x,f32 y); -void rsxDrawVertex3f(gcmContextData *context,u8 idx,f32 x,f32 y,f32 z); -void rsxDrawVertex4f(gcmContextData *context,u8 idx,f32 x,f32 y,f32 z,f32 w); -void rsxSetScissor(gcmContextData *context,u16 x,u16 y,u16 w,u16 h); - -/*! \brief Specify the value used for depth buffer comparisons. -\param context Pointer to the context object. -\param func Specifies the depth comparison function. Possible values are: - - \ref GCM_NEVER - - \ref GCM_LESS - - \ref GCM_EQUAL - - \ref GCM_LEQUAL - - \ref GCM_GREATER - - \ref GCM_NOTEQUAL - - \ref GCM_GEQUAL - - \ref GCM_ALWAYS -*/ -void rsxSetDepthFunc(gcmContextData *context,u32 func); - -/*! \brief Enable or disable the depth test. - -If depth test is enabled, the GPU performs depth comparisons and updates the -depth buffer. -Note that even if the depth buffer exists and the depth mask is non-zero, -the depth buffer is not updated if the depth test is disabled. -\param context Pointer to the context object. -\param enable Enable flag. Possible values are: - - \ref GCM_TRUE - - \ref GCM_FALSE -*/ -void rsxSetDepthTestEnable(gcmContextData *context,u32 enable); - -/*! \brief Clear the render surface. - -This function clears the chosen selection of color components, depth and stencil -values for all pixels in the destination surface. The clear color can be chosen -using \ref rsxSetClearColor, and the clear value for the depth buffer is set -using \ref rsxSetClearDepthValue. - -\param context Pointer to the context object. -\param clear_mask A selection of components to be cleared. Must be an OR -combination of the following values: - - \ref GCM_CLEAR_Z - - \ref GCM_CLEAR_S - - \ref GCM_CLEAR_R - - \ref GCM_CLEAR_G - - \ref GCM_CLEAR_B - - \ref GCM_CLEAR_A -The value of \ref GCM_CLEAR_M can also be chosen, to clear all RGBA components, -depth and stencil buffers. -*/ -void rsxClearSurface(gcmContextData *context,u32 clear_mask); - -/*! \brief Set the clear depth value. - -This value is used by the \ref rsxClearSurface function. -\param context Pointer to the context object. -\param value Color value -*/ -void rsxSetClearDepthValue(gcmContextData *context,u32 value); -void rsxSetReturnCommand(gcmContextData *context); -void rsxSetCallCommand(gcmContextData *context,u32 offset); -void rsxSetJumpCommand(gcmContextData *context,u32 offset); -void rsxSetNopCommand(gcmContextData *context,u32 count); - -/*! \brief Set the clear color. - -The clear color value is used by the \ref rsxClearSurface function. -\param context Pointer to the context object. -\param color The clear color value. -*/ -void rsxSetClearColor(gcmContextData *context,u32 color); - -/*! \brief Enable or disable write access to the framebuffer color components. -\param context Pointer to the context object. -\param mask A selection of the components to enable write access. It is an OR -combination of the following values: - - \ref GCM_COLOR_MASK_B - - \ref GCM_COLOR_MASK_G - - \ref GCM_COLOR_MASK_R - - \ref GCM_COLOR_MASK_A -*/ -void rsxSetColorMask(gcmContextData *context,u32 mask); - -/*! \brief Enable or disable write access to the framebuffer color components -(Multiple Render Target output). -\param context Pointer to the context object. -\param mask A selection of the components to enable write access. It is an OR -combination of the following values: - - \ref GCM_COLOR_MASK_B - - \ref GCM_COLOR_MASK_G - - \ref GCM_COLOR_MASK_R - - \ref GCM_COLOR_MASK_A -*/ -void rsxSetColorMaskMRT(gcmContextData *context,u32 mask); - -/*! \brief Setup the render surface. - -This function is used to setup the render target where RSX should render the frame into. -\param context Pointer to the context object. -\param surface Pointer to the surface object. -*/ -void rsxSetSurface(gcmContextData *context,gcmSurface *surface); -void rsxSetReferenceCommand(gcmContextData *context,u32 ref_value); - -/*! \brief Enqueues a Wait for label command. -\param context Pointer to the context object. -\param index Label index -\param valuie Label value -*/ -void rsxSetWaitLabel(gcmContextData *context,u8 index,u32 value); - -/*! \brief Enqueues a Write Command label command. -\param context Pointer to the context object. -\param index Label index -\param value Label value -*/ -void rsxSetWriteCommandLabel(gcmContextData *context,u8 index,u32 value); - -/*! \brief Enqueues a Write Backend label command. -\param context Pointer to the context object. -\param index Label index -\param value Label value -*/ -void rsxSetWriteBackendLabel(gcmContextData *context,u8 index,u32 value); - -void rsxSetViewportClip(gcmContextData *context,u8 sel,u16 width,u16 height); - -/*! \brief Set viewport. - -This function sets the viewport.
-The origin (0,0) of the normalized device coordinate points to the center of the screen.
-Performing viewport conversion, where the upper left corner is the origin is as follows: -\code - x = X; - y = Y; - width = WIDTH; - height = HEIGHT; - min = 0.0f; - max = 1.0f; - scale[0] = width * 0.5f; - scale[1] = height * 0.5f; - scale[2] = (max - min) * 0.5f; - offset[0] = x + width * 0.5f; - offset[1] = y + height * 0.5f; - offset[2] = (max + min) * 0.5f; -\endcode -

-Performing viewport conversion, where the lower left corner is the origin is as follows (this is equivalent to glViewport): -\code - x = X; - y = WINDOW_HEIGHT - Y - HEIGHT; - width = WIDTH; - height = HEIGHT; - min = 0.0f; - max = 1.0f; - scale[0] = width * 0.5f; - scale[1] = height * -0.5f; - scale[2] = (max - min) * 0.5f; - offset[0] = x + width * 0.5f; - offset[1] = y + height * 0.5f; - offset[2] = (max + min) * 0.5f; -\endcode -\param context Pointer to the context object. -\param x Origin of the viewport rectangle in pixels (0 - 4095). Initial value is (0,0). -\param y Origin of the viewport rectangle in pixels (0 - 4095). Initial value is (0,0). -\param width Width of the viewport (0 - 4096). Initial value is 4096. -\param height Height of the viewport (0 - 4096). Initial value is 4096. -\param min Minimum Z clip value. Initial value is 0.0. -\param max Maximum Z clip value. Initial value is 1.0. -\param scale Scale values to be used for viewport conversion. Initial values are (2048.0,2048.0,0.5,0.0). -\param offset Offset values to be used for viewport conversion. Initial values are (2048.0,2048.0,0.5,0.0). -*/ -void rsxSetViewport(gcmContextData *context,u16 x,u16 y,u16 width,u16 height,f32 min,f32 max,const f32 scale[4],const f32 offset[4]); - -/*! \brief Invalidates a texture cache. -\param context Pointer to the context object. -\param type Type of texture cache to be invalidated. Possible values are: - - \ref GCM_INVALIDATE_TEXTURE - - \ref GCM_INVALIDATE_VERTEX_TEXTURE -*/ -void rsxInvalidateTextureCache(gcmContextData *context,u32 type); - -/*! \brief Loads a texture. -\param context Pointer to the context object. -\param index Texture index. -\param texture Pointer to the texture data. -*/ -void rsxLoadTexture(gcmContextData *context,u8 index,const gcmTexture *texture); - -/*! \brief Set texture control parameters. -\param context Pointer to the context object. -\param index Texture index. -\param enable Enable flag. Possible values are: - - \ref GCM_TRUE - - \ref GCM_FALSE -\param minlod minimum level of detail. -\param maxlod maximum level of detail. -\param maxaniso sample level of the anisotropic filter. Possible values are: - - \ref GCM_TEXTURE_MAX_ANISO_1 - - \ref GCM_TEXTURE_MAX_ANISO_2 - - \ref GCM_TEXTURE_MAX_ANISO_4 - - \ref GCM_TEXTURE_MAX_ANISO_6 - - \ref GCM_TEXTURE_MAX_ANISO_8 - - \ref GCM_TEXTURE_MAX_ANISO_10 - - \ref GCM_TEXTURE_MAX_ANISO_12 - - \ref GCM_TEXTURE_MAX_ANISO_16 -\todo finish args documentation. -*/ -void rsxTextureControl(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod,u8 maxaniso); -void rsxTextureFilter(gcmContextData *context,u8 index,u8 min,u8 mag,u8 conv); -void rsxTextureWrapMode(gcmContextData *context,u8 index,u8 wraps,u8 wrapt,u8 wrapr,u8 unsignedRemap,u8 zfunc,u8 gamma); - -/*! \brief Load a compiled vertex shader program. -\param context Pointer to the context object -\param program Pointer to the vertex program configuration -\param ucode Pointer to the shader micro code -*/ -void rsxLoadVertexProgram(gcmContextData *context,rsxVertexProgram *program,const void *ucode); - -/*! \brief Load a compiled fragment shader program. -\param context Pointer to the context object -\param program Pointer to the fragment program configuration -\param offset Memory offset of fragment program -\param location Memory location type where the program relies. Possible values are: -- \ref GCM_LOCATION_RSX -- \ref GCM_LOCATION_CELL -*/ -void rsxLoadFragmentProgramLocation(gcmContextData *context,rsxFragmentProgram *program,u32 offset,u32 location); -void rsxZControl(gcmContextData *context,u8 cullNearFar,u8 zClampEnable,u8 cullIgnoreW); -void rsxLoadVertexProgramBlock(gcmContextData *context,rsxVertexProgram *program,const void *ucode); -void rsxLoadVertexProgramParameterBlock(gcmContextData *context,u32 base_const,u32 const_cnt,const f32 *value); -void rsxSetVertexProgramParameter(gcmContextData *context,rsxVertexProgram *program,s32 index,const f32 *value); -void rsxSetFragmentProgramParameter(gcmContextData *context,rsxFragmentProgram *program,s32 index,const f32 *value,u32 offset); -void rsxDrawVertexArray(gcmContextData *context,u32 type,u32 start,u32 count); -void rsxBindVertexArrayAttrib(gcmContextData *context,u8 attr,u32 offset,u8 stride,u8 elems,u8 dtype,u8 location); -void rsxDrawIndexArray(gcmContextData *context,u32 type,u32 offset,u32 count,u32 data_type,u32 location); -void rsxInlineTransfer(gcmContextData *context,const u32 dstOffset,const void *srcAddress,const u32 sizeInWords,const u8 location); -void rsxSetUserClipPlaneControl(gcmContextData *context,u32 plane0,u32 plane1,u32 plane2,u32 plane3,u32 plane4,u32 plane5); - -/*! \brief Specify pixel arithmetic. - -In RGBA mode, pixels can be drawn using a function that blends the incoming -(source) RGBA values with the RGBA values that are already in the frame buffer -(the destination values). Blending is initially disabled. -Use \ref rsxSetBlendEnable to enable and disable blending. - -\c rsxSetBlendFunc defines the operation of blending when it is enabled. -\p sfcolor and and \p sfalpha specify which method is used to scale the source -color and alpha components. -\p dfcolor and and \p dfalpha specify which method is used to scale the -destination color and alpha components. -The possible methods are described in the following table. -Each method defines four scale factors, one each for red, green, blue, and -alpha. -In the table and in subsequent equations, source and destination color -components are referred to as Rs, Gs, Bs, -As and Rd, Gd, Bd, Ad, -respectively. -The color specified by \ref rsxSetBlendColor is referred to as -Rc, Gc, Bc, Ac. -They are understood to have integer values between 0 and -kR, kG, kB, kA, where - -kc = 2mc - 1 - -and mR, mG, mB, mA is the number of -red, green, blue, and alpha bitplanes. - -Source and destination scale factors are referred to as -sR, sG, sB, sA and dR, -dG, dB, dA. -The scale factors described in the table, denoted fR, fG, -fB, fA, represent either source or destination -factors. All scale factors have range [0,1]. - - - - - - - - - - - - - - - - - - -
Parameter fR fG fB fA
\ref GCM_ZERO 0 0 0 0
\ref GCM_ONE 1 1 1 1
\ref GCM_SRC_COLOR Rs/kR Gs/kG Bs/kB As/kA
\ref GCM_ONE_MINUS_SRC_COLOR 1-Rs/kR1-Gs/kG1-Bs/kB1-As/kA
\ref GCM_DST_COLOR Rd/kR Gd/kG Bd/kB Ad/kA
\ref GCM_ONE_MINUS_DST_COLOR 1-Rd/kR1-Gd/kG1-Bd/kB1-Ad/kA
\ref GCM_SRC_ALPHA As/kA As/kA As/kA As/kA
\ref GCM_ONE_MINUS_SRC_ALPHA 1-As/kA1-As/kA1-As/kA1-As/kA
\ref GCM_DST_ALPHA Ad/kA Ad/kA Ad/kA Ad/kA
\ref GCM_ONE_MINUS_DST_ALPHA 1-Ad/kA1-Ad/kA1-Ad/kA1-Ad/kA
\ref GCM_CONSTANT_COLOR Rc Gc Bc Ac
\ref GCM_ONE_MINUS_CONSTANT_COLOR1-Rc 1-Gc 1-Bc 1-Ac
\ref GCM_CONSTANT_ALPHA Ac Ac Ac Ac
\ref GCM_ONE_MINUS_CONSTANT_ALPHA1-Ac 1-Ac 1-Ac 1-Ac
\ref GCM_SRC_ALPHA_SATURATE i i i 1
-In the table, - -i = min(As/kA, 1 - Ad/kA) - -To determine the blended RGBA values of a pixel when drawing in RGBA mode, -the equation defined by \ref rsxSetBlendEquation us used. In the default mode -(\ref GCM_FUNC_ADD for RGB and alpha equations), the equations are the -following: - - - Rd = min(kR, RssR + RddR) - - Gd = min(kG, GssG + GddG) - - Bd = min(kB, BssB + BddB) - - Ad = min(kA, AssA + AddA) - -Despite the apparent precision of the above equations, blending arithmetic is -not exactly specified, because blending operates with imprecise integer color -values. -However, a blend factor that should be equal to 1 is guaranteed not to modify -its multiplicand, and a blend factor equal to 0 reduces its multiplicand to 0. -For example, when \p sfcolor is \ref GCM_SRC_ALPHA, \p fdcolor is -\ref GCM_ONE_MINUS_SRC_ALPHA, and As is equal to kA, -the equations reduce to simple replacement: - -Rd = Rs ; -Gd = Gs ; -Bd = Bs - -\par Examples - -Transparency is best implemented using blend function -(\p sfcolor = \p sfalpha = \ref GCM_SRC_ALPHA, -\p dfcolor = \p dfalpha = \ref GCM_ONE_MINUS_SRC_ALPHA) with primitives sorted from -farthest to nearest. Note that this transparency calculation does not require -the presence of alpha bitplanes in the frame buffer. - -Blend function (\ref GCM_SRC_ALPHA, \ref GCM_ONE_MINUS_SRC_ALPHA) is also useful -for rendering antialiased points and lines in arbitrary order. - -Polygon antialiasing is optimized using blend function -(\ref GCM_SRC_ALPHA_SATURATE, \ref GCM_ONE) with polygons sorted from nearest -to farthest. -Destination alpha bitplanes, which must be present for this blend function to -operate correctly, store the accumulated coverage. - -\par Notes - -Incoming (source) alpha is correctly thought of as a material opacity, ranging -from 1.0 ( kA ), representing complete opacity, to 0.0 (0), -representing complete transparency. - - -\param context Pointer to the context object -\param sfcolor Specifies how the red, green, and blue source blending factors are computed. -\param dfcolor Specifies how the red, green, and blue source blending factors are computed. -\param sfalpha Specifies how the alpha source blending factor is computed. -\param dfalpha Specifies how the alpha destination blending factor is computed. -*/ -void rsxSetBlendFunc(gcmContextData *context,u16 sfcolor,u16 dfcolor,u16 sfalpha,u16 dfalpha); - -/*! \brief Set the blend equation. - -The blend equations determine how a new pixel (the “source” color) -is combined with a pixel already in the framebuffer (the -“destination” color). -This function specifies one blend equation for the RGB-color components -and one blend equation for the alpha component. - -These equations use the source and destination blend factors specified by -\ref rsxSetBlendFunc. See \ref rsxSetBlendFunc for a description of the various -blend factors. - -In the equations that follow, source and destination color components are -referred to as Rs, Gs, Bs, As -and Rd, Gd, Bd, Ad, respectively. -The result color is referred to as Rr, Gr, Br, -Ar. -The source and destination blend factors are denoted -sR, sG, sB, sA and dR, -dG, dB, dA, respectively. -For these equations all color components are understood to have values in the -range [0,1]. - - - - - - - - -
Mode Rr Gr Br Ar
\ref GCM_FUNC_ADD RssR+RddRGssG+GddGBssB+BddBAssA+AddA
\ref GCM_MIN min(Rs,Rd) min(Gs,Gd) min(Bs,Bd) min(As,Ad)
\ref GCM_MAX max(Rs,Rd) max(Gs,Gd) max(Bs,Bd) max(As,Ad)
\ref GCM_FUNC_SUBTRACT RssR-RddRGssG-GddGBssB-BddBAssA-AddA
\ref GCM_FUNC_REVERSE_SUBTRACTRddR-RssRGddG-GssGBddB-BssBAddA-AssA
- -The results of these equations are clamped to the range [0,1]. - -The \ref GCM_MIN and \ref GCM_MAX equations are useful for applications that -analyze image data (image thresholding against a constant color, for example). -The \ref GCM_FUNC_ADD equation is useful for antialiasing and transparency, -among other things. - -Initially, both the RGB blend equation and the alpha blend equation are set -to \ref GCM_FUNC_ADD. - -\par Notes - -The \ref GCM_MIN, and \ref GCM_MAX equations do not use the source or -destination factors, only the source and destination colors. - -\param context Pointer to the context object -\param color Specifies the RGB blend equation, how the red, green, and blue -components of the source and destination colors are combined. -\param alpha Specifies the alpha blend equation, how the alpha component of -the source and destination colors are combined. -*/ -void rsxSetBlendEquation(gcmContextData *context,u16 color,u16 alpha); - - -/*! \brief Set the blending constant color. -\param context Pointer to the context object -\param color0 all A, R, G, B components in 8-bit component mode -\param color1 reserved for 16-bit components -*/ -void rsxSetBlendColor(gcmContextData *context,u32 color0,u32 color1); - -/*! \brief Enable or disable blending. -\param context Pointer to the context object -\param enable - - \c GCM_TRUE : enable blending - - \c GCM_FALSE : disable blending -*/ -void rsxSetBlendEnable(gcmContextData *context,u32 enable); - -void rsxSetTransformBranchBits(gcmContextData *context,u32 branchBits); - -/*! \brief Configuration the mode for an upcoming asynchronous RSX DMA transfer. -\param context Pointer to the context object -\param mode Specify source and destination memory areas. Possible values are: -- \ref GCM_TRANSFER_LOCAL_TO_LOCAL -- \ref GCM_TRANSFER_MAIN_TO_LOCAL -- \ref GCM_TRANSFER_LOCAL_TO_MAIN -- \ref GCM_TRANSFER_MAIN_TO_MAIN -*/ -void rsxSetTransferDataMode(gcmContextData *context,u8 mode); - -/*! \brief Specify the memory locations for an RSX DMA transfer. This function should be called after rsxSetTransferDataMode() and rsxSetTransferDataFormat(). -\param context Pointer to the context object -\param dst Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -\param src Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -*/ -void rsxSetTransferDataOffset(gcmContextData *context,u32 dst,u32 src); - -/*! \brief Format an upcoming asynchronous RSX DMA transfer. -\param context Pointer to the context object -\param inpitch Pitch size, in bytes, of the source buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). -\param outpitch Pitch size, in bytes, of the destination buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). -\param linelength Size, in bytes, of each line of data that will be transfered. -\param linecount Number of lines of data to transfer. -\param inbytes Number of bytes for each block (e.g., pixel) of data to be transfered: 1, 2, or 4. Will perform scatter-gather transfer if different from outbytes. -\param outbytes Number of bytes for each block (e.g., pixel) of data to be transfered: 1, 2, or 4. Will perform scatter-gather transfer if different from inbytes. -*/ -void rsxSetTransferDataFormat(gcmContextData *context,s32 inpitch,s32 outpitch,u32 linelength,u32 linecount,u8 inbytes,u8 outbytes); - -/*! \brief Initiate an asynchronous RSX DMA transfer. -\param context Pointer to the context object -\param mode Specify source and destination memory areas. Possible values are: -- \ref GCM_TRANSFER_LOCAL_TO_LOCAL -- \ref GCM_TRANSFER_MAIN_TO_LOCAL -- \ref GCM_TRANSFER_LOCAL_TO_MAIN -- \ref GCM_TRANSFER_MAIN_TO_MAIN -\param dst Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -\param outpitch Pitch size, in bytes, of the destination buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). -\param src Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -\param inpitch Pitch size, in bytes, of the source buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). -\param linelength Size, in bytes, of each line of data that will be transfered. -\param linecount Number of lines of data to transfer. -*/ -void rsxSetTransferData(gcmContextData *context,u8 mode,u32 dst,u32 outpitch,u32 src,u32 inpitch,u32 linelength,u32 linecount); - -/*! \brief Configure an upcoming asynchronous RSX blit. -\param context Pointer to the context object -\param mode Specify source and destination memory areas. Possible values are: -- \ref GCM_TRANSFER_LOCAL_TO_LOCAL -- \ref GCM_TRANSFER_MAIN_TO_LOCAL -- \ref GCM_TRANSFER_LOCAL_TO_MAIN -- \ref GCM_TRANSFER_MAIN_TO_MAIN -\param surface Transfer surface mode. Possible values are: -- \ref GCM_TRANSFER_SURFACE -- \ref GCM_TRANSFER_SWIZZLE -*/ -void rsxSetTransferScaleMode(gcmContextData *context,const u8 mode,const u8 surface); - -/*! \brief Initiate an asynchronous RSX blit. -\param context Pointer to the context object -\param scale Specify the transfer geometry & parameters. -\param surface Specify the surface to blit to. -*/ -void rsxSetTransferScaleSurface(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSurface *surface); - -/*! \brief Initialiate an asynchronous transfer of a rectangular image from one area of memory to another. -\param context Pointer to the context object -\param mode Specify source and destination memory areas. Possible values are: -- \ref GCM_TRANSFER_LOCAL_TO_LOCAL -- \ref GCM_TRANSFER_MAIN_TO_LOCAL -- \ref GCM_TRANSFER_LOCAL_TO_MAIN -- \ref GCM_TRANSFER_MAIN_TO_MAIN -\param dstOffset Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -\param dstPitch Pitch size, in bytes, of the destination image data (width multiplied by the number of bytes in each pixel). -\param dstX Origin of the destination data, relative to the beginning of the destination buffer. -\param dstY Origin of the destination data, relative to the beginning of the destination buffer. -\param srcOffset Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). -\param srcPitch Pitch size, in bytes, of the source image data (width multiplied by the number of bytes in each pixel). -\param srcX Origin of the source rectangle, relative to the beginning of the source buffer. -\param srcY Origin of the source rectangle, relative to the beginning of the source buffer. -\param width Width of the transfer rectangle. -\param height Height of the transfer rectangle. -\param bytesPerPixel Number of bytes per pixel to transfer: 2 or 4. -*/ -void rsxSetTransferImage(gcmContextData *context,const u8 mode,const u32 dstOffset,const u32 dstPitch,const u32 dstX,const u32 dstY,const u32 srcOffset,const u32 srcPitch,const u32 srcX,const u32 srcY,const u32 width,const u32 height,const u32 bytesPerPixel); -void rsxSetTimeStamp(gcmContextData *context,u32 index); - -#if 0 -/*! \brief Unfinished -*/ -void rsxSetTransferScaleSwizzle(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSwizzle *swizzle); -#endif +#define RSX_INTERNAL 0 + +#define RSX_UNSAFE 1 +#define RSX_FUNCTION_MACROS +#include +#include +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE + +#define RSX_UNSAFE 0 +#define RSX_FUNCTION_MACROS +#include +#include +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE + +#undef RSX_INTERNAL #ifdef __cplusplus } diff --git a/ppu/include/rsx/commands_inc.h b/ppu/include/rsx/commands_inc.h new file mode 100644 index 00000000..2d48b7f9 --- /dev/null +++ b/ppu/include/rsx/commands_inc.h @@ -0,0 +1,677 @@ +/*! \brief Set drawing direction of front face. +\param context Pointer to the context object. +\param dir Drawing direction of front face. Possible values are: +- \ref GCM_FRONTFACE_CW +- \ref GCM_FRONTFACE_CCW +*/ +void RSX_FUNC(SetFrontFace)(gcmContextData *context,u32 dir); + +/*! \brief Set culling mode. +\param context Pointer to context object. +\param cull Type of cull mode. Possible values are: +- \ref GCM_CULL_FRONT +- \ref GCM_CULL_BACK +- \ref GCM_CULL_ALL +*/ +void RSX_FUNC(SetCullFace)(gcmContextData *context,u32 cull); + +/*! \brief Enable/Disable face culling. +\param context Pointer to the context object. +\param enable Enable flag. Possible values are: + - \ref GCM_TRUE + - \ref GCM_FALSE + */ +void RSX_FUNC(SetCullFaceEnable)(gcmContextData *context,u32 enable); + +/*! \brief Control front-facing polygon rendering. +\param context Pointer to the context object. +\param enable Drawing mode. Possible values are: + - \ref GCM_POLYGON_MODE_POINT + - \ref GCM_POLYGON_MODE_LINE + - \ref GCM_POLYGON_MODE_FILL + */ +void RSX_FUNC(SetFrontPolygonMode)(gcmContextData *context,u32 mode); + +/*! \brief Control back-facing polygon rendering. +\param context Pointer to the context object. +\param enable Drawing mode. Possible values are: + - \ref GCM_POLYGON_MODE_POINT + - \ref GCM_POLYGON_MODE_LINE + - \ref GCM_POLYGON_MODE_FILL + */ +void RSX_FUNC(SetBackPolygonMode)(gcmContextData *context,u32 mode); + +void RSX_FUNC(SetPolygonOffsetFillEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetPolygonOffset)(gcmContextData *context,f32 factor,f32 units); + +/*! \brief Enable/Disable write to depth buffer. +\param context Pointer to the context object. +\param enable Enable flag. Possible values are: +- \ref GCM_TRUE +- \ref GCM_FALSE +*/ +void RSX_FUNC(SetDepthWriteEnable)(gcmContextData *context,u32 enable); + +/*! \brief Stop the render sequence. + +Stops the rendering for a primitive, started by \ref rsxDrawVertexBegin. +\param context Pointer to the context object. +*/ +void RSX_FUNC(DrawVertexEnd)(gcmContextData *context); + +/*! \brief Set the shading model for the render sequence. +\param context Pointer to the context object. +\param shadeModel Type of shading model. Possible values are: +- \ref GCM_SHADE_MODEL_FLAT +- \ref GCM_SHADE_MODEL_SMOOTH +*/ +void RSX_FUNC(SetShadeModel)(gcmContextData *context,u32 shadeModel); + +/*! \brief Start the render sequence. + +Starts the rendering for a primitive. +\param context Pointer to the context object. +\param type Type of primitive to render. Possible values are: +- \ref GCM_TYPE_POINTS +- \ref GCM_TYPE_LINES +- \ref GCM_TYPE_LINE_LOOP +- \ref GCM_TYPE_LINE_STRIP +- \ref GCM_TYPE_TRIANGLES +- \ref GCM_TYPE_TRIANGLE_STRIP +- \ref GCM_TYPE_TRIANGLE_FAN +- \ref GCM_TYPE_QUADS +- \ref GCM_TYPE_QUAD_STRIP +- \ref GCM_TYPE_POLYGON +*/ +void RSX_FUNC(DrawVertexBegin)(gcmContextData *context,u32 type); +void RSX_FUNC(DrawVertex1f)(gcmContextData *context,u8 idx,f32 v); +void RSX_FUNC(DrawVertex2f)(gcmContextData *context,u8 idx,const f32 v[2]); +void RSX_FUNC(DrawVertex3f)(gcmContextData *context,u8 idx,const f32 v[3]); +void RSX_FUNC(DrawVertex4f)(gcmContextData *context,u8 idx,const f32 v[4]); +void RSX_FUNC(DrawVertex4s)(gcmContextData *context,u8 idx,const s16 v[4]); +void RSX_FUNC(DrawVertexScaled4s)(gcmContextData *context,u8 idx,const s16 v[4]); +void RSX_FUNC(DrawVertex2s)(gcmContextData *context,u8 idx,const s16 v[2]); +void RSX_FUNC(DrawVertex4ub)(gcmContextData *context,u8 idx,const u8 v[4]); +void RSX_FUNC(SetScissor)(gcmContextData *context,u16 x,u16 y,u16 w,u16 h); + +/*! \brief Specify the value used for depth buffer comparisons. +\param context Pointer to the context object. +\param func Specifies the depth comparison function. Possible values are: + - \ref GCM_NEVER + - \ref GCM_LESS + - \ref GCM_EQUAL + - \ref GCM_LEQUAL + - \ref GCM_GREATER + - \ref GCM_NOTEQUAL + - \ref GCM_GEQUAL + - \ref GCM_ALWAYS +*/ +void RSX_FUNC(SetDepthFunc)(gcmContextData *context,u32 func); + +/*! \brief Enable or disable the depth test. + +If depth test is enabled, the GPU performs depth comparisons and updates the +depth buffer. +Note that even if the depth buffer exists and the depth mask is non-zero, +the depth buffer is not updated if the depth test is disabled. +\param context Pointer to the context object. +\param enable Enable flag. Possible values are: + - \ref GCM_TRUE + - \ref GCM_FALSE +*/ +void RSX_FUNC(SetDepthTestEnable)(gcmContextData *context,u32 enable); + +/*! \brief Clear the render surface. + +This function clears the chosen selection of color components, depth and stencil +values for all pixels in the destination surface. The clear color can be chosen +using \ref rsxSetClearColor, and the clear value for the depth buffer is set +using \ref rsxSetClearDepthValue. + +\param context Pointer to the context object. +\param clear_mask A selection of components to be cleared. Must be an OR +combination of the following values: + - \ref GCM_CLEAR_Z + - \ref GCM_CLEAR_S + - \ref GCM_CLEAR_R + - \ref GCM_CLEAR_G + - \ref GCM_CLEAR_B + - \ref GCM_CLEAR_A +The value of \ref GCM_CLEAR_M can also be chosen, to clear all RGBA components, +depth and stencil buffers. +*/ +void RSX_FUNC(ClearSurface)(gcmContextData *context,u32 clear_mask); + +/*! \brief Set the clear depth value. + +This value is used by the \ref rsxClearSurface function. +\param context Pointer to the context object. +\param value Color value +*/ +void RSX_FUNC(SetClearDepthStencil)(gcmContextData *context,u32 value); +void RSX_FUNC(SetReturnCommand)(gcmContextData *context); +void RSX_FUNC(SetCallCommand)(gcmContextData *context,u32 offset); +void RSX_FUNC(SetJumpCommand)(gcmContextData *context,u32 offset); +void RSX_FUNC(SetNopCommand)(gcmContextData *context,u32 count); +void RSX_FUNC(SetSkipNop)(gcmContextData *context,u32 count); + +/*! \brief Set the clear color. + +The clear color value is used by the \ref rsxClearSurface function. +\param context Pointer to the context object. +\param color The clear color value. +*/ +void RSX_FUNC(SetClearColor)(gcmContextData *context,u32 color); + +/*! \brief Enable or disable write access to the framebuffer color components. +\param context Pointer to the context object. +\param mask A selection of the components to enable write access. It is an OR +combination of the following values: + - \ref GCM_COLOR_MASK_B + - \ref GCM_COLOR_MASK_G + - \ref GCM_COLOR_MASK_R + - \ref GCM_COLOR_MASK_A +*/ +void RSX_FUNC(SetColorMask)(gcmContextData *context,u32 mask); + +/*! \brief Enable or disable write access to the framebuffer color components +(Multiple Render Target output). +\param context Pointer to the context object. +\param mask A selection of the components to enable write access. It is an OR +combination of the following values: + - \ref GCM_COLOR_MASK_B + - \ref GCM_COLOR_MASK_G + - \ref GCM_COLOR_MASK_R + - \ref GCM_COLOR_MASK_A +*/ +void RSX_FUNC(SetColorMaskMRT)(gcmContextData *context,u32 mask); + +void RSX_FUNC(SetPointSpriteControl)(gcmContextData *context,u32 enable,u32 rmode,u32 texcoordMask); +void RSX_FUNC(SetPointSize)(gcmContextData *context,f32 size); +void RSX_FUNC(SetAntialiasingControl)(gcmContextData *context,u32 enable,u32 alphaToCoverage,u32 alphaToOne,u32 sampleMask); +void RSX_FUNC(SetCylindricalWrap)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetStencilFunc)(gcmContextData *context,u32 func,u32 ref,u32 mask); +void RSX_FUNC(SetStencilMask)(gcmContextData *context,u32 mask); +void RSX_FUNC(SetStencilOp)(gcmContextData *context,u32 fail,u32 depthFail,u32 depthPass); +void RSX_FUNC(SetStencilTestEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetBackStencilFunc)(gcmContextData *context,u32 func,u32 ref,u32 mask); +void RSX_FUNC(SetBackStencilMask)(gcmContextData *context,u32 mask); +void RSX_FUNC(SetBackStencilOp)(gcmContextData *context,u32 fail,u32 depthFail,u32 depthPass); +void RSX_FUNC(SetTwoSidedStencilTestEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetTwoSideLightEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetRenderEnable)(gcmContextData *context,u8 mode,u32 index); +void RSX_FUNC(SetReport)(gcmContextData *context,u32 type,u32 index); +void RSX_FUNC(SetClearReport)(gcmContextData *context,u32 type); +void RSX_FUNC(SetSCullControl)(gcmContextData *context,u8 sFunc,u8 sRef,u8 sMask); +void RSX_FUNC(SetZCullEnable)(gcmContextData *context, u32 depth, u32 stencil); +void RSX_FUNC(SetClearZCullSurface)(gcmContextData *context, u32 depth, u32 stencil); +void RSX_FUNC(SetZCullLimit)(gcmContextData *context,u16 moveforwardlimit,u16 pushbacklimit); +void RSX_FUNC(SetZCullControl)(gcmContextData *context,u8 zculldir,u8 zcullformat); +void RSX_FUNC(SetZCullStatsEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetPolygonSmoothEnable)(gcmContextData *context,u32 enable); + +/*! \brief Setup the render surface. + +This function is used to setup the render target where RSX should render the frame into. +\param context Pointer to the context object. +\param surface Pointer to the surface object. +*/ +void RSX_FUNC(SetSurface)(gcmContextData *context,const gcmSurface *surface); +void RSX_FUNC(SetReferenceCommand)(gcmContextData *context,u32 ref_value); + +/*! \brief Enqueues a Wait for label command. +\param context Pointer to the context object. +\param index Label index +\param valuie Label value +*/ +void RSX_FUNC(SetWaitLabel)(gcmContextData *context,u8 index,u32 value); + +/*! \brief Enqueues a Write Command label command. +\param context Pointer to the context object. +\param index Label index +\param value Label value +*/ +void RSX_FUNC(SetWriteCommandLabel)(gcmContextData *context,u8 index,u32 value); + +/*! \brief Enqueues a Write Backend label command. +\param context Pointer to the context object. +\param index Label index +\param value Label value +*/ +void RSX_FUNC(SetWriteBackendLabel)(gcmContextData *context,u8 index,u32 value); + +void RSX_FUNC(SetWriteTextureLabel)(gcmContextData *context,u8 index,u32 value); + +void RSX_FUNC(SetViewportClip)(gcmContextData *context,u8 sel,u16 width,u16 height); + +/*! \brief Set viewport. + +This function sets the viewport.
+The origin (0,0) of the normalized device coordinate points to the center of the screen.
+Performing viewport conversion, where the upper left corner is the origin is as follows: +\code + x = X; + y = Y; + width = WIDTH; + height = HEIGHT; + min = 0.0f; + max = 1.0f; + scale[0] = width * 0.5f; + scale[1] = height * 0.5f; + scale[2] = (max - min) * 0.5f; + offset[0] = x + width * 0.5f; + offset[1] = y + height * 0.5f; + offset[2] = (max + min) * 0.5f; +\endcode +

+Performing viewport conversion, where the lower left corner is the origin is as follows (this is equivalent to glViewport): +\code + x = X; + y = WINDOW_HEIGHT - Y - HEIGHT; + width = WIDTH; + height = HEIGHT; + min = 0.0f; + max = 1.0f; + scale[0] = width * 0.5f; + scale[1] = height * -0.5f; + scale[2] = (max - min) * 0.5f; + offset[0] = x + width * 0.5f; + offset[1] = y + height * 0.5f; + offset[2] = (max + min) * 0.5f; +\endcode +\param context Pointer to the context object. +\param x Origin of the viewport rectangle in pixels (0 - 4095). Initial value is (0,0). +\param y Origin of the viewport rectangle in pixels (0 - 4095). Initial value is (0,0). +\param width Width of the viewport (0 - 4096). Initial value is 4096. +\param height Height of the viewport (0 - 4096). Initial value is 4096. +\param min Minimum Z clip value. Initial value is 0.0. +\param max Maximum Z clip value. Initial value is 1.0. +\param scale Scale values to be used for viewport conversion. Initial values are (2048.0,2048.0,0.5,0.0). +\param offset Offset values to be used for viewport conversion. Initial values are (2048.0,2048.0,0.5,0.0). +*/ +void RSX_FUNC(SetViewport)(gcmContextData *context,u16 x,u16 y,u16 width,u16 height,f32 min,f32 max,const f32 scale[4],const f32 offset[4]); + +/*! \brief Invalidates a texture cache. +\param context Pointer to the context object. +\param type Type of texture cache to be invalidated. Possible values are: + - \ref GCM_INVALIDATE_TEXTURE + - \ref GCM_INVALIDATE_VERTEX_TEXTURE +*/ +void RSX_FUNC(InvalidateTextureCache)(gcmContextData *context,u32 type); + +void RSX_FUNC(InvalidateVertexCache)(gcmContextData *context); + +/*! \brief Loads a texture. +\param context Pointer to the context object. +\param index Texture index. +\param texture Pointer to the texture data. +*/ +void RSX_FUNC(LoadTexture)(gcmContextData *context,u8 index,const gcmTexture *texture); + +/*! \brief Set texture control parameters. +\param context Pointer to the context object. +\param index Texture index. +\param enable Enable flag. Possible values are: + - \ref GCM_TRUE + - \ref GCM_FALSE +\param minlod minimum level of detail. +\param maxlod maximum level of detail. +\param maxaniso sample level of the anisotropic filter. Possible values are: + - \ref GCM_TEXTURE_MAX_ANISO_1 + - \ref GCM_TEXTURE_MAX_ANISO_2 + - \ref GCM_TEXTURE_MAX_ANISO_4 + - \ref GCM_TEXTURE_MAX_ANISO_6 + - \ref GCM_TEXTURE_MAX_ANISO_8 + - \ref GCM_TEXTURE_MAX_ANISO_10 + - \ref GCM_TEXTURE_MAX_ANISO_12 + - \ref GCM_TEXTURE_MAX_ANISO_16 +\todo finish args documentation. +*/ +void RSX_FUNC(TextureControl)(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod,u8 maxaniso); +void RSX_FUNC(TextureFilter)(gcmContextData *context,u8 index,u16 bias,u8 min,u8 mag,u8 conv); +void RSX_FUNC(TextureWrapMode)(gcmContextData *context,u8 index,u8 wraps,u8 wrapt,u8 wrapr,u8 unsignedRemap,u8 zfunc,u8 gamma); +void RSX_FUNC(TextureBorderColor)(gcmContextData *context,u8 index,u32 color); +void RSX_FUNC(TextureOptimization)(gcmContextData *context,u8 index,u8 slope,u8 iso,u8 aniso); +void RSX_FUNC(TextureAnisoSpread)(gcmContextData *context,u8 index,u8 reduceSamplesEnable,u8 hReduceSamplesEnable,u8 vReduceSamplesEnable,u8 spacingSelect,u8 hSpacingSelect,u8 vSpacingSelect); + + +void RSX_FUNC(LoadVertexTexture)(gcmContextData *context,u8 index,const gcmTexture *texture); +void RSX_FUNC(VertexTextureControl)(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod); +void RSX_FUNC(VertexTextureFilter)(gcmContextData *context,u8 index,u16 bias); +void RSX_FUNC(VertexTextureWrapMode)(gcmContextData *context,u8 index,u8 wraps,u8 wrapt); +void RSX_FUNC(VertexTextureBorderColor)(gcmContextData *context,u8 index,u32 color); + +/*! \brief Load a compiled vertex shader program. +\param context Pointer to the context object +\param program Pointer to the vertex program configuration +\param ucode Pointer to the shader micro code +*/ +void RSX_FUNC(LoadVertexProgram)(gcmContextData *context,const rsxVertexProgram *program,const void *ucode); + +/*! \brief Load a compiled fragment shader program. +\param context Pointer to the context object +\param program Pointer to the fragment program configuration +\param offset Memory offset of fragment program +\param location Memory location type where the program relies. Possible values are: +- \ref GCM_LOCATION_RSX +- \ref GCM_LOCATION_CELL +*/ +void RSX_FUNC(LoadFragmentProgramLocation)(gcmContextData *context,const rsxFragmentProgram *program,u32 offset,u32 location); +void RSX_FUNC(UpdateFragmentProgramLocation)(gcmContextData *context,u32 offset,u32 location); +void RSX_FUNC(SetZControl)(gcmContextData *context,u8 cullNearFar,u8 zClampEnable,u8 cullIgnoreW); +void RSX_FUNC(SetZPixelCountEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(LoadVertexProgramBlock)(gcmContextData *context,const rsxVertexProgram *program,const void *ucode); +void RSX_FUNC(LoadVertexProgramParameterBlock)(gcmContextData *context,u32 base_const,u32 const_cnt,const f32 *value); +void RSX_FUNC(SetVertexProgramParameter)(gcmContextData *context,const rsxVertexProgram *program,const rsxProgramConst *param,const f32 *value); +void RSX_FUNC(SetVertexProgramParameterByIndex)(gcmContextData *context,const rsxVertexProgram *program,s32 index,const f32 *value); +void RSX_FUNC(SetFragmentProgramParameter)(gcmContextData *context,const rsxFragmentProgram *program,const rsxProgramConst *param,const f32 *value,u32 offset,u32 location); +void RSX_FUNC(SetFragmentProgramParameterByIndex)(gcmContextData *context,const rsxFragmentProgram *program,s32 index,const f32 *value,u32 offset,u32 location); +void RSX_FUNC(DrawVertexArray)(gcmContextData *context,u32 type,u32 start,u32 count); +void RSX_FUNC(BindVertexArrayAttrib)(gcmContextData *context,u8 attr,u16 frequency,u32 offset,u8 stride,u8 elems,u8 dtype,u8 location); +void RSX_FUNC(DrawIndexArray)(gcmContextData *context,u8 type,u32 offset,u32 count,u8 data_type,u8 location); +void RSX_FUNC(DrawInlineIndexArray16)(gcmContextData *context,u8 type,u32 start,u32 count,const u16 *data); +void RSX_FUNC(DrawInlineIndexArray32)(gcmContextData *context,u8 type,u32 start,u32 count,const u32 *data); +void RSX_FUNC(InlineTransfer)(gcmContextData *context,u32 dstOffset,const void *srcAddress,u32 sizeInWords,u8 location); +void RSX_FUNC(SetUserClipPlaneControl)(gcmContextData *context,u32 plane0,u32 plane1,u32 plane2,u32 plane3,u32 plane4,u32 plane5); +void RSX_FUNC(SetAlphaFunc)(gcmContextData *context,u32 alphaFunc,u32 ref); +void RSX_FUNC(SetAlphaTestEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetBlendEnableMrt)(gcmContextData *context, u32 mrt1, u32 mrt2, u32 mrt3); +void RSX_FUNC(SetBlendOptimization)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetLogicOp)(gcmContextData *context,u32 op); +void RSX_FUNC(SetLogicOpEnable)(gcmContextData *context,u32 enable); +void RSX_FUNC(SetFogMode)(gcmContextData *context,u32 mode); +void RSX_FUNC(SetFogParams)(gcmContextData *context,f32 p0,f32 p1); +void RSX_FUNC(SetVertexAttribOutputMask)(gcmContextData *context,u32 mask); + +/*! \brief Specify pixel arithmetic. + +In RGBA mode, pixels can be drawn using a function that blends the incoming +(source) RGBA values with the RGBA values that are already in the frame buffer +(the destination values). Blending is initially disabled. +Use \ref rsxSetBlendEnable to enable and disable blending. + +\c rsxSetBlendFunc defines the operation of blending when it is enabled. +\p sfcolor and and \p sfalpha specify which method is used to scale the source +color and alpha components. +\p dfcolor and and \p dfalpha specify which method is used to scale the +destination color and alpha components. +The possible methods are described in the following table. +Each method defines four scale factors, one each for red, green, blue, and +alpha. +In the table and in subsequent equations, source and destination color +components are referred to as Rs, Gs, Bs, +As and Rd, Gd, Bd, Ad, +respectively. +The color specified by \ref rsxSetBlendColor is referred to as +Rc, Gc, Bc, Ac. +They are understood to have integer values between 0 and +kR, kG, kB, kA, where + +kc = 2mc - 1 + +and mR, mG, mB, mA is the number of +red, green, blue, and alpha bitplanes. + +Source and destination scale factors are referred to as +sR, sG, sB, sA and dR, +dG, dB, dA. +The scale factors described in the table, denoted fR, fG, +fB, fA, represent either source or destination +factors. All scale factors have range [0,1]. + + + + + + + + + + + + + + + + + + +
Parameter fR fG fB fA
\ref GCM_ZERO 0 0 0 0
\ref GCM_ONE 1 1 1 1
\ref GCM_SRC_COLOR Rs/kR Gs/kG Bs/kB As/kA
\ref GCM_ONE_MINUS_SRC_COLOR 1-Rs/kR1-Gs/kG1-Bs/kB1-As/kA
\ref GCM_DST_COLOR Rd/kR Gd/kG Bd/kB Ad/kA
\ref GCM_ONE_MINUS_DST_COLOR 1-Rd/kR1-Gd/kG1-Bd/kB1-Ad/kA
\ref GCM_SRC_ALPHA As/kA As/kA As/kA As/kA
\ref GCM_ONE_MINUS_SRC_ALPHA 1-As/kA1-As/kA1-As/kA1-As/kA
\ref GCM_DST_ALPHA Ad/kA Ad/kA Ad/kA Ad/kA
\ref GCM_ONE_MINUS_DST_ALPHA 1-Ad/kA1-Ad/kA1-Ad/kA1-Ad/kA
\ref GCM_CONSTANT_COLOR Rc Gc Bc Ac
\ref GCM_ONE_MINUS_CONSTANT_COLOR1-Rc 1-Gc 1-Bc 1-Ac
\ref GCM_CONSTANT_ALPHA Ac Ac Ac Ac
\ref GCM_ONE_MINUS_CONSTANT_ALPHA1-Ac 1-Ac 1-Ac 1-Ac
\ref GCM_SRC_ALPHA_SATURATE i i i 1
+In the table, + +i = min(As/kA, 1 - Ad/kA) + +To determine the blended RGBA values of a pixel when drawing in RGBA mode, +the equation defined by \ref rsxSetBlendEquation us used. In the default mode +(\ref GCM_FUNC_ADD for RGB and alpha equations), the equations are the +following: + + - Rd = min(kR, RssR + RddR) + - Gd = min(kG, GssG + GddG) + - Bd = min(kB, BssB + BddB) + - Ad = min(kA, AssA + AddA) + +Despite the apparent precision of the above equations, blending arithmetic is +not exactly specified, because blending operates with imprecise integer color +values. +However, a blend factor that should be equal to 1 is guaranteed not to modify +its multiplicand, and a blend factor equal to 0 reduces its multiplicand to 0. +For example, when \p sfcolor is \ref GCM_SRC_ALPHA, \p fdcolor is +\ref GCM_ONE_MINUS_SRC_ALPHA, and As is equal to kA, +the equations reduce to simple replacement: + +Rd = Rs ; +Gd = Gs ; +Bd = Bs + +\par Examples + +Transparency is best implemented using blend function +(\p sfcolor = \p sfalpha = \ref GCM_SRC_ALPHA, +\p dfcolor = \p dfalpha = \ref GCM_ONE_MINUS_SRC_ALPHA) with primitives sorted from +farthest to nearest. Note that this transparency calculation does not require +the presence of alpha bitplanes in the frame buffer. + +Blend function (\ref GCM_SRC_ALPHA, \ref GCM_ONE_MINUS_SRC_ALPHA) is also useful +for rendering antialiased points and lines in arbitrary order. + +Polygon antialiasing is optimized using blend function +(\ref GCM_SRC_ALPHA_SATURATE, \ref GCM_ONE) with polygons sorted from nearest +to farthest. +Destination alpha bitplanes, which must be present for this blend function to +operate correctly, store the accumulated coverage. + +\par Notes + +Incoming (source) alpha is correctly thought of as a material opacity, ranging +from 1.0 ( kA ), representing complete opacity, to 0.0 (0), +representing complete transparency. + + +\param context Pointer to the context object +\param sfcolor Specifies how the red, green, and blue source blending factors are computed. +\param dfcolor Specifies how the red, green, and blue source blending factors are computed. +\param sfalpha Specifies how the alpha source blending factor is computed. +\param dfalpha Specifies how the alpha destination blending factor is computed. +*/ +void RSX_FUNC(SetBlendFunc)(gcmContextData *context,u16 sfcolor,u16 dfcolor,u16 sfalpha,u16 dfalpha); + +/*! \brief Set the blend equation. + +The blend equations determine how a new pixel (the “source” color) +is combined with a pixel already in the framebuffer (the +“destination” color). +This function specifies one blend equation for the RGB-color components +and one blend equation for the alpha component. + +These equations use the source and destination blend factors specified by +\ref rsxSetBlendFunc. See \ref rsxSetBlendFunc for a description of the various +blend factors. + +In the equations that follow, source and destination color components are +referred to as Rs, Gs, Bs, As +and Rd, Gd, Bd, Ad, respectively. +The result color is referred to as Rr, Gr, Br, +Ar. +The source and destination blend factors are denoted +sR, sG, sB, sA and dR, +dG, dB, dA, respectively. +For these equations all color components are understood to have values in the +range [0,1]. + + + + + + + + +
Mode Rr Gr Br Ar
\ref GCM_FUNC_ADD RssR+RddRGssG+GddGBssB+BddBAssA+AddA
\ref GCM_MIN min(Rs,Rd) min(Gs,Gd) min(Bs,Bd) min(As,Ad)
\ref GCM_MAX max(Rs,Rd) max(Gs,Gd) max(Bs,Bd) max(As,Ad)
\ref GCM_FUNC_SUBTRACT RssR-RddRGssG-GddGBssB-BddBAssA-AddA
\ref GCM_FUNC_REVERSE_SUBTRACTRddR-RssRGddG-GssGBddB-BssBAddA-AssA
+ +The results of these equations are clamped to the range [0,1]. + +The \ref GCM_MIN and \ref GCM_MAX equations are useful for applications that +analyze image data (image thresholding against a constant color, for example). +The \ref GCM_FUNC_ADD equation is useful for antialiasing and transparency, +among other things. + +Initially, both the RGB blend equation and the alpha blend equation are set +to \ref GCM_FUNC_ADD. + +\par Notes + +The \ref GCM_MIN, and \ref GCM_MAX equations do not use the source or +destination factors, only the source and destination colors. + +\param context Pointer to the context object +\param color Specifies the RGB blend equation, how the red, green, and blue +components of the source and destination colors are combined. +\param alpha Specifies the alpha blend equation, how the alpha component of +the source and destination colors are combined. +*/ +void RSX_FUNC(SetBlendEquation)(gcmContextData *context,u16 color,u16 alpha); + + +/*! \brief Set the blending constant color. +\param context Pointer to the context object +\param color0 all A, R, G, B components in 8-bit component mode +\param color1 reserved for 16-bit components +*/ +void RSX_FUNC(SetBlendColor)(gcmContextData *context,u32 color0,u32 color1); + +/*! \brief Enable or disable blending. +\param context Pointer to the context object +\param enable + - \c GCM_TRUE : enable blending + - \c GCM_FALSE : disable blending +*/ +void RSX_FUNC(SetBlendEnable)(gcmContextData *context,u32 enable); + +void RSX_FUNC(SetTransformBranchBits)(gcmContextData *context,u32 branchBits); + +/*! \brief Configuration the mode for an upcoming asynchronous RSX DMA transfer. +\param context Pointer to the context object +\param mode Specify source and destination memory areas. Possible values are: +- \ref GCM_TRANSFER_LOCAL_TO_LOCAL +- \ref GCM_TRANSFER_MAIN_TO_LOCAL +- \ref GCM_TRANSFER_LOCAL_TO_MAIN +- \ref GCM_TRANSFER_MAIN_TO_MAIN +*/ +void RSX_FUNC(SetTransferDataMode)(gcmContextData *context,u8 mode); + +/*! \brief Specify the memory locations for an RSX DMA transfer. This function should be called after rsxSetTransferDataMode() and rsxSetTransferDataFormat(). +\param context Pointer to the context object +\param dst Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +\param src Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +*/ +void RSX_FUNC(SetTransferDataOffset)(gcmContextData *context,u32 dst,u32 src); + +/*! \brief Format an upcoming asynchronous RSX DMA transfer. +\param context Pointer to the context object +\param inpitch Pitch size, in bytes, of the source buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). +\param outpitch Pitch size, in bytes, of the destination buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). +\param linelength Size, in bytes, of each line of data that will be transfered. +\param linecount Number of lines of data to transfer. +\param inbytes Number of bytes for each block (e.g., pixel) of data to be transfered: 1, 2, or 4. Will perform scatter-gather transfer if different from outbytes. +\param outbytes Number of bytes for each block (e.g., pixel) of data to be transfered: 1, 2, or 4. Will perform scatter-gather transfer if different from inbytes. +*/ +void RSX_FUNC(SetTransferDataFormat)(gcmContextData *context,s32 inpitch,s32 outpitch,u32 linelength,u32 linecount,u8 inbytes,u8 outbytes); + +/*! \brief Initiate an asynchronous RSX DMA transfer. +\param context Pointer to the context object +\param mode Specify source and destination memory areas. Possible values are: +- \ref GCM_TRANSFER_LOCAL_TO_LOCAL +- \ref GCM_TRANSFER_MAIN_TO_LOCAL +- \ref GCM_TRANSFER_LOCAL_TO_MAIN +- \ref GCM_TRANSFER_MAIN_TO_MAIN +\param dst Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +\param outpitch Pitch size, in bytes, of the destination buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). +\param src Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +\param inpitch Pitch size, in bytes, of the source buffer (e.g., for a buffer that represents a rectangular image, this would be the width multiplied by the number of bytes in each pixel). +\param linelength Size, in bytes, of each line of data that will be transfered. +\param linecount Number of lines of data to transfer. +*/ +void RSX_FUNC(SetTransferData)(gcmContextData *context,u8 mode,u32 dst,u32 outpitch,u32 src,u32 inpitch,u32 linelength,u32 linecount); + +/*! \brief Configure an upcoming asynchronous RSX blit. +\param context Pointer to the context object +\param mode Specify source and destination memory areas. Possible values are: +- \ref GCM_TRANSFER_LOCAL_TO_LOCAL +- \ref GCM_TRANSFER_MAIN_TO_LOCAL +- \ref GCM_TRANSFER_LOCAL_TO_MAIN +- \ref GCM_TRANSFER_MAIN_TO_MAIN +\param surface Transfer surface mode. Possible values are: +- \ref GCM_TRANSFER_SURFACE +- \ref GCM_TRANSFER_SWIZZLE +*/ +void RSX_FUNC(SetTransferScaleMode)(gcmContextData *context,u8 mode,u8 surface); + +/*! \brief Initiate an asynchronous RSX blit. +\param context Pointer to the context object +\param scale Specify the transfer geometry & parameters. +\param surface Specify the surface to blit to. +*/ +void RSX_FUNC(SetTransferScaleSurface)(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSurface *surface); + +/*! \brief Initialiate an asynchronous transfer of a rectangular image from one area of memory to another. +\param context Pointer to the context object +\param mode Specify source and destination memory areas. Possible values are: +- \ref GCM_TRANSFER_LOCAL_TO_LOCAL +- \ref GCM_TRANSFER_MAIN_TO_LOCAL +- \ref GCM_TRANSFER_LOCAL_TO_MAIN +- \ref GCM_TRANSFER_MAIN_TO_MAIN +\param dstOffset Destination memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +\param dstPitch Pitch size, in bytes, of the destination image data (width multiplied by the number of bytes in each pixel). +\param dstX Origin of the destination data, relative to the beginning of the destination buffer. +\param dstY Origin of the destination data, relative to the beginning of the destination buffer. +\param srcOffset Source memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). +\param srcPitch Pitch size, in bytes, of the source image data (width multiplied by the number of bytes in each pixel). +\param srcX Origin of the source rectangle, relative to the beginning of the source buffer. +\param srcY Origin of the source rectangle, relative to the beginning of the source buffer. +\param width Width of the transfer rectangle. +\param height Height of the transfer rectangle. +\param bytesPerPixel Number of bytes per pixel to transfer: 2 or 4. +*/ +void RSX_FUNC(SetTransferImage)(gcmContextData *context,u8 mode,u32 dstOffset,u32 dstPitch,u32 dstX,u32 dstY,u32 srcOffset,u32 srcPitch,u32 srcX,u32 srcY,u32 width,u32 height,u32 bytesPerPixel); +void RSX_FUNC(SetTimeStamp)(gcmContextData *context,u32 index); + +void RSX_FUNC(SetConvertSwizzleFormat)(gcmContextData *context,u32 dstOffset,u32 dstWidth,u32 dstHeight,u32 dstX,u32 dstY,u32 srcOffset,u32 srcPitch,u32 srcX,u32 srcY,u32 width,u32 height,u32 bytesPerPixel,u32 mode); + +void RSX_FUNC(SetTransferScaleSwizzle)(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSwizzle *swizzle); + +void RSX_FUNC(SetWaitForIdle)(gcmContextData *context); + +/*! \brief Flushes the RSX command buffer. + +This ensures all remaining commands in the command buffer are executed, and +that the buffer is empty when that function returns. +\param context Pointer to the context object. +*/ +void RSX_FUNC(FlushBuffer)(gcmContextData *context); + +/*! \brief Reset the RSX command buffer. +\param context Pointer to the context object. +*/ +void RSX_FUNC(ResetCommandBuffer)(gcmContextData *context); +void RSX_FUNC(Finish)(gcmContextData *context,u32 ref_value); diff --git a/ppu/include/rsx/gcm_sys.h b/ppu/include/rsx/gcm_sys.h index 04077907..7b426733 100644 --- a/ppu/include/rsx/gcm_sys.h +++ b/ppu/include/rsx/gcm_sys.h @@ -8,393 +8,691 @@ #include /*! \brief true boolean value */ -#define GCM_TRUE 1 +#define GCM_TRUE 1 /*! \brief false boolean value */ -#define GCM_FALSE 0 +#define GCM_FALSE 0 + +/*! \brief Traditional FIFO mode. Checks the get pointer in the traditional + way for any opening in the next segment. May sleep-wait if the get + pointer is pointing to the next segment. +*/ +#define GCM_DEFAULT_FIFO_MODE_TRADITIONAL 0 + +/* \brief Optimized FIFO mode. Uses the \ref rsxSetWriteTextureLable() to manage the + command buffer. It handles each segment buffer as an index and monitors + states of the segment buffers by reading the label value executed + by \ref rsxSetWriteTextureLabel(). +*/ +#define GCM_DEFAULT_FIFO_MODE_OPTIMIZE 1 + +/* \brief Conditional FIFO mode. Uses the \ref rsxSetWriteCommandLabel() to manage the + the command buffer. The management of the command buffer is carried out in + the same manner as \ref GCM_DEFAULT_FIFO_MODE_OPTIMIZE. +*/ +#define GCM_DEFAULT_FIFO_MODE_CONDITIONAL 2 /*! \brief flip on horizontal sync, accurate mode */ -#define GCM_FLIP_HSYNC 1 +#define GCM_FLIP_HSYNC 1 /*! \brief flip on vertical sync */ -#define GCM_FLIP_VSYNC 2 +#define GCM_FLIP_VSYNC 2 /*! \brief flip on horizontal sync, inaccurate mode */ -#define GCM_FLIP_HSYNC_AND_BREAK_EVERYTHING 3 +#define GCM_FLIP_HSYNC_AND_BREAK_EVERYTHING 3 /*! \brief maximum count of multiple render targets */ -#define GCM_MAX_MRT_COUNT 4 +#define GCM_MAX_MRT_COUNT 4 -#define GCM_DMA_MEMORY_FRAME_BUFFER (0xFEED0000) -#define GCM_DMA_MEMORY_HOST_BUFFER (0xFEED0001) +#define GCM_DMA_MEMORY_FRAME_BUFFER (0xFEED0000) +#define GCM_DMA_MEMORY_HOST_BUFFER (0xFEED0001) -#define GCM_CONTEXT_SURFACE2D (0x313371C3) -#define GCM_CONTEXT_SWIZZLE2D (0x31337A73) +#define GCM_CONTEXT_SURFACE2D (0x313371C3) +#define GCM_CONTEXT_SWIZZLE2D (0x31337A73) -#define GCM_TRANSFER_LOCAL_TO_LOCAL 0 -#define GCM_TRANSFER_MAIN_TO_LOCAL 1 -#define GCM_TRANSFER_LOCAL_TO_MAIN 2 -#define GCM_TRANSFER_MAIN_TO_MAIN 3 +#define GCM_TRANSFER_LOCAL_TO_LOCAL 0 +#define GCM_TRANSFER_MAIN_TO_LOCAL 1 +#define GCM_TRANSFER_LOCAL_TO_MAIN 2 +#define GCM_TRANSFER_MAIN_TO_MAIN 3 -#define GCM_TF_COLOR_R5G5B5 3 -#define GCM_TF_COLOR_X8R8G8B8 5 -#define GCM_TF_COLOR_A8R8G8B8 8 +/*! \brief Memory buffer is located in RSX memory. */ +#define GCM_LOCATION_RSX 0 +/*! \brief Memory buffer is located in main memory. */ +#define GCM_LOCATION_CELL 1 +/*! \brief Memory buffer is located in report memory. */ +#define GCM_LOCATION_REPORT 2 + +#define GCM_SURFACE_X1R5G5B5_Z1R5G5B5 1 +#define GCM_SURFACE_X1R5G5B5_O1R5G5B5 2 +#define GCM_SURFACE_R5G5B5 3 +#define GCM_SURFACE_X8R8G8B8_Z8R8G8B8 4 +#define GCM_SURFACE_X8R8G8B8 5 +#define GCM_SURFACE_A8R8G8B8 8 +#define GCM_SURFACE_B8 9 +#define GCM_SURFACE_G8B8 10 +#define GCM_SURFACE_F_W16Z16Y16X16 11 +#define GCM_SURFACE_F_W32Z32Y32X32 12 +#define GCM_SURFACE_F_X32 13 +#define GCM_SURFACE_X8B8G8R8_Z8B8G8R8 14 +#define GCM_SURFACE_X8B8G8R8_O8B8G8R8 15 +#define GCM_SURFACE_A8B8G8R8 16 /*! \brief 16-bit depth buffer */ -#define GCM_TF_ZETA_Z16 1 +#define GCM_SURFACE_ZETA_Z16 1 /*! \brief 24-bit depth buffer and 8-bit stencil buffer. */ -#define GCM_TF_ZETA_Z24S8 2 +#define GCM_SURFACE_ZETA_Z24S8 2 /*! \brief Render target is linear */ -#define GCM_TF_TYPE_LINEAR 1 +#define GCM_SURFACE_TYPE_LINEAR 1 /*! \brief Render target is swizzled */ -#define GCM_TF_TYPE_SWIZZLE 2 - -/*! \brief Memory buffer is located in RSX memory. */ -#define GCM_LOCATION_RSX 0 -/*! \brief Memory buffer is located in main memory. */ -#define GCM_LOCATION_CELL 1 +#define GCM_SURFACE_TYPE_SWIZZLE 2 /*! \brief Do not use render target */ -#define GCM_TF_TARGET_NONE 0 +#define GCM_SURFACE_TARGET_NONE 0 /*! \brief Render target 0 */ -#define GCM_TF_TARGET_0 1 +#define GCM_SURFACE_TARGET_0 1 /*! \brief Render target 1 */ -#define GCM_TF_TARGET_1 2 +#define GCM_SURFACE_TARGET_1 2 /*! \brief Render target 0 and 1 */ -#define GCM_TF_TARGET_MRT1 0x13 +#define GCM_SURFACE_TARGET_MRT1 0x13 /*! \brief Render target 0,1 and 2 */ -#define GCM_TF_TARGET_MRT2 0x17 +#define GCM_SURFACE_TARGET_MRT2 0x17 /*! \brief Render target 0,1,2 and 3 */ -#define GCM_TF_TARGET_MRT3 0x1f +#define GCM_SURFACE_TARGET_MRT3 0x1f /*! \brief Do not use multiple samples. */ -#define GCM_TF_CENTER_1 0 +#define GCM_SURFACE_CENTER_1 0 +#define GCM_SURFACE_DIAGONAL_CENTERED_2 3 +#define GCM_SURFACE_SQUARE_CENTERED_4 4 +#define GCM_SURFACE_SQUARE_ROTATED_4 5 /*! \brief blue color component */ -#define GCM_COLOR_MASK_B 0x00000001 +#define GCM_COLOR_MASK_B 0x00000001 /*! \brief green color component */ -#define GCM_COLOR_MASK_G 0x00000100 +#define GCM_COLOR_MASK_G 0x00000100 /*! \brief red color component */ -#define GCM_COLOR_MASK_R 0x00010000 +#define GCM_COLOR_MASK_R 0x00010000 /*! \brief alpha component */ -#define GCM_COLOR_MASK_A 0x01000000 +#define GCM_COLOR_MASK_A 0x01000000 + +#define GCM_COLOR_MASK_MRT1_A 0x00000010 +#define GCM_COLOR_MASK_MRT1_R 0x00000020 +#define GCM_COLOR_MASK_MRT1_G 0x00000040 +#define GCM_COLOR_MASK_MRT1_B 0x00000080 +#define GCM_COLOR_MASK_MRT2_A 0x00000100 +#define GCM_COLOR_MASK_MRT2_R 0x00000200 +#define GCM_COLOR_MASK_MRT2_G 0x00000400 +#define GCM_COLOR_MASK_MRT2_B 0x00000800 +#define GCM_COLOR_MASK_MRT3_A 0x00001000 +#define GCM_COLOR_MASK_MRT3_R 0x00002000 +#define GCM_COLOR_MASK_MRT3_G 0x00004000 +#define GCM_COLOR_MASK_MRT3_B 0x00008000 /*! \brief clear the Z buffer (depth buffer) */ -#define GCM_CLEAR_Z 0x01 +#define GCM_CLEAR_Z 0x01 /*! \brief clear the stencil buffer */ -#define GCM_CLEAR_S 0x02 +#define GCM_CLEAR_S 0x02 /*! \brief clear the red components */ -#define GCM_CLEAR_R 0x10 +#define GCM_CLEAR_R 0x10 /*! \brief clear the green components */ -#define GCM_CLEAR_G 0x20 +#define GCM_CLEAR_G 0x20 /*! \brief clear the blue components */ -#define GCM_CLEAR_B 0x40 +#define GCM_CLEAR_B 0x40 /*! \brief clear the alpha components */ -#define GCM_CLEAR_A 0x80 +#define GCM_CLEAR_A 0x80 /*! \brief clear all RGBA components, Z buffer and stencil buffer */ -#define GCM_CLEAR_M 0xf3 +#define GCM_CLEAR_M 0xf3 /*! \brief depth test never passes. */ -#define GCM_NEVER 0x0200 +#define GCM_NEVER 0x0200 /*! \brief depth test passes if the incoming depth value is less than the stored depth value. */ -#define GCM_LESS 0x0201 +#define GCM_LESS 0x0201 /*! \brief depth test passes if the incoming depth value is equal to the stored depth value. */ -#define GCM_EQUAL 0x0202 +#define GCM_EQUAL 0x0202 /*! \brief depth test passes if the incoming depth value is less than or equal to the stored depth value. */ -#define GCM_LEQUAL 0x0203 +#define GCM_LEQUAL 0x0203 /*! \brief depth test passes if the incoming depth value is greater than the stored depth value. */ -#define GCM_GREATER 0x0204 +#define GCM_GREATER 0x0204 /*! \brief depth test passes if the incoming depth value is not equal to the stored depth value. */ -#define GCM_NOTEQUAL 0x0205 +#define GCM_NOTEQUAL 0x0205 /*! \brief depth test passes if the incoming depth value is greater than or equal to the stored depth value. */ -#define GCM_GEQUAL 0x0206 +#define GCM_GEQUAL 0x0206 /*! \brief depth test always passes. */ -#define GCM_ALWAYS 0x0207 +#define GCM_ALWAYS 0x0207 /*! \brief culling of front face */ -#define GCM_CULL_FRONT 0x0404 +#define GCM_CULL_FRONT 0x0404 /*! \brief culling of back face */ -#define GCM_CULL_BACK 0x0405 +#define GCM_CULL_BACK 0x0405 /*! \brief culling of front and back faces */ -#define GCM_CULL_ALL 0x0408 +#define GCM_CULL_ALL 0x0408 + +/*! \brief render the polygon by points */ +#define GCM_POLYGON_MODE_POINT 0x1b00 +/*! \brief render the polygon by lines */ +#define GCM_POLYGON_MODE_LINE 0x1b01 +/*! \brief render the polygon by filling */ +#define GCM_POLYGON_MODE_FILL 0x1b02 /*! \brief front face is to be drawn clock wise */ -#define GCM_FRONTFACE_CW 0x0900 +#define GCM_FRONTFACE_CW 0x0900 /*! \brief front face is to be drawn counter clock wise */ -#define GCM_FRONTFACE_CCW 0x0901 +#define GCM_FRONTFACE_CCW 0x0901 + +#define GCM_CLEAR 0x1500 +#define GCM_AND 0x1501 +#define GCM_AND_REVERSE 0x1502 +#define GCM_COPY 0x1503 +#define GCM_AND_INVERTED 0x1504 +#define GCM_NOOP 0x1505 +#define GCM_XOR 0x1506 +#define GCM_OR 0x1507 +#define GCM_NOR 0x1508 +#define GCM_EQUIV 0x1509 +#define GCM_INVERT 0x150A +#define GCM_OR_REVERSE 0x150B +#define GCM_COPY_INVERTED 0x150C +#define GCM_OR_INVERTED 0x150D +#define GCM_NAND 0x150E +#define GCM_SET 0x150F + +/*! \brief keep current stencil buffer value */ +#define GCM_KEEP 0x1E00 +/*! \brief set stencil buffer value to 0 */ +#define GCM_REPLACE 0x1E01 +/*! \brief increment current stencil buffer value. clamp to 255 */ +#define GCM_INCR 0x1E02 +/*! \brief decrement current stencil buffer value. clamp to 0 */ +#define GCM_DECR 0x1E03 +/*! \brief increment current stencil buffer value. when incrementing a stencil value of 255, wrap around to 0 */ +#define GCM_INCR_WRAP 0x8507 +/*! \brief decrement current stencil buffer value. when decrementing a stencil value of 0, wrap around to 255 */ +#define GCM_DECR_WRAP 0x8508 /*! \brief render POINTS primitive */ -#define GCM_TYPE_POINTS 1 +#define GCM_TYPE_POINTS 1 /*! \brief render LINES primitive */ -#define GCM_TYPE_LINES 2 +#define GCM_TYPE_LINES 2 /*! \brief render LINE_LOOP primitive */ -#define GCM_TYPE_LINE_LOOP 3 +#define GCM_TYPE_LINE_LOOP 3 /*! \brief render LINE_STRIP primitive */ -#define GCM_TYPE_LINE_STRIP 4 +#define GCM_TYPE_LINE_STRIP 4 /*! \brief render TRIANGLES primitive */ -#define GCM_TYPE_TRIANGLES 5 +#define GCM_TYPE_TRIANGLES 5 /*! \brief render TRIANGLE_STRIP primitive */ -#define GCM_TYPE_TRIANGLE_STRIP 6 +#define GCM_TYPE_TRIANGLE_STRIP 6 /*! \brief render TRIANGLE_FAN primitive */ -#define GCM_TYPE_TRIANGLE_FAN 7 +#define GCM_TYPE_TRIANGLE_FAN 7 /*! \brief render QUADS primitive */ -#define GCM_TYPE_QUADS 8 +#define GCM_TYPE_QUADS 8 /*! \brief render QUAD_STRIP primitive */ -#define GCM_TYPE_QUAD_STRIP 9 +#define GCM_TYPE_QUAD_STRIP 9 /*! \brief render POLYGON primitive */ -#define GCM_TYPE_POLYGON 10 +#define GCM_TYPE_POLYGON 10 /*! \brief invalidate texture cache for fragment programs */ -#define GCM_INVALIDATE_TEXTURE 1 +#define GCM_INVALIDATE_TEXTURE 1 /*! \brief invalidate texture cache for vertex programs */ -#define GCM_INVALIDATE_VERTEX_TEXTURE 2 +#define GCM_INVALIDATE_VERTEX_TEXTURE 2 /*! \brief texture is 1D. */ -#define GCM_TEXTURE_DIMS_1D 1 +#define GCM_TEXTURE_DIMS_1D 1 /*! \brief texture is 2D. */ -#define GCM_TEXTURE_DIMS_2D 2 +#define GCM_TEXTURE_DIMS_2D 2 /*! \brief texture is 3D. */ -#define GCM_TEXTURE_DIMS_3D 3 - -#define GCM_TEXTURE_FORMAT_SWZ 0x00 -#define GCM_TEXTURE_FORMAT_LIN 0x20 -#define GCM_TEXTURE_FORMAT_NRM 0x40 - -#define GCM_TEXTURE_FORMAT_L8 1 -#define GCM_TEXTURE_FORMAT_A1R5G5B5 2 -#define GCM_TEXTURE_FORMAT_A4R4G4B4 3 -#define GCM_TEXTURE_FORMAT_R5G6B5 4 -#define GCM_TEXTURE_FORMAT_A8R8G8B8 5 -#define GCM_TEXTURE_FORMAT_DXT1 6 -#define GCM_TEXTURE_FORMAT_DXT3 7 -#define GCM_TEXTURE_FORMAT_DXT5 8 -#define GCM_TEXTURE_FORMAT_A8L8 24 +#define GCM_TEXTURE_DIMS_3D 3 + +/*! \brief texture uses swizzle format */ +#define GCM_TEXTURE_FORMAT_SWZ 0x00 +/*! \brief texture uses linear format */ +#define GCM_TEXTURE_FORMAT_LIN 0x20 +/*! \brief texture uses normalized texture coordinates */ +#define GCM_TEXTURE_FORMAT_NRM 0x00 +/*! \brief texture uses unnormalized texture coordinates */ +#define GCM_TEXTURE_FORMAT_UNRM 0x40 + +/*! \brief texture color format is 8-bit unsigned integer */ +#define GCM_TEXTURE_FORMAT_B8 1 +/*! \brief texture color format is 1-bit alpha and three 5-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_A1R5G5B5 2 +/*! \brief texture color format is four 4-bit unsigned values */ +#define GCM_TEXTURE_FORMAT_A4R4G4B4 3 +/*! \brief texture color format is 5-bit, 6-bit and 5-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_R5G6B5 4 +/*! \brief texture color format is four 8-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_A8R8G8B8 5 +/*! \brief texture color format is 4x4 pixels compressed to 8 bytes */ +#define GCM_TEXTURE_FORMAT_DXT1 6 +/*! \brief texture color format is 4x4 pixels compressed to 16 bytes */ +#define GCM_TEXTURE_FORMAT_DXT23 7 +/*! \brief texture color format is 4x4 pixels compressed to 16 bytes */ +#define GCM_TEXTURE_FORMAT_DXT45 8 +/*! \brief texture color format is two 8-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_G8B8 11 +/*! \brief texture color format is 6-bit, 5-bit and 5-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_R6G5B5 15 +/*! \brief texture color format is 24-bit fixed and 8-bit dummy data */ +#define GCM_TEXTURE_FORMAT_DEPTH24_D8 16 +/*! \brief texture color format is 24-bit float and 8-bit dummy data */ +#define GCM_TEXTURE_FORMAT_DEPTH24_D8_FLOAT 17 +/*! \brief texture color format is 16-bit fixed */ +#define GCM_TEXTURE_FORMAT_DEPTH16 18 +/*! \brief texture color format is 16-bit float */ +#define GCM_TEXTURE_FORMAT_DEPTH16_FLOAT 19 +/*! \brief texture color format is 16-bit integer */ +#define GCM_TEXTURE_FORMAT_X16 20 +/*! \brief texture color format is two 16-bit integers */ +#define GCM_TEXTURE_FORMAT_Y16_X16 21 +/*! \brief texture color format is three 5-bit unsigned integers and one 1-bit value */ +#define GCM_TEXTURE_FORMAT_R5G6B5A1 23 +/*! \brief texture color format is two 16-bit unsigned values compressed to two 8-bit values */ +#define GCM_TEXTURE_FORMAT_COMPRESSED_HILO8 24 +/*! \brief texture color format is two 16-bit signed values compressed to two 8-bit values */ +#define GCM_TEXTURE_FORMAT_COMPRESSED_HILO8_S8 25 +/*! \brief texture color format is four 16-bit float values */ +#define GCM_TEXTURE_FORMAT_W16_Z16_Y16_X16_FLOAT 26 +/*! \brief texture color format is four 32-bit float values */ +#define GCM_TEXTURE_FORMAT_W32_Z32_Y32_X32_FLOAT 27 +/*! \brief texture color format is one 32-bit float value */ +#define GCM_TEXTURE_FORMAT_X32_FLOAT 28 +/*! \brief texture color format is 1-bit dummy data and 5-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_D1R5G5B5 29 +/*! \brief texture color format is 8-bit dummy data and 8-bit unsigned integers */ +#define GCM_TEXTURE_FORMAT_D8R8G8B8 30 +/*! \brief texture color format is two 16-bit float values */ +#define GCM_TEXTURE_FORMAT_Y16_X16_FLOAT 31 +/*! \brief texture color format is two pixels compressed to 32 bits in YUV format */ +#define GCM_TEXTURE_FORMAT_COMPRESSED_B8R8_G8R8 45 +/*! \brief texture color format is two pixels compressed to 32 bits in YUV format */ +#define GCM_TEXTURE_FORMAT_COMPRESSED_R8B8_R8G8 46 + /*! \brief shift value for texture remapping type corresponding to the blue component */ -#define GCM_TEXTURE_REMAP_TYPE_B_SHIFT 14 +#define GCM_TEXTURE_REMAP_TYPE_B_SHIFT 14 /*! \brief shift value for texture remapping type corresponding to the green component */ -#define GCM_TEXTURE_REMAP_TYPE_G_SHIFT 12 +#define GCM_TEXTURE_REMAP_TYPE_G_SHIFT 12 /*! \brief shift value for texture remapping type corresponding to the red component */ -#define GCM_TEXTURE_REMAP_TYPE_R_SHIFT 10 +#define GCM_TEXTURE_REMAP_TYPE_R_SHIFT 10 /*! \brief shift value for texture remapping type corresponding to the alpha component */ -#define GCM_TEXTURE_REMAP_TYPE_A_SHIFT 8 +#define GCM_TEXTURE_REMAP_TYPE_A_SHIFT 8 /*! \brief shift value for texture remapping component color corresponding to the blue component */ -#define GCM_TEXTURE_REMAP_COLOR_B_SHIFT 6 +#define GCM_TEXTURE_REMAP_COLOR_B_SHIFT 6 /*! \brief shift value for texture remapping component color corresponding to the green component */ -#define GCM_TEXTURE_REMAP_COLOR_G_SHIFT 4 +#define GCM_TEXTURE_REMAP_COLOR_G_SHIFT 4 /*! \brief shift value for texture remapping component color corresponding to the red component */ -#define GCM_TEXTURE_REMAP_COLOR_R_SHIFT 2 +#define GCM_TEXTURE_REMAP_COLOR_R_SHIFT 2 /*! \brief shift value for texture remapping component color corresponding to the alpha component */ -#define GCM_TEXTURE_REMAP_COLOR_A_SHIFT 0 +#define GCM_TEXTURE_REMAP_COLOR_A_SHIFT 0 /*! \brief remap component to all zero bits */ -#define GCM_TEXTURE_REMAP_TYPE_ZERO 0 +#define GCM_TEXTURE_REMAP_TYPE_ZERO 0 /*! \brief remap component to all one bits */ -#define GCM_TEXTURE_REMAP_TYPE_ONE 1 +#define GCM_TEXTURE_REMAP_TYPE_ONE 1 /*! \brief remap component to specified component */ -#define GCM_TEXTURE_REMAP_TYPE_REMAP 2 +#define GCM_TEXTURE_REMAP_TYPE_REMAP 2 /*! \brief remap component to alpha component */ -#define GCM_TEXTURE_REMAP_COLOR_A 0 +#define GCM_TEXTURE_REMAP_COLOR_A 0 /*! \brief remap component to red component */ -#define GCM_TEXTURE_REMAP_COLOR_R 1 +#define GCM_TEXTURE_REMAP_COLOR_R 1 /*! \brief remap component to green component */ -#define GCM_TEXTURE_REMAP_COLOR_G 2 +#define GCM_TEXTURE_REMAP_COLOR_G 2 /*! \brief remap component to blue component */ -#define GCM_TEXTURE_REMAP_COLOR_B 3 +#define GCM_TEXTURE_REMAP_COLOR_B 3 /*! \brief x1 sample */ -#define GCM_TEXTURE_MAX_ANISO_1 0 +#define GCM_TEXTURE_MAX_ANISO_1 0 /*! \brief x2 sample */ -#define GCM_TEXTURE_MAX_ANISO_2 1 +#define GCM_TEXTURE_MAX_ANISO_2 1 /*! \brief x4 sample */ -#define GCM_TEXTURE_MAX_ANISO_4 2 +#define GCM_TEXTURE_MAX_ANISO_4 2 /*! \brief x6 sample */ -#define GCM_TEXTURE_MAX_ANISO_6 3 +#define GCM_TEXTURE_MAX_ANISO_6 3 /*! \brief x8 sample */ -#define GCM_TEXTURE_MAX_ANISO_8 4 +#define GCM_TEXTURE_MAX_ANISO_8 4 /*! \brief x10 sample */ -#define GCM_TEXTURE_MAX_ANISO_10 5 +#define GCM_TEXTURE_MAX_ANISO_10 5 /*! \brief x12 sample */ -#define GCM_TEXTURE_MAX_ANISO_12 6 +#define GCM_TEXTURE_MAX_ANISO_12 6 /*! \brief x16 sample */ -#define GCM_TEXTURE_MAX_ANISO_16 7 - -#define GCM_TEXTURE_NEAREST 1 -#define GCM_TEXTURE_LINEAR 2 -#define GCM_TEXTURE_NEAREST_MIPMAP_NEAREST 3 -#define GCM_TEXTURE_LINEAR_MIPMAP_NEAREST 4 -#define GCM_TEXTURE_NEAREST_MIPMAP_LINEAR 5 -#define GCM_TEXTURE_LINEAR_MIPMAP_LINEAR 6 - -#define GCM_TEXTURE_CONVOLUTION_QUINCUNX 1 -#define GCM_TEXTURE_CONVOLUTION_GAUSSIAN 2 -#define GCM_TEXTURE_CONVOLUTION_QUINCUNX_ALT 3 - -#define GCM_TEXTURE_REPEAT 1 -#define GCM_TEXTURE_MIRRORED_REPEAT 2 -#define GCM_TEXTURE_CLAMP_TO_EDGE 3 -#define GCM_TEXTURE_CLAMP_TO_BORDER 4 -#define GCM_TEXTURE_CLAMP 5 -#define GCM_TEXTURE_MIRROR_CLAMP_TO_EDGE 6 -#define GCM_TEXTURE_MIRROR_CLAMP_TO_BORDER 7 -#define GCM_TEXTURE_MIRROR_CLAMP 8 - -#define GCM_TEXTURE_ZFUNC_NEVER 0 -#define GCM_TEXTURE_ZFUNC_LESS 1 -#define GCM_TEXTURE_ZFUNC_EQUAL 2 -#define GCM_TEXTURE_ZFUNC_LEQUAL 3 -#define GCM_TEXTURE_ZFUNC_GREATER 4 -#define GCM_TEXTURE_ZFUNC_NOTEQUAL 5 -#define GCM_TEXTURE_ZFUNC_GEQUAL 6 -#define GCM_TEXTURE_ZFUNC_ALWAYS 7 - -#define GCM_VERTEX_ATTRIB_POS 0 -#define GCM_VERTEX_ATTRIB_WEIGHT 1 -#define GCM_VERTEX_ATTRIB_NORMAL 2 -#define GCM_VERTEX_ATTRIB_COLOR0 3 -#define GCM_VERTEX_ATTRIB_COLOR1 4 -#define GCM_VERTEX_ATTRIB_FOG 5 -#define GCM_VERTEX_ATTRIB_COLOR_INDEX 6 -#define GCM_VERTEX_ATTRIB_POINT_SIZE 6 /*alias*/ -#define GCM_VERTEX_ATTRIB_EDGEFLAG 7 -#define GCM_VERTEX_ATTRIB_TEX0 8 -#define GCM_VERTEX_ATTRIB_TEX1 9 -#define GCM_VERTEX_ATTRIB_TEX2 10 -#define GCM_VERTEX_ATTRIB_TEX3 11 -#define GCM_VERTEX_ATTRIB_TEX4 12 -#define GCM_VERTEX_ATTRIB_TEX5 13 -#define GCM_VERTEX_ATTRIB_TEX6 14 -#define GCM_VERTEX_ATTRIB_TEX7 15 - -#define GCM_VERTEX_DATA_TYPE_F32 2 -#define GCM_VERTEX_DATA_TYPE_U8 4 - -#define GCM_INDEX_TYPE_32B 0 -#define GCM_INDEX_TYPE_16B 1 - -#define GCM_USER_CLIP_PLANE_DISABLE 0 -#define GCM_USER_CLIP_PLANE_LT 1 -#define GCM_USER_CLIP_PLANE_GE 2 +#define GCM_TEXTURE_MAX_ANISO_16 7 + +#define GCM_FOG_MODE_LINEAR 0x2601 +#define GCM_FOG_MODE_EXP 0x0800 +#define GCM_FOG_MODE_EXP2 0x0801 +#define GCM_FOG_MODE_EXP_ABS 0x0802 +#define GCM_FOG_MODE_EXP2_ABS 0x0803 +#define GCM_FOG_MODE_LINEAR_ABS 0x0804 + +#define GCM_POINT_SPRITE_TEX0 (1<<8) +#define GCM_POINT_SPRITE_TEX1 (1<<9) +#define GCM_POINT_SPRITE_TEX2 (1<<10) +#define GCM_POINT_SPRITE_TEX3 (1<<11) +#define GCM_POINT_SPRITE_TEX4 (1<<12) +#define GCM_POINT_SPRITE_TEX5 (1<<13) +#define GCM_POINT_SPRITE_TEX6 (1<<14) +#define GCM_POINT_SPRITE_TEX7 (1<<15) +#define GCM_POINT_SPRITE_TEX8 (1<<16) +#define GCM_POINT_SPRITE_TEX9 (1<<17) + +#define GCM_POINT_SPRITE_RMODE_ZERO 0 +#define GCM_POINT_SPRITE_RMODE_FROM_R 1 +#define GCM_POINT_SPRITE_RMODE_FROM_S 2 + +#define GCM_TEXTURE_NEAREST 1 +#define GCM_TEXTURE_LINEAR 2 +#define GCM_TEXTURE_NEAREST_MIPMAP_NEAREST 3 +#define GCM_TEXTURE_LINEAR_MIPMAP_NEAREST 4 +#define GCM_TEXTURE_NEAREST_MIPMAP_LINEAR 5 +#define GCM_TEXTURE_LINEAR_MIPMAP_LINEAR 6 +#define GCM_TEXTURE_CONVOLUTUIN_MIN 7 +#define GCM_TEXTURE_CONVOLUTUIN_MAG 4 + +#define GCM_TEXTURE_CONVOLUTION_QUINCUNX 1 +#define GCM_TEXTURE_CONVOLUTION_GAUSSIAN 2 +#define GCM_TEXTURE_CONVOLUTION_QUINCUNX_ALT 3 + +#define GCM_TEXTURE_REPEAT 1 +#define GCM_TEXTURE_MIRRORED_REPEAT 2 +#define GCM_TEXTURE_CLAMP_TO_EDGE 3 +#define GCM_TEXTURE_BORDER 4 +#define GCM_TEXTURE_CLAMP 5 +#define GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_EDGE 6 +#define GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_BORDER 7 +#define GCM_TEXTURE_MIRROR_ONCE_CLAMP 8 + +#define GCM_TEXTURE_UNSIGNED_REMAP_NORMAL 0 +#define GCM_TEXTURE_UNSIGNED_REMAP_BIASED 1 + +#define GCM_TEXTURE_GAMMA_R (1<<0) +#define GCM_TEXTURE_GAMMA_G (1<<1) +#define GCM_TEXTURE_GAMMA_B (1<<2) +#define GCM_TEXTURE_GAMMA_A (1<<3) + +#define GCM_TEXTURE_ZFUNC_NEVER 0 +#define GCM_TEXTURE_ZFUNC_LESS 1 +#define GCM_TEXTURE_ZFUNC_EQUAL 2 +#define GCM_TEXTURE_ZFUNC_LEQUAL 3 +#define GCM_TEXTURE_ZFUNC_GREATER 4 +#define GCM_TEXTURE_ZFUNC_NOTEQUAL 5 +#define GCM_TEXTURE_ZFUNC_GEQUAL 6 +#define GCM_TEXTURE_ZFUNC_ALWAYS 7 + +#define GCM_TEXTURE_ISO_LOW 0 +#define GCM_TEXTURE_ISO_HIGH 1 + +#define GCM_TEXTURE_ANISO_LOW 0 +#define GCM_TEXTURE_ANISO_HIGH 1 + +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX0_U (1<<0) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX0_V (1<<1) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX0_P (1<<2) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX0_Q (1<<3) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX1_U (1<<4) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX1_V (1<<5) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX1_P (1<<6) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX1_Q (1<<7) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX2_U (1<<8) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX2_V (1<<9) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX2_P (1<<10) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX2_Q (1<<11) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX3_U (1<<12) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX3_V (1<<13) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX3_P (1<<14) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX3_Q (1<<15) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX4_U (1<<16) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX4_V (1<<17) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX4_P (1<<18) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX4_Q (1<<19) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX5_U (1<<20) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX5_V (1<<21) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX5_P (1<<22) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX5_Q (1<<23) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX6_U (1<<24) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX6_V (1<<25) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX6_P (1<<26) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX6_Q (1<<27) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_U (1<<28) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_V (1<<29) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_P (1<<30) +#define GCM_TEXTURE_CYLINDRICAL_WRAP_ENABLE_TEX7_Q (1<<31) + +#define GCM_VERTEX_ATTRIB_POS 0 +#define GCM_VERTEX_ATTRIB_WEIGHT 1 +#define GCM_VERTEX_ATTRIB_NORMAL 2 +#define GCM_VERTEX_ATTRIB_COLOR0 3 +#define GCM_VERTEX_ATTRIB_COLOR1 4 +#define GCM_VERTEX_ATTRIB_FOG 5 +#define GCM_VERTEX_ATTRIB_COLOR_INDEX 6 +#define GCM_VERTEX_ATTRIB_POINT_SIZE 6 /*alias*/ +#define GCM_VERTEX_ATTRIB_EDGEFLAG 7 +#define GCM_VERTEX_ATTRIB_TEX0 8 +#define GCM_VERTEX_ATTRIB_TEX1 9 +#define GCM_VERTEX_ATTRIB_TEX2 10 +#define GCM_VERTEX_ATTRIB_TEX3 11 +#define GCM_VERTEX_ATTRIB_TEX4 12 +#define GCM_VERTEX_ATTRIB_TEX5 13 +#define GCM_VERTEX_ATTRIB_TEX6 14 +#define GCM_VERTEX_ATTRIB_TANGENT 14 /*alias*/ +#define GCM_VERTEX_ATTRIB_TEX7 15 +#define GCM_VERTEX_ATTRIB_BINORMAL 15 /*alias*/ + +#define GCM_VERTEX_DATA_TYPE_F32 2 +#define GCM_VERTEX_DATA_TYPE_U8 4 + +#define GCM_INDEX_TYPE_32B 0 +#define GCM_INDEX_TYPE_16B 1 + +#define GCM_USER_CLIP_PLANE_DISABLE 0 +#define GCM_USER_CLIP_PLANE_LT 1 +#define GCM_USER_CLIP_PLANE_GE 2 + +#define GCM_ATTRIB_OUTPUT_MASK_FRONTDIFFUSE (1<< 0) +#define GCM_ATTRIB_OUTPUT_MASK_FRONTSPECULAR (1<< 1) +#define GCM_ATTRIB_OUTPUT_MASK_BACKDIFFUSE (1<< 2) +#define GCM_ATTRIB_OUTPUT_MASK_BACKSPECULAR (1<< 3) +#define GCM_ATTRIB_OUTPUT_MASK_FOG (1<< 4) +#define GCM_ATTRIB_OUTPUT_MASK_POINTSIZE (1<< 5) +#define GCM_ATTRIB_OUTPUT_MASK_UC0 (1<< 6) +#define GCM_ATTRIB_OUTPUT_MASK_UC1 (1<< 7) +#define GCM_ATTRIB_OUTPUT_MASK_UC2 (1<< 8) +#define GCM_ATTRIB_OUTPUT_MASK_UC3 (1<< 9) +#define GCM_ATTRIB_OUTPUT_MASK_UC4 (1<<10) +#define GCM_ATTRIB_OUTPUT_MASK_UC5 (1<<11) +#define GCM_ATTRIB_OUTPUT_MASK_TEX8 (1<<12) +#define GCM_ATTRIB_OUTPUT_MASK_TEX9 (1<<13) +#define GCM_ATTRIB_OUTPUT_MASK_TEX0 (1<<14) +#define GCM_ATTRIB_OUTPUT_MASK_TEX1 (1<<15) +#define GCM_ATTRIB_OUTPUT_MASK_TEX2 (1<<16) +#define GCM_ATTRIB_OUTPUT_MASK_TEX3 (1<<17) +#define GCM_ATTRIB_OUTPUT_MASK_TEX4 (1<<18) +#define GCM_ATTRIB_OUTPUT_MASK_TEX5 (1<<19) +#define GCM_ATTRIB_OUTPUT_MASK_TEX6 (1<<20) +#define GCM_ATTRIB_OUTPUT_MASK_TEX7 (1<<21) /*! \brief Flat shading */ -#define GCM_SHADE_MODEL_FLAT 0x1D00 +#define GCM_SHADE_MODEL_FLAT 0x1D00 /*! \brief Smooth shading */ -#define GCM_SHADE_MODEL_SMOOTH 0x1D01 +#define GCM_SHADE_MODEL_SMOOTH 0x1D01 /*! \brief blend factors are zero */ -#define GCM_ZERO 0 +#define GCM_ZERO 0 /*! \brief blend factors are one */ -#define GCM_ONE 1 +#define GCM_ONE 1 /*! \brief blend factors are the source color components */ -#define GCM_SRC_COLOR 0x0300 +#define GCM_SRC_COLOR 0x0300 /*! \brief blend factors are one minus source color components */ -#define GCM_ONE_MINUS_SRC_COLOR 0x0301 +#define GCM_ONE_MINUS_SRC_COLOR 0x0301 /*! \brief blend factors are the source alpha component */ -#define GCM_SRC_ALPHA 0x0302 +#define GCM_SRC_ALPHA 0x0302 /*! \brief blend factors are one minus the source alpha component */ -#define GCM_ONE_MINUS_SRC_ALPHA 0x0303 +#define GCM_ONE_MINUS_SRC_ALPHA 0x0303 /*! \brief blend factors are the destination alpha component */ -#define GCM_DST_ALPHA 0x0304 +#define GCM_DST_ALPHA 0x0304 /*! \brief blend factors are one minus the destination alpha component */ -#define GCM_ONE_MINUS_DST_ALPHA 0x0305 +#define GCM_ONE_MINUS_DST_ALPHA 0x0305 /*! \brief blend factors are the destination color components */ -#define GCM_DST_COLOR 0x0306 +#define GCM_DST_COLOR 0x0306 /*! \brief blend factors are one minus the destination color components */ -#define GCM_ONE_MINUS_DST_COLOR 0x0307 +#define GCM_ONE_MINUS_DST_COLOR 0x0307 /*! \brief blend factors are set to saturate the output */ -#define GCM_SRC_ALPHA_SATURATE 0x0308 +#define GCM_SRC_ALPHA_SATURATE 0x0308 /*! \brief blend factors are the constant color components */ -#define GCM_CONSTANT_COLOR 0x8001 +#define GCM_CONSTANT_COLOR 0x8001 /*! \brief blend factors are one minus the constant color components */ -#define GCM_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GCM_ONE_MINUS_CONSTANT_COLOR 0x8002 /*! \brief blend factors are the constant color alpha component */ -#define GCM_CONSTANT_ALPHA 0x8003 +#define GCM_CONSTANT_ALPHA 0x8003 /*! \brief blend factors are one minus the constant color alpha component */ -#define GCM_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GCM_ONE_MINUS_CONSTANT_ALPHA 0x8004 /*! \brief use scaled source plus destination */ -#define GCM_FUNC_ADD 0x8006 +#define GCM_FUNC_ADD 0x8006 /*! \brief use the minimum of source and destination color components */ -#define GCM_MIN 0x8007 +#define GCM_FUNC_MIN 0x8007 /*! \brief use the maximum of source and destination color components */ -#define GCM_MAX 0x8008 +#define GCM_FUNC_MAX 0x8008 /*! \brief use scaled source minus destination */ -#define GCM_FUNC_SUBTRACT 0x800a +#define GCM_FUNC_SUBTRACT 0x800a /*! \brief use scaled destination minus source */ -#define GCM_FUNC_REVERSE_SUBTRACT 0x800b +#define GCM_FUNC_REVERSE_SUBTRACT 0x800b /*! \brief use scaled destination minus source (signed) */ -#define GCM_FUNC_REVERSE_SUBTRACT_SIGNED 0xf005 +#define GCM_FUNC_REVERSE_SUBTRACT_SIGNED 0xf005 /*! \brief use scaled source plus destination (signed) */ -#define GCM_FUNC_ADD_SIGNED 0xf006 +#define GCM_FUNC_ADD_SIGNED 0xf006 /*! \brief use scaled destination plus source (signed) */ -#define GCM_FUNC_REVERSE_ADD_SIGNED 0xf007 +#define GCM_FUNC_REVERSE_ADD_SIGNED 0xf007 -#define GCM_TRANSFER_SURFACE 0 -#define GCM_TRANSFER_SWIZZLE 1 +#define GCM_TRANSFER_SURFACE 0 +#define GCM_TRANSFER_SWIZZLE 1 /*! \brief Convert pixel component values using dithering. */ -#define GCM_TRANSFER_CONVERSION_DITHER 0 +#define GCM_TRANSFER_CONVERSION_DITHER 0 /*! \brief Convert pixel component values by truncation (\em ie, ignore lower bits). */ -#define GCM_TRANSFER_CONVERSION_TRUNCATE 1 +#define GCM_TRANSFER_CONVERSION_TRUNCATE 1 /*! \brief Convert pixel component values by subtraction/truncation. */ -#define GCM_TRANSFER_CONVERSION_SUBTRACT_TRUNCATE 2 +#define GCM_TRANSFER_CONVERSION_SUBTRACT_TRUNCATE 2 /*! \brief Pixel format is 1-bit alpha, 5-bit red, 5-bit green, 5-bit blue */ -#define GCM_TRANSFER_SCALE_FORMAT_A1R5G5B5 1 +#define GCM_TRANSFER_SCALE_FORMAT_A1R5G5B5 1 /*! \brief Pixel format is 1-bit unused, 5-bit red, 5-bit green, 5-bit blue */ -#define GCM_TRANSFER_SCALE_FORMAT_X1R5G5B5 2 +#define GCM_TRANSFER_SCALE_FORMAT_X1R5G5B5 2 /*! \brief Pixel format is 8-bit alpha, 8-bit red, 8-bit green, 8-bit blue */ -#define GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 3 +#define GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 3 /*! \brief Pixel format is 8-bit unused, 8-bit red, 8-bit green, 8-bit blue */ -#define GCM_TRANSFER_SCALE_FORMAT_X8R8G8B8 4 +#define GCM_TRANSFER_SCALE_FORMAT_X8R8G8B8 4 /*! \brief Pixel format is 8-bit red chrominance, 8-bit luminance, 8-bit blue chrominance, 8-bit alpha */ -#define GCM_TRANSFER_SCALE_FORMAT_CR8YB8CB8YA8 5 +#define GCM_TRANSFER_SCALE_FORMAT_CR8YB8CB8YA8 5 /*! \brief Pixel format is 8-bit luminance, 8-bit red chrominance, 8-bit alpha, 8-bit blue chrominance */ -#define GCM_TRANSFER_SCALE_FORMAT_YB8CR8YA8CB8 6 +#define GCM_TRANSFER_SCALE_FORMAT_YB8CR8YA8CB8 6 /*! \brief Pixel format is 5-bit red, 6-bit green, 5-bit blue */ -#define GCM_TRANSFER_SCALE_FORMAT_R5G6B5 7 +#define GCM_TRANSFER_SCALE_FORMAT_R5G6B5 7 /*! \brief Pixel format is 8-bit grayscale */ -#define GCM_TRANSFER_SCALE_FORMAT_Y8 8 +#define GCM_TRANSFER_SCALE_FORMAT_Y8 8 /*! \brief Pixel format is 8-bit alpha */ -#define GCM_TRANSFER_SCALE_FORMAT_AY8 9 +#define GCM_TRANSFER_SCALE_FORMAT_AY8 9 /*! \brief Pixel format is EYB8ECR8EYA8ECB8 */ -#define GCM_TRANSFER_SCALE_FORMAT_EYB8ECR8EYA8ECB8 0xa +#define GCM_TRANSFER_SCALE_FORMAT_EYB8ECR8EYA8ECB8 0xa /*! \brief Pixel format is ECR8EYB8ECB8EYA8 */ -#define GCM_TRANSFER_SCALE_FORMAT_ECR8EYB8ECB8EYA8 0xb +#define GCM_TRANSFER_SCALE_FORMAT_ECR8EYB8ECB8EYA8 0xb /*! \brief Pixel format is 8-bit alpha, 8-bit blue, 8-bit green, 8-bit red */ -#define GCM_TRANSFER_SCALE_FORMAT_A8B8G8R8 0xc +#define GCM_TRANSFER_SCALE_FORMAT_A8B8G8R8 0xc /*! \brief Pixel format is 8-bit unused, 8-bit blue, 8-bit green, 8-bit red */ -#define GCM_TRANSFER_SCALE_FORMAT_X8B8G8R8 0xd +#define GCM_TRANSFER_SCALE_FORMAT_X8B8G8R8 0xd /*! \brief Copy source image, perform logical \c AND with destination. */ -#define GCM_TRANSFER_OPERATION_SRCCOPY_AND 0 +#define GCM_TRANSFER_OPERATION_SRCCOPY_AND 0 /*! \brief Perform ROP (raster operation), and logical \c AND with destination. */ -#define GCM_TRANSFER_OPERATION_ROP_AND 1 +#define GCM_TRANSFER_OPERATION_ROP_AND 1 /*! \brief Perform blending, and logical \c AND with destination. */ -#define GCM_TRANSFER_OPERATION_BLEND_AND 2 +#define GCM_TRANSFER_OPERATION_BLEND_AND 2 /*! \brief Copy source image. */ -#define GCM_TRANSFER_OPERATION_SRCCOPY 3 +#define GCM_TRANSFER_OPERATION_SRCCOPY 3 /*! \brief Copy pre-multiplied source image. */ -#define GCM_TRANSFER_OPERATION_SRCCOPY_PREMULT 4 +#define GCM_TRANSFER_OPERATION_SRCCOPY_PREMULT 4 /*! \brief Blend pre-multiplied source image. */ -#define GCM_TRANSFER_OPERATION_BLEND_PREMULT 5 +#define GCM_TRANSFER_OPERATION_BLEND_PREMULT 5 /*! \brief Origin is the center of the source image. */ -#define GCM_TRANSFER_ORIGIN_CENTER 1 +#define GCM_TRANSFER_ORIGIN_CENTER 1 /*! \brief Origin is the topleft cornet of the source image. */ -#define GCM_TRANSFER_ORIGIN_CORNER 2 +#define GCM_TRANSFER_ORIGIN_CORNER 2 /*! \brief Use point sampling interpolation. */ -#define GCM_TRANSFER_INTERPOLATOR_NEAREST 0 +#define GCM_TRANSFER_INTERPOLATOR_NEAREST 0 // point sampling /*! \brief Use point linear interpolation. */ -#define GCM_TRANSFER_INTERPOLATOR_LINEAR 1 +#define GCM_TRANSFER_INTERPOLATOR_LINEAR 1 // bilinear interpolation /*! \brief Source surface pixel format is 5-bit red, 6-bit green, 5-bit blue. */ -#define GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 4 +#define GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 4 /*! \brief Source surface pixel format is 8-bit alpha, 8-bit red, 8-bit green, 8-bit blue. */ -#define GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 0xa +#define GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 0xa /*! \brief Source surface pixel format is Y32. */ -#define GCM_TRANSFER_SURFACE_FORMAT_Y32 0xb +#define GCM_TRANSFER_SURFACE_FORMAT_Y32 0xb + +#define GCM_FREQUENCY_MODULO 1 +#define GCM_FREQUENCY_DIVIDE 0 + +#define GCM_COMPMODE_DISABLED 0 +#define GCM_COMPMODE_C32_2X1 7 +#define GCM_COMPMODE_C32_2X2 8 +#define GCM_COMPMODE_Z32_SEPSTENCIL 9 +#define GCM_COMPMODE_Z32_SEPSTENCIL_REG 10 +#define GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR 10 +#define GCM_COMPMODE_Z32_SEPSTENCIL_DIAGONAL 11 +#define GCM_COMPMODE_Z32_SEPSTENCIL_ROTATED 12 + +#define GCM_ZCULL_Z16 1 +#define GCM_ZCULL_Z24S8 2 + +#define GCM_ZCULL_MSB 0 +#define GCM_ZCULL_LONES 1 + +#define GCM_ZCULL_LESS 0 +#define GCM_ZCULL_GREATER 1 + +#define GCM_SCULL_SFUNC_NEVER 0 +#define GCM_SCULL_SFUNC_LESS 1 +#define GCM_SCULL_SFUNC_EQUAL 2 +#define GCM_SCULL_SFUNC_LEQUAL 3 +#define GCM_SCULL_SFUNC_GREATER 4 +#define GCM_SCULL_SFUNC_NOTEQUAL 5 +#define GCM_SCULL_SFUNC_GEQUAL 6 +#define GCM_SCULL_SFUNC_ALWAYS 7 + +#define GCM_CONDITIONAL 2 + +#define GCM_ZPASS_PIXEL_CNT 1 +#define GCM_ZCULL_STATS 2 +#define GCM_ZCULL_STATS1 3 +#define GCM_ZCULL_STATS2 4 +#define GCM_ZCULL_STATS3 5 + +#define GCM_ZCULL_ALIGN_OFFSET 4096 +#define GCM_ZCULL_ALIGN_WIDTH 64 +#define GCM_ZCULL_ALIGN_HEIGHT 64 +#define GCM_ZCULL_ALIGN_CULLSTART 4096 +#define GCM_ZCULL_COMPRESSION_TAG_BASE_MAX 0x7FF +#define GCM_ZCULL_RAM_SIZE_MAX 0x00300000 + +#define GCM_TILE_ALIGN_OFFSET 0x00010000 +#define GCM_TILE_ALIGN_SIZE 0x00010000 +#define GCM_TILE_LOCAL_ALIGN_HEIGHT 32 +#define GCM_TILE_MAIN_ALIGN_HEIGHT 64 + +#define GCM_TILE_ALIGN_BUFFER_START_BOUNDARY 8 + +#define GCM_FRAGMENT_UCODE_LOCAL_ALIGN_OFFSET 64 +#define GCM_FRAGMENT_UCODE_MAIN_ALIGN_OFFSET 128 + +#define GCM_SURFACE_LINEAR_ALIGN_OFFSET 64 +#define GCM_SURFACE_SWIZZLE_ALIGN_OFFSET 128 + +#define GCM_TEXTURE_SWIZZLE_ALIGN_OFFSET 128 +#define GCM_TEXTURE_CUBEMAP_ALIGN_OFFSET 128 +#define GCM_TEXTURE_SWIZZLED_CUBEMAP_FACE_ALIGN_OFFSET 128 + +#define GCM_VERTEX_TEXTURE_CACHE_LINE_SIZE 32 +#define GCM_L2_TEXTURE_CACHE_LOCAL_LINE_SIZE 64 +#define GCM_L2_TEXTURE_CACHE_MAIN_LINE_SIZE 128 #ifdef __cplusplus extern "C" { @@ -403,375 +701,377 @@ extern "C" { struct _gcmCtxData; typedef s32 (*gcmContextCallback)(struct _gcmCtxData *context,u32 count); -/* START OF STRUCTS */ - /*! \brief RSX Context data structure. - This structure is used for managing and controlling the command buffer. +This structure is used for managing and controlling the command buffer. */ typedef struct _gcmCtxData { - u32 *__restrict begin ATTRIBUTE_PRXPTR; /*!< \brief Start address of command buffer */ - u32 *__restrict end ATTRIBUTE_PRXPTR; /*!< \brief End address of command buffer */ - u32 *__restrict current ATTRIBUTE_PRXPTR; /*!< \brief Current address of command buffer */ - gcmContextCallback callback ATTRIBUTE_PRXPTR; /*!< \brief Callback function that is called when current reaches end */ + u32 *__restrict begin ATTRIBUTE_PRXPTR; /*!< \brief Start address of command buffer */ + u32 *__restrict end ATTRIBUTE_PRXPTR; /*!< \brief End address of command buffer */ + u32 *__restrict current ATTRIBUTE_PRXPTR; /*!< \brief Current address of command buffer */ + gcmContextCallback callback ATTRIBUTE_PRXPTR; /*!< \brief Callback function that is called when current reaches end */ } gcmContextData; /*! \brief RSX control data structure. - This structure is used to control the command buffer. +This structure is used to control the command buffer. */ typedef struct _gcmCtrlRegister { - vu32 put; /*!< \brief member for accessing the PUT register */ - vu32 get; /*!< \brief member for accessing the GET register */ - vu32 ref; /*!< \brief member for accessing the REF register. Initial value is 0xFFFFFFFF */ + vu32 put; /*!< \brief member for accessing the PUT register */ + vu32 get; /*!< \brief member for accessing the GET register */ + vu32 ref; /*!< \brief member for accessing the REF register. Initial value is 0xFFFFFFFF */ } gcmControlRegister; /*! \brief RSX Configuration structure. - This structure holds system informations of RSX. +This structure holds system informations of RSX. */ typedef struct _gcmCfg { - void *localAddress ATTRIBUTE_PRXPTR; /*!< \brief effective start address of RSX memory */ - void *ioAddress ATTRIBUTE_PRXPTR; /*!< \brief effective start address of I/O mapped main memory to be used by RSX */ - u32 localSize; /*!< \brief maximum available size of RSX memory */ - u32 ioSize; /*!< \brief maximum available size of I/O mapped main memory to be used by RSX */ - u32 memoryFreq; /*!< \brief RSX memory clock frequency. */ - u32 coreFreq; /*!< \brief Core clock frequency of RSX */ + void *localAddress ATTRIBUTE_PRXPTR; /*!< \brief effective start address of RSX memory */ + void *ioAddress ATTRIBUTE_PRXPTR; /*!< \brief effective start address of I/O mapped main memory to be used by RSX */ + u32 localSize; /*!< \brief maximum available size of RSX memory */ + u32 ioSize; /*!< \brief maximum available size of I/O mapped main memory to be used by RSX */ + u32 memoryFreq; /*!< \brief RSX memory clock frequency. */ + u32 coreFreq; /*!< \brief Core clock frequency of RSX */ } gcmConfiguration; /*! \brief RSX target surface data structure. - This structure holds settings of the render target that is to be the render buffer. - Set the buffer to use for rendering by passing this structure as the argument when calling \ref rsxSetSurface. */ +This structure holds settings of the render target that is to be the render buffer. +Set the buffer to use for rendering by passing this structure as the argument when calling \ref rsxSetSurface. */ typedef struct _gcmSurface { - /*! \brief Type of render target. - - Possible values are: - - \ref GCM_TF_TYPE_LINEAR - - \ref GCM_TF_TYPE_SWIZZLE - */ - u8 type; - - /*! \brief Antialiasing format type. - - Specifies the mode of multiple samples. Possible values are: - - \ref GCM_TF_CENTER_1 - */ - u8 antiAlias; - - /*! \brief Format of the color buffer. - - Possible values are: - - \ref GCM_TF_COLOR_R5G5B5 - */ - u8 colorFormat; - - /*! \brief Target of the color buffer. - - Specifies the render target to use as a surface. Possible values are: - - \ref GCM_TF_TARGET_NONE - - \ref GCM_TF_TARGET_0 - - \ref GCM_TF_TARGET_1 - - \ref GCM_TF_TARGET_MRT1 - - \ref GCM_TF_TARGET_MRT2 - - \ref GCM_TF_TARGET_MRT3 - */ - u8 colorTarget; - - /*! \brief Location of the color buffer. - - When using multiple render targets, set as many locations as the number of color buffers enabled in colorTarget. - In this system, up to 4 color buffers can be specified for multiple render targets, and the location of each individual color buffer can be specified independently. - Possible values are: - - \ref GCM_LOCATION_RSX - - \ref GCM_LOCATION_CELL - */ - u8 colorLocation[GCM_MAX_MRT_COUNT]; - - /*! \brief Offset from the base address of the color buffer. - - When using multiple render targets, set as many addresses as the number of color buffers specified in colorTarget. - Use \ref rsxAddressToOffset to convert the effective addresses into offset values when specifying the buffer offset. colorOffset should be aligned on a 64 bytes boundery. - */ - u32 colorOffset[GCM_MAX_MRT_COUNT]; - - /*! \brief Size of a color buffer line in bytes. - - When using multiple render targets, specify as many pitch sizes as the number of color buffers specified in colorTarget. - The pitch size should be 64 when rendering in the swizzle format. For all others, the pitch size should be a multiple of 64. - */ - u32 colorPitch[GCM_MAX_MRT_COUNT]; - - /*! \brief Format of the depth buffer. - - Possible values are: - - \ref GCM_TF_ZETA_Z16 - - \ref GCM_TF_ZETA_Z24S8 - */ - u8 depthFormat; - - /*! \brief Location of the depth buffer. - - Possible values are: - - \ref GCM_LOCATION_RSX - - \ref GCM_LOCATION_CELL - */ - u8 depthLocation; - - /*! \brief unused padding bytes. most be 0. */ - u8 _pad[2]; - - /*! \brief Offset from the base address of the depth buffer. - - As in colorOffset use \ref rsxAddressToOffset to convert effective addresses into offset values. depthOffset should be aligned on a 64 bytes boundery. - */ - u32 depthOffset; - - /*! \brief Size of a depth buffer line in bytes. */ - u32 depthPitch; - - /*! \brief Width of the render buffer (1 - 4096). */ - u16 width; - - /*! \brief Height of the render buffer (1 - 4096). */ - u16 height; - - /*! \brief Window offset in x direction (0 - 4095). */ - u16 x; - - /*! \brief Window offset in y direction (0 - 4095). */ - u16 y; + /*! \brief Type of render target. + + Possible values are: + - \ref GCM_SURFACE_TYPE_LINEAR + - \ref GCM_SURFACE_TYPE_SWIZZLE + */ + u8 type; + + /*! \brief Antialiasing format type. + + Specifies the mode of multiple samples. Possible values are: + - \ref GCM_SURFACE_CENTER_1 + - \ref GCM_SURFACE_DIAGONAL_CENTERED_2 + - \ref GCM_SURFACE_SQUARE_CENTERED_4 + - \ref GCM_SURFACE_SQUARE_ROTATED_4 + */ + u8 antiAlias; + + /*! \brief Format of the color buffer. + + Possible values are: + -\ ref GCM_SURFACE_X1R5G5B5_Z1R5G5B5 + -\ ref GCM_SURFACE_X1R5G5B5_O1R5G5B5 + -\ ref GCM_SURFACE_R5G5B5 + -\ ref GCM_SURFACE_X8R8G8B8_Z8R8G8B8 + -\ ref GCM_SURFACE_X8R8G8B8 + -\ ref GCM_SURFACE_A8R8G8B8 + -\ ref GCM_SURFACE_B8 + -\ ref GCM_SURFACE_G8B8 + -\ ref GCM_SURFACE_F_W16Z16Y16X16 + -\ ref GCM_SURFACE_F_W32Z32Y32X32 + -\ ref GCM_SURFACE_F_X32 + -\ ref GCM_SURFACE_X8B8G8R8_Z8B8G8R8 + -\ ref GCM_SURFACE_X8B8G8R8_O8B8G8R8 + -\ ref GCM_SURFACE_A8B8G8R8 + */ + u8 colorFormat; + + /*! \brief Target of the color buffer. + + Specifies the render target to use as a surface. Possible values are: + - \ref GCM_SURFACE_TARGET_NONE + - \ref GCM_SURFACE_TARGET_0 + - \ref GCM_SURFACE_TARGET_1 + - \ref GCM_SURFACE_TARGET_MRT1 + - \ref GCM_SURFACE_TARGET_MRT2 + - \ref GCM_SURFACE_TARGET_MRT3 + */ + u8 colorTarget; + + /*! \brief Location of the color buffer. + + When using multiple render targets, set as many locations as the number of color buffers enabled in colorTarget. + In this system, up to 4 color buffers can be specified for multiple render targets, and the location of each individual color buffer can be specified independently. + Possible values are: + - \ref GCM_LOCATION_RSX + - \ref GCM_LOCATION_CELL + */ + u8 colorLocation[GCM_MAX_MRT_COUNT]; + + /*! \brief Offset from the base address of the color buffer. + + When using multiple render targets, set as many addresses as the number of color buffers specified in colorTarget. + Use \ref rsxAddressToOffset to convert the effective addresses into offset values when specifying the buffer offset. colorOffset should be aligned on a 64 bytes boundery. + */ + u32 colorOffset[GCM_MAX_MRT_COUNT]; + + /*! \brief Size of a color buffer line in bytes. + + When using multiple render targets, specify as many pitch sizes as the number of color buffers specified in colorTarget. + The pitch size should be 64 when rendering in the swizzle format. For all others, the pitch size should be a multiple of 64. + */ + u32 colorPitch[GCM_MAX_MRT_COUNT]; + + /*! \brief Format of the depth buffer. + + Possible values are: + - \ref GCM_SURFACE_ZETA_Z16 + - \ref GCM_SURFACE_ZETA_Z24S8 + */ + u8 depthFormat; + + /*! \brief Location of the depth buffer. + + Possible values are: + - \ref GCM_LOCATION_RSX + - \ref GCM_LOCATION_CELL + */ + u8 depthLocation; + + /*! \brief unused padding bytes. most be 0. */ + u8 _pad[2]; + + /*! \brief Offset from the base address of the depth buffer. + + As in colorOffset use \ref rsxAddressToOffset to convert effective addresses into offset values. depthOffset should be aligned on a 64 bytes boundery. + */ + u32 depthOffset; + + /*! \brief Size of a depth buffer line in bytes. */ + u32 depthPitch; + + /*! \brief Width of the render buffer (1 - 4096). */ + u16 width; + + /*! \brief Height of the render buffer (1 - 4096). */ + u16 height; + + /*! \brief Window offset in x direction (0 - 4095). */ + u16 x; + + /*! \brief Window offset in y direction (0 - 4095). */ + u16 y; } gcmSurface; /*! \brief RSX Texture data structure. */ typedef struct _gcmTexture { - /*! \brief Texture format. - - This is an OR-ed combination of the following values: - - \ref GCM_TEXTURE_FORMAT_SWZ - - \ref GCM_TEXTURE_FORMAT_LIN - - \ref GCM_TEXTURE_FORMAT_NRM - - \ref GCM_TEXTURE_FORMAT_L8 - - \ref GCM_TEXTURE_FORMAT_A1R5G5B5 - - \ref GCM_TEXTURE_FORMAT_A4R4G4B4 - - \ref GCM_TEXTURE_FORMAT_R5G6B5 - - \ref GCM_TEXTURE_FORMAT_A8R8G8B8 - - \ref GCM_TEXTURE_FORMAT_DXT1 - - \ref GCM_TEXTURE_FORMAT_DXT3 - - \ref GCM_TEXTURE_FORMAT_DXT5 - - \ref GCM_TEXTURE_FORMAT_A8L8 - */ - u8 format; - - /*! \brief Indicates if this is a mip-mapped texture. - - Possible values are: - - \ref GCM_TRUE - - \ref GCM_FALSE - */ - u8 mipmap; - - /*! \brief Texture dimension. - - Possible values are: - - \ref GCM_TEXTURE_DIMS_1D - - \ref GCM_TEXTURE_DIMS_2D - - \ref GCM_TEXTURE_DIMS_3D - */ - u8 dimension; - - /*! \brief Indicates if this is a cube-mapped texture. - - Possible values are: - - \ref GCM_TRUE - - \ref GCM_FALSE - */ - u8 cubemap; - - /*! \brief Color remapping bitfield. - - Each of the texture color components (red, green, blue, alpha) can be - remapped according to a specified remapping type. The type specifies - that the component is either set to zero, all one bits, or takes value - of one of the source components. All remapping types and values are to - be OR-ed together. - - For instance, to have the alpha component set to zero, the red and blue - components swapped and the green component kept as-is, set the following - value: - - (\ref GCM_TEXTURE_REMAP_TYPE_ZERO << \ref GCM_TEXTURE_REMAP_TYPE_A_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_R_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_COLOR_B << \ref GCM_TEXTURE_REMAP_COLOR_R_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_G_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_COLOR_G << \ref GCM_TEXTURE_REMAP_COLOR_G_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_B_SHIFT)\n - | (\ref GCM_TEXTURE_REMAP_COLOR_R << \ref GCM_TEXTURE_REMAP_COLOR_B_SHIFT) - */ - u32 remap; - - /*! \brief Texture width in pixels. */ - u16 width; - /*! \brief Texture height in pixels. */ - u16 height; - /*! \brief Texture depth. */ - u16 depth; - /*! \brief Location of texture. - Possible values are: - - \ref GCM_LOCATION_RSX - - \ref GCM_LOCATION_CELL - */ - u8 location; - /*! \brief unused padding byte. */ - u8 _pad; - /*! \brief Size of a texture line in bytes. */ - u32 pitch; - /*! \brief Offset of texture data. */ - u32 offset; + /*! \brief Texture format. + + This is an OR-ed combination of the following values: + - \ref GCM_TEXTURE_FORMAT_SWZ + - \ref GCM_TEXTURE_FORMAT_LIN + - \ref GCM_TEXTURE_FORMAT_NRM + - \ref GCM_TEXTURE_FORMAT_B8 + - \ref GCM_TEXTURE_FORMAT_A1R5G5B5 + - \ref GCM_TEXTURE_FORMAT_A4R4G4B4 + - \ref GCM_TEXTURE_FORMAT_R5G6B5 + - \ref GCM_TEXTURE_FORMAT_A8R8G8B8 + - \ref GCM_TEXTURE_FORMAT_DXT1 + - \ref GCM_TEXTURE_FORMAT_DXT3 + - \ref GCM_TEXTURE_FORMAT_DXT5 + - \ref GCM_TEXTURE_FORMAT_A8L8 + */ + u8 format; + + /*! \brief Indicates if this is a mip-mapped texture. + + Possible values are: + - \ref GCM_TRUE + - \ref GCM_FALSE + */ + u8 mipmap; + + /*! \brief Texture dimension. + + Possible values are: + - \ref GCM_TEXTURE_DIMS_1D + - \ref GCM_TEXTURE_DIMS_2D + - \ref GCM_TEXTURE_DIMS_3D + */ + u8 dimension; + + /*! \brief Indicates if this is a cube-mapped texture. + + Possible values are: + - \ref GCM_TRUE + - \ref GCM_FALSE + */ + u8 cubemap; + + /*! \brief Color remapping bitfield. + + Each of the texture color components (red, green, blue, alpha) can be + remapped according to a specified remapping type. The type specifies + that the component is either set to zero, all one bits, or takes value + of one of the source components. All remapping types and values are to + be OR-ed together. + + For instance, to have the alpha component set to zero, the red and blue + components swapped and the green component kept as-is, set the following + value: + + (\ref GCM_TEXTURE_REMAP_TYPE_ZERO << \ref GCM_TEXTURE_REMAP_TYPE_A_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_R_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_COLOR_B << \ref GCM_TEXTURE_REMAP_COLOR_R_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_G_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_COLOR_G << \ref GCM_TEXTURE_REMAP_COLOR_G_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_TYPE_REMAP << \ref GCM_TEXTURE_REMAP_TYPE_B_SHIFT)\n + | (\ref GCM_TEXTURE_REMAP_COLOR_R << \ref GCM_TEXTURE_REMAP_COLOR_B_SHIFT) + */ + u32 remap; + + /*! \brief Texture width in pixels. */ + u16 width; + /*! \brief Texture height in pixels. */ + u16 height; + /*! \brief Texture depth. */ + u16 depth; + /*! \brief Location of texture. + + Possible values are: + - \ref GCM_LOCATION_RSX + - \ref GCM_LOCATION_CELL + */ + u8 location; + /*! \brief unused padding byte. */ + u8 _pad; + /*! \brief Size of a texture line in bytes. */ + u32 pitch; + /*! \brief Offset of texture data. */ + u32 offset; } gcmTexture; -/*! \brief Specify scaled image blit geometry and format for rsxSetTransferScaleSurface(). */ +/*! \brief Specify scaled image blit geometry and format for rsxSetTransferImage() */ typedef struct _gcmTransferScale { - /*! \brief Conversion to perform when converting pixels to lower bit precision. - - Possible values: - - \ref GCM_TRANSFER_CONVERSION_DITHER - - \ref GCM_TRANSFER_CONVERSION_TRUNCATE - - \ref GCM_TRANSFER_CONVERSION_SUBTRACT_TRUNCATE - */ - u32 conversion; - - /*! \brief Format of source image pixels. - - Possible values: - - \ref GCM_TRANSFER_SCALE_FORMAT_A1R5G5B5 - - \ref GCM_TRANSFER_SCALE_FORMAT_X1R5G5B5 - - \ref GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 - - \ref GCM_TRANSFER_SCALE_FORMAT_X8R8G8B8 - - \ref GCM_TRANSFER_SCALE_FORMAT_CR8YB8CB8YA8 - - \ref GCM_TRANSFER_SCALE_FORMAT_YB8CR8YA8CB8 - - \ref GCM_TRANSFER_SCALE_FORMAT_R5G6B5 - - \ref GCM_TRANSFER_SCALE_FORMAT_Y8 - - \ref GCM_TRANSFER_SCALE_FORMAT_AY8 - - \ref GCM_TRANSFER_SCALE_FORMAT_EYB8ECR8EYA8ECB8 - - \ref GCM_TRANSFER_SCALE_FORMAT_ECR8EYB8ECB8EYA8 - - \ref GCM_TRANSFER_SCALE_FORMAT_A8B8G8R8 - - \ref GCM_TRANSFER_SCALE_FORMAT_X8B8G8R8 - */ - u32 format; - - /*! \brief Blit operation. - - Possible values: - - \ref GCM_TRANSFER_OPERATION_SRCCOPY_AND - - \ref GCM_TRANSFER_OPERATION_ROP_AND - - \ref GCM_TRANSFER_OPERATION_BLEND_AND - - \ref GCM_TRANSFER_OPERATION_SRCCOPY - - \ref GCM_TRANSFER_OPERATION_SRCCOPY_PREMULT - - \ref GCM_TRANSFER_OPERATION_BLEND_PREMULT - */ - u32 operation; - - /*! \brief X origin of clipping rectangle, within the destination surface. */ - s16 clipX; - - /*! \brief Y origin of clipping rectangle, within the destination surface. */ - s16 clipY; - - /*! \brief Width of clipping rectangle, within the destination surface. */ - u16 clipW; - - /*! \brief Height of clipping rectangle, within the destination surface. */ - u16 clipH; - - /*! \brief X origin of destination rectangle. */ - s16 outX; - - /*! \brief Y origin of destination rectangle. */ - s16 outY; - - /*! \brief Width of the destination rectangle. */ - u16 outW; - - /*! \brief Height of the destination rectangle. */ - u16 outH; - - /*! \brief Ratio in X direction of the source rectangle size to the destination rectangle size, encoded as a 32-bit signed fixed-point number. Such a value can be obtained from a floating point number by rsxGetFixedSint32(). */ - s32 ratioX; - - /*! \brief Ratio in Y direction of the source rectangle size to the destination rectangle size, encoded as a 32-bit signed fixed-point number. Such a value can be obtained from a floating point number by rsxGetFixedSint32(). */ - s32 ratioY; - - /*! \brief Width of the source rectangle. */ - u16 inW; - - /*! \brief Height of the source rectangle. */ - u16 inH; - - /*! \brief Pitch size, in bytes, of the source image data (width multiplied by the number of bytes in each pixel). */ - u16 pitch; - - /*! \brief How the origin of each pixel is determined. - - Possible values: - - \ref GCM_TRANSFER_ORIGIN_CENTER - - \ref GCM_TRANSFER_ORIGIN_CORNER - */ - u8 origin; - - /*! \brief Sampling for scaled blits. - - Possible values: - - \ref GCM_TRANSFER_INTERPOLATOR_NEAREST - - \ref GCM_TRANSFER_INTERPOLATOR_LINEAR - */ - u8 interp; - - /*! \brief Image data offset, e.g., a value returned by gcmAddressToOffset() - or gcmMapMainMemory(). */ - u32 offset; - - /*! \brief X origin of the blit rectangle in the source image. - Format is 16-bit fixed point, see rsxGetFixedUint16(). */ - u16 inX; - - /*! \brief Y origin of the blit rectangle in the source image. - Format is 16-bit fixed point, see rsxGetFixedUint16(). */ - u16 inY; + /*! \brief Not sure what this dones. Possible values: + - \ref GCM_TRANSFER_CONVERSION_DITHER + - \ref GCM_TRANSFER_CONVERSION_TRUNCATE + - \ref GCM_TRANSFER_CONVERSION_SUBTRACT_TRUNCATE + */ + u32 conversion; + + /*! \brief Format of image data. Possible values: + - \ref GCM_TRANSFER_SCALE_FORMAT_A1R5G5B5 + - \ref GCM_TRANSFER_SCALE_FORMAT_X1R5G5B5 + - \ref GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8 + - \ref GCM_TRANSFER_SCALE_FORMAT_X8R8G8B8 + - \ref GCM_TRANSFER_SCALE_FORMAT_CR8YB8CB8YA8 + - \ref GCM_TRANSFER_SCALE_FORMAT_YB8CR8YA8CB8 + - \ref GCM_TRANSFER_SCALE_FORMAT_R5G6B5 + - \ref GCM_TRANSFER_SCALE_FORMAT_Y8 + - \ref GCM_TRANSFER_SCALE_FORMAT_AY8 + - \ref GCM_TRANSFER_SCALE_FORMAT_EYB8ECR8EYA8ECB8 + - \ref GCM_TRANSFER_SCALE_FORMAT_ECR8EYB8ECB8EYA8 + - \ref GCM_TRANSFER_SCALE_FORMAT_A8B8G8R8 + - \ref GCM_TRANSFER_SCALE_FORMAT_X8B8G8R8 + */ + u32 format; + + /*! \brief Blit operation. Possible values: + - \ref GCM_TRANSFER_OPERATION_SRCCOPY_AND + - \ref GCM_TRANSFER_OPERATION_ROP_AND + - \ref GCM_TRANSFER_OPERATION_BLEND_AND + - \ref GCM_TRANSFER_OPERATION_SRCCOPY + - \ref GCM_TRANSFER_OPERATION_SRCCOPY_PREMULT + - \ref GCM_TRANSFER_OPERATION_BLEND_PREMULT + */ + u32 operation; + + /*! \brief X origin of clipping rectangle, within the destination surface. */ + s16 clipX; + + /*! \brief Y origin of clipping rectangle, within the destination surface. */ + s16 clipY; + + /*! \brief Width of clipping rectangle, within the destination surface. */ + u16 clipW; + + /*! \brief Height of clipping rectangle, within the destination surface. */ + u16 clipH; + + /*! \brief X origin of destination rectangle. */ + s16 outX; + + /*! \brief Y origin of destination rectangle. */ + s16 outY; + + /*! \brief Width of the destination rectangle. */ + u16 outW; + + /*! \brief Height of the destination rectangle. */ + u16 outH; + + /*! \brief Ratio in X direction of the source rectangle size to the destination rectangle size, encoded as a 32-bit signed fixed-point number. Such a value can be obtained from a floating point number by rsxGetFixedSint32(). */ + s32 ratioX; + + /*! \brief Ratio in Y direction of the source rectangle size to the destination rectangle size, encoded as a 32-bit signed fixed-point number. Such a value can be obtained from a floating point number by rsxGetFixedSint32(). */ + s32 ratioY; + + /*! \brief Width of the source rectangle. */ + u16 inW; + + /*! \brief Height of the source rectangle. */ + u16 inH; + + /*! \brief Pitch size, in bytes, of the source image data (width multiplied by the number of bytes in each pixel). */ + u16 pitch; + + /*! \brief How the origin of each pixel is determined. Possible values: + - \ref GCM_TRANSFER_ORIGIN_CENTER + - \ref GCM_TRANSFER_ORIGIN_CORNER + */ + u8 origin; + + /*! \brief Sampling for scaled blits. Possible values: + - \ref GCM_TRANSFER_INTERPOLATOR_NEAREST: no interpolation + - \ref GCM_TRANSFER_INTERPOLATOR_LINEAR: bilinear interpolation + */ + u8 interp; + + /*! \brief Image data offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). */ + u32 offset; + + /*! \brief X origin of destination rectangle. */ + u16 inX; + + /*! \brief Y origin of destination rectangle. */ + u16 inY; } gcmTransferScale; -/*! \brief Specify destination surface characteristics for rsxSetTransferScaleSurface(). */ +/*! \brief Specify destination surface characteristics for rsxSetTransferImage(). */ typedef struct _gcmTransferSurface { - /*! \brief Format of destination surface. Possible values are: - - \ref GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 - - \ref GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 - - \ref GCM_TRANSFER_SURFACE_FORMAT_Y32 - */ - u32 format; + /*! \brief Format of destination surface. Possible values are: + - \ref GCM_TRANSFER_SURFACE_FORMAT_R5G6B5 + - \ref GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8 + - \ref GCM_TRANSFER_SURFACE_FORMAT_Y32 + */ + u32 format; - /*! \brief Pitch for destination surface (width multipied by the number of bytes per pixel). */ - u16 pitch; + /*! \brief Pitch for destination surface (width multipied by the number of bytes per pixel). */ + u16 pitch; - /*! \brief unused padding bytes. most be 0. */ - u8 _pad0[2]; + /*! \brief unused padding bytes. most be 0. */ + u8 _pad0[2]; - /*! \brief Destination suface memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). */ - u32 offset; + /*! \brief Destination suface memory offset, e.g., a value returned by gcmAddressToOffset() or gcmMapMainMemory(). */ + u32 offset; } gcmTransferSurface; typedef struct _gcmTransferSwizzle { - u16 format; - u8 width; - u8 height; - u32 offset; + u16 format; + u8 width; + u8 height; + u32 offset; } gcmTransferSwizzle; typedef struct _gcmTileInfo @@ -812,12 +1112,6 @@ typedef struct _gcmOffsetTable u16 *ea; /* io -> ea */ } gcmOffsetTable; -typedef struct _gcmCast -{ - u32 u; - float f; -} gcmCast; - typedef struct _reportData { u64 timer; @@ -831,118 +1125,129 @@ typedef struct _notifyData u64 zero; } gcmNotifyData; -/* END STRUCTS */ - -/* - * system functions - */ - /*! \brief Initialize the RSX context. - \param ctx Pointer to where the effective address of the allocated context structure will be stored. - \param cmdSize The command buffer size. - \param ioSize The allocated IO buffer size. - \param ioAddress Pointer to an allocated buffer of \p ioSize bytes. - \return zero if no error occured, nonzero otherwise. + +\param ctx Pointer to where the effective address of the allocated context + structure will be stored. +\param cmdSize The command buffer size. +\param ioSize The allocated IO buffer size. +\param ioAddress Pointer to an allocated buffer of \p ioSize bytes. +\return zero if no error occured, nonzero otherwise. */ -s32 gcmInitBody(gcmContextData* ATTRIBUTE_PRXPTR *ctx,const u32 cmdSize,const u32 ioSize,const void *ioAddress); +s32 gcmInitBody(gcmContextData **ctx,const u32 cmdSize,const u32 ioSize,const void *ioAddress); /*! \brief Converts an effective address in RSX memory to an offset. - \param address The effective address to be converted. - \param offset A pointer to the returned offset value. - \return zero if no error occured, nonzero otherwise. +\param address The effective address to be converted. +\param offset A pointer to the returned offset value. +\return zero if no error occured, nonzero otherwise. */ -s32 gcmAddressToOffset(void *address,u32 *offset); +s32 gcmAddressToOffset(const void *address,u32 *offset); -/*! \brief Maps a memory block in main memory for RSX to access it. - \param address Pointer to the block to be mapped. - \param size Size of the block in bytes. - \param offset A pointer to the returned mapped offset value. - \return zero if no error occured, nonzero otherwise. +/*! \brief Converts an offset to an effective address in RSX memory. +\param offset The offset to be converted. +\param address A pointer to the returned effective address. +\return zero if no error occured, nonzero otherwise. */ -s32 gcmMapMainMemory(const void *address,const u32 size,u32 *offset); +s32 gcmIoOffsetToAddress(u32 offset,void **address); /*! \brief Retrieves the RSX configuration. - \param config A pointer to the configuration structure to be updated. - \return zero if no error occured, nonzero otherwise. +\param config A pointer to the configuration structure to be updated. +\return zero if no error occured, nonzero otherwise. */ s32 gcmGetConfiguration(gcmConfiguration *config); -/*! \brief Converts an offset to an effective address in RSX memory. - \param offset The offset to be converted. - \param address A pointer to the returned effective address. - \return zero if no error occured, nonzero otherwise. -*/ -s32 gcmIoOffsetToAddress(u32 offset,u32 *address); +/*! \brief Gets the flip status. +Once a flip occurred, querying for a subsequent flip requires the flip status +to be reset using \ref gcmResetFlipStatus. +\return zero if no flip occured, nonzero otherwise. +*/ +u32 gcmGetFlipStatus(); -/* - * display functions - */ +/*! \brief Enqueues a flip command into the command buffer. +\param context Pointer to the context object. +\param bufferId Framebuffer id to flip to (as configured with + \ref gcmSetDisplayBuffer). +\return zero if no error occured, nonzero otherwise. +*/ +s32 gcmSetFlip(gcmContextData *context,const u8 bufferId); /*! \brief Configures a display framebuffer. - \param bufferId The buffer id (0-7). - \param offset The offset of the allocated memory block (see \ref rsxAddressToOffset). - \param pitch The size of a buffer line in bytes. - \param width The buffer width in pixels. - \param height The buffer height in pixels. - \return zero if no error occured, nonzero otherwise. +\param bufferId The buffer id (0-7). +\param offset The offset of the allocated memory block (see \ref rsxAddressToOffset). +\param pitch The size of a buffer line in bytes. +\param width The buffer width in pixels. +\param height The buffer height in pixels. +\return zero if no error occured, nonzero otherwise. */ -s32 gcmSetDisplayBuffer(u32 bufferId,u32 offset,u32 pitch,u32 width,u32 height); +s32 gcmSetDisplayBuffer(const u8 bufferId,const u32 offset,const u32 pitch,const u32 width,const u32 height); -/*! \brief Set flip mode. - \param mode The specified flip mode. Possible vales are: - - \ref GCM_FLIP_HSYNC - - \ref GCM_FLIP_VSYNC - - \ref GCM_FLIP_HSYNC_AND_BREAK_EVERYTHING +/*! \brief Maps a memory block in main memory for RSX to access it. +\param address Pointer to the block to be mapped. +\param size Size of the block in bytes. +\param offset A pointer to the returned mapped offset value. +\return zero if no error occured, nonzero otherwise. +*/ +s32 gcmMapMainMemory(const void *address,const u32 size,u32 *offset); + +/*! \brief Get address of specified label. +\param index The label index whose address is to be obtained. +\return Pointer to the label address. */ -void gcmSetFlipMode(s32 mode); +u32* gcmGetLabelAddress(const u8 index); /*! \brief Reset the flip status. */ void gcmResetFlipStatus(); -/*! \brief Gets the flip status. - Once a flip occurred, querying for a subsequent flip requires the flip status to be reset using \ref gcmResetFlipStatus. - \return zero if a flip occured, nonzero otherwise. -*/ -s32 gcmGetFlipStatus(); - -/*! \brief Enqueues a flip command into the command buffer. - \param context Pointer to the context object. - \param bufferId Framebuffer id to flip to (as configured with - \ref gcmSetDisplayBuffer). - \return zero if no error occured, nonzero otherwise. +/*! \brief Set flip mode. +\param mode The specified flip mode. Possible vales are: + - \ref GCM_FLIP_HSYNC + - \ref GCM_FLIP_VSYNC + - \ref GCM_FLIP_HSYNC_AND_BREAK_EVERYTHING */ -s32 gcmSetFlip(gcmContextData *context,u32 bufferId); +void gcmSetFlipMode(const u32 mode); /*! \brief Wait for a flip to be completed. - \param context Pointer to the context object. +\param context Pointer to the context object. */ void gcmSetWaitFlip(gcmContextData *context); +/*! \brief Perform preprocessing for display output +\param context Pointer to context object +\param id buffer id +*/ +u32 gcmSetPrepareFlip(gcmContextData *context,const u8 id); + +/*! \brief Register a callback function to be called upon VBlank. -/* - * render functions - */ +This function registers a callback function to be called upon VBlank and after VSync. The registered callback can be canceled if NULL is specified for handler. +\param handler Callback function to register +*/ +void gcmSetVBlankHandler(void (*handler)(const u32 head)); -/*! \brief Get address of specified label. - \param index The label index whose address is to be obtained. - \return Pointer to the label address. +/*! \brief Register a callback function for when a flip is executed. + +This function registers a callback function to be called when RSX actually carries out a flip. The registered callback can be canceled if NULL is specified for handler. +\param handler Callback function to register */ -u32* gcmGetLabelAddress(const u8 index); +void gcmSetFlipHandler(void (*handler)(const u32 head)); +/*! \brief Register a graphics callback function. -/* previously missing / new additions */ +This function registers a callback function to be executed when an exception occurs in the graphics pipeline. The registered callback can be canceled if NULL is specified for handler. +\param handler Callback function to register +*/ +void gcmSetGraphicsHandler(void (*handler)(const u32 val)); +void gcmSetDefaultCommandBuffer(); -/* - * system functions - */ -s32 gcmInitSystemMode(const u64 mode); +/*! \brief Obtain registers for controlling the command buffer. +\return Pointer to a \ref gcmControlRegister structure +*/ gcmControlRegister* gcmGetControlRegister(); + +s32 gcmInitSystemMode(const u64 mode); u32 gcmGetTiledPitchSize(const u32 size); -void gcmSetVBlankHandler(void (*handler)(const u32 head)); void gcmSetSecondVHandler(void (*handler)(const u32 head)); -void gcmSetGraphicsHandler(void (*handler)(const u32 val)); -void gcmSetFlipHandler(void (*handler)(const u32 head)); void gcmSetQueueHandler(void (*handler)(const u32 head)); void gcmSetUserHandler(void (*handler)(const u32 cause)); void gcmSetDebugOutputLevel(s32 level); @@ -982,15 +1287,9 @@ s32 gcmSetCursorImageOffset(const u32 offset); s32 gcmSetCursorPosition(const s32 x, const s32 y); s32 gcmUpdateCursor(); - /* * flow control functions */ -/* TODO: uint32_t *cellGcmGetCurrentBuffer(void); */ -void cellGcmSetCurrentBuffer(const uint32_t *addr, const size_t size); -void gcmSetDefaultCommandBuffer(); -/* TODO: void cellGcmSetUserCallback(CellGcmContextCallback callback); */ -/* TODO: void cellGcmSetupContextData(CellGcmContextData *context, const uint32_t *addr, const uint32_t size, CellGcmContextCallback callback); */ s32 gcmSetDefaultCommandBufferAndSegmentWordSize(const u32 bufferSize, const u32 segmentSize); u32 gcmGetDefaultCommandWordSize(); u32 gcmGetDefaultSegmentWordSize(); @@ -1020,13 +1319,6 @@ gcmReportData* gcmGetReportDataAddressLocation(const u32 index, const u32 locati u64 gcmGetTimeStampLocation(const u32 index, const u32 location); u32 gcmGetReportDataLocation(const u32 index, const u32 location); - -/* - * data xfer / format conversion functions - */ -/* TODO: void cellGcmConvertSwizzleFormat(void *swizzledTexture, const void *texture, const uint32_t dstx0, const uint32_t dsty0, const uint32_t dstz0, const uint32_t dstWidth, const uint32_t dstHeight, const uint32_t dstDepth, const uint32_t srcx0, const uint32_t srcy0, const uint32_t srcz0, const uint32_t srcx1, const uint32_t srcy1, const uint32_t srcz1, const uint32_t srcWidth, const uint32_t srcHeight, const uint32_t srcDepth, const uint32_t dstLog2cdepth, const uint32_t srcColordepth, const uint32_t border, const uint32_t dim, void (*copyTexel)(void *dst, const void *src)); */ - - /* * notify functions */ @@ -1045,28 +1337,10 @@ const gcmDisplayInfo* gcmGetDisplayInfo(); */ s32 gcmDumpGraphicsError(); - -/* TODO: CELL_GCM_DECL CELL_GCM_FUNC_TYPE CELL_GCM_FUNC(SetUserCommand)(CELL_GCM_ARGS(const u32 cause)); */ -/* inline __attribute__((always_inline)) void gcmSetUserCommand(void (*handler)(const u32 cause)); */ void gcmSetUserCommand(void (*handler)(const u32 cause)); -/* TODO: CELL_GCM_GLOBAL_DECL CELL_GCM_FUNC_TYPE_UINT32 CELL_GCM_FUNC(SetPrepareFlip)(CELL_GCM_ARGS(const u8 id)) */ -/* inline __attribute__((always_inline)) u32 gcmSetPrepareFlip(const u8 id); */ -u32 gcmSetPrepareFlip(const u8 id); - -/* TODO: gcmTerminate() no prototype */ -/* TODO: gcmFunc1 no prototype */ -/* TODO: gcmFunc2 no prototype */ -/* TODO: gcmFunc3 no prototype */ -/* TODO: gcmFunc4 no prototype */ -/* TODO: gcmFunc12 no prototype */ -/* TODO: gcmFunc13 no prototype */ -/* TODO: gcmFunc15 no prototype */ -/* TODO: gcmFunc38 no prototype */ - #ifdef __cplusplus - } + } #endif #endif - diff --git a/ppu/include/rsx/nv40.h b/ppu/include/rsx/nv40.h index 9bbd6e18..34bb2a2f 100644 --- a/ppu/include/rsx/nv40.h +++ b/ppu/include/rsx/nv40.h @@ -4326,16 +4326,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40_SWIZZLED_SURFACE 0x0000309e -#define NV3062TCL 0x00003062 - -#define NV3062TCL_SET_CONTEXT_DMA_IMAGE_DEST 0x00006188 -#define NV3062TCL_SET_COLOR_FORMAT 0x00006300 -#define NV3062TCL_SET_OFFSET_DEST 0x0000630c - -#define NC308ATCL 0x0000308a - -#define NV308ATCL_POINT 0x0000a304 -#define NV308ATCL_COLOR 0x0000a400 #define NV406ETCL 0x0000406e @@ -4351,6 +4341,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_REF_CNT 0x00000050 #define NV40TCL_NOP 0x00000100 #define NV40TCL_NOTIFY 0x00000104 +#define NV40TCL_WAIT_FOR_IDLE 0x00000110 +#define NV40TCL_PM_TRIGGER 0x00000140 #define NV40TCL_DMA_NOTIFY 0x00000180 #define NV40TCL_DMA_TEXTURE0 0x00000184 #define NV40TCL_DMA_TEXTURE1 0x00000188 @@ -4408,6 +4400,8 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_RT_ENABLE_COLOR1 (1 << 1) #define NV40TCL_RT_ENABLE_COLOR0 (1 << 0) #define NV40TCL_ZETA_PITCH 0x0000022c +#define NV40TCL_CYLINDRICAL_WRAP 0x00000238 +#define NV40TCL_CYLINDRICAL_WRAP1 0x0000023c #define NV40TCL_COLOR2_PITCH 0x00000280 #define NV40TCL_COLOR3_PITCH 0x00000284 #define NV40TCL_COLOR2_OFFSET 0x00000288 @@ -4611,6 +4605,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_SHADE_MODEL 0x00000368 #define NV40TCL_SHADE_MODEL_FLAT 0x00001d00 #define NV40TCL_SHADE_MODEL_SMOOTH 0x00001d01 +#define NV40TCL_BLEND_ENABLE_MRT 0x0000036c #define NV40TCL_MRT_COLOR_MASK 0x00000370 #define NV40TCL_MRT_COLOR_MASK_BUFFER1_A (1 << 4) #define NV40TCL_MRT_COLOR_MASK_BUFFER1_R (1 << 5) @@ -4648,7 +4643,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_DEPTH_RANGE_FAR 0x00000398 #define NV40TCL_LINE_WIDTH 0x000003b8 #define NV40TCL_LINE_SMOOTH_ENABLE 0x000003bc -#define NV40TCL_UNK03C0(x) (0x000003c0+((x)*4)) +#define NV40TCL_TEX_ANISO_SPREAD(x) (0x000003c0+((x)*4)) #define NV40TCL_UNK03C0__SIZE 0x00000010 #define NV40TCL_UNK0400(x) (0x00000400+((x)*4)) #define NV40TCL_UNK0400__SIZE 0x00000010 @@ -4673,6 +4668,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_FP_ADDRESS_OFFSET_MASK 0xffffff00 #define NV40TCL_FP_ADDRESS_DMA1 (1 << 1) #define NV40TCL_FP_ADDRESS_DMA0 (1 << 0) +#define NV40TCL_VP_TEXTURE_OFFSET(x) (0x00000900+((x)*32)) +#define NV40TCL_VP_TEXTURE_FORMAT(x) (0x00000904+((x)*32)) +#define NV40TCL_VP_TEXTURE_ADDRESS(x) (0x00000908+((x)*32)) +#define NV40TCL_VP_TEXTURE_CONTROL0(x) (0x0000090c+((x)*32)) +#define NV40TCL_VP_TEXTURE_CONTROL3(x) (0x00000910+((x)*32)) +#define NV40TCL_VP_TEXTURE_FILTER(x) (0x00000914+((x)*32)) +#define NV40TCL_VP_TEXTURE_IMAGE_RECT(x) (0x00000918+((x)*32)) +#define NV40TCL_VP_TEXTURE_BORDER_COLOR(x) (0x0000091c+((x)*32)) #define NV40TCL_VIEWPORT_HORIZ 0x00000a00 #define NV40TCL_VIEWPORT_HORIZ_W_SHIFT 16 #define NV40TCL_VIEWPORT_HORIZ_W_MASK 0xffff0000 @@ -4692,9 +4695,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_VIEWPORT_SCALE_Y 0x00000a34 #define NV40TCL_VIEWPORT_SCALE_Z 0x00000a38 #define NV40TCL_VIEWPORT_SCALE_W 0x00000a3c -#define NV40TCL_POLYGON_OFFSET_FILL_ENABLE 0x00000a60 +#define NV40TCL_POLYGON_OFFSET_POINT_ENABLE 0x00000a60 #define NV40TCL_POLYGON_OFFSET_LINE_ENABLE 0x00000a64 -#define NV40TCL_POLYGON_OFFSET_POINT_ENABLE 0x00000a68 +#define NV40TCL_POLYGON_OFFSET_FILL_ENABLE 0x00000a68 #define NV40TCL_DEPTH_FUNC 0x00000a6c #define NV40TCL_DEPTH_FUNC_NEVER 0x00000200 #define NV40TCL_DEPTH_FUNC_LESS 0x00000201 @@ -4709,10 +4712,25 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_DEPTH_TEST_ENABLE 0x00000a74 #define NV40TCL_POLYGON_OFFSET_FACTOR 0x00000a78 #define NV40TCL_POLYGON_OFFSET_UNITS 0x00000a7c +#define NV40TCL_VTX_ATTR_4I_SCALED_0(x) (0x00000a80+((x)*8)) +#define NV40TCL_VTX_ATTR_4I_SCALED_0__SIZE 0x00000010 +#define NV40TCL_VTX_ATTR_4I_SCALED_0_Y_SHIFT 16 +#define NV40TCL_VTX_ATTR_4I_SCALED_0_Y_MASK 0xffff0000 +#define NV40TCL_VTX_ATTR_4I_SCALED_0_X_SHIFT 0 +#define NV40TCL_VTX_ATTR_4I_SCALED_0_X_MASK 0x0000ffff +#define NV40TCL_VTX_ATTR_4I_SCALED_1(x) (0x00000a84+((x)*8)) +#define NV40TCL_VTX_ATTR_4I_SCALED_1__SIZE 0x00000010 +#define NV40TCL_VTX_ATTR_4I_SCALED_1_W_SHIFT 16 +#define NV40TCL_VTX_ATTR_4I_SCALED_1_W_MASK 0xffff0000 +#define NV40TCL_VTX_ATTR_4I_SCALED_1_Z_SHIFT 0 +#define NV40TCL_VTX_ATTR_4I_SCALED_1_Z_MASK 0x0000ffff +#define NV40TCL_TEX_CONTROL2(x) (0x00000b00+((x)*4)) #define NV40TCL_TEX_COORD_CONTROL(x) (0x00000b40+((x)*4)) #define NV40TCL_TEX_COORD_CONTROL__SIZE 0x00000008 #define NV40TCL_VP_UPLOAD_INST(x) (0x00000b80+((x)*16)) #define NV40TCL_VP_UPLOAD_INST__SIZE 0x00000004 +#define NV40TCL_TWO_SIDE_LIGHT_EN 0x0000142c +#define NV40TCL_CLEAR_ZCULL_SURFACE 0x00001438 #define NV40TCL_CLIP_PLANE_ENABLE 0x00001478 #define NV40TCL_CLIP_PLANE_ENABLE_PLANE0 (1 << 2) #define NV40TCL_CLIP_PLANE_ENABLE_PLANE1 (1 << 6) @@ -4734,6 +4752,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_VTXBUF_ADDRESS_DMA1 (1 << 31) #define NV40TCL_VTXBUF_ADDRESS_OFFSET_SHIFT 0 #define NV40TCL_VTXBUF_ADDRESS_OFFSET_MASK 0x0fffffff +#define NV40TCL_VTX_CACHE_INVALIDATE2 0x00001710 #define NV40TCL_VTX_CACHE_INVALIDATE 0x00001714 #define NV40TCL_VTXFMT(x) (0x00001740+((x)*4)) #define NV40TCL_VTXFMT__SIZE 0x00000010 @@ -4746,12 +4765,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_VTXFMT_STRIDE_SHIFT 8 #define NV40TCL_VTXFMT_STRIDE_MASK 0x0000ff00 #define NV40TCL_QUERY_RESET 0x000017c8 -#define NV40TCL_QUERY_UNK17CC 0x000017cc +#define NV40TCL_QUERY_ENABLE 0x000017cc #define NV40TCL_QUERY_GET 0x00001800 #define NV40TCL_QUERY_GET_UNK24_SHIFT 24 #define NV40TCL_QUERY_GET_UNK24_MASK 0xff000000 #define NV40TCL_QUERY_GET_OFFSET_SHIFT 0 #define NV40TCL_QUERY_GET_OFFSET_MASK 0x00ffffff +#define NV40TCL_ZCULL_STATS_ENABLE 0x00001804 #define NV40TCL_BEGIN_END 0x00001808 #define NV40TCL_BEGIN_END_STOP 0x00000000 #define NV40TCL_BEGIN_END_POINTS 0x00000001 @@ -4812,18 +4832,29 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_VTX_ATTR_2I_Y_MASK 0xffff0000 #define NV40TCL_VTX_ATTR_2I_X_SHIFT 0 #define NV40TCL_VTX_ATTR_2I_X_MASK 0x0000ffff -#define NV40TCL_VTX_ATTR_4I_0(x) (0x00001900+((x)*8)) +#define NV40TCL_VTX_ATTR_4UB(x) (0x00001940+((x)*4)) +#define NV40TCL_VTX_ATTR_4UB__SIZE 0x00000010 +#define NV40TCL_VTX_ATTR_4UB_Y_SHIFT 8 +#define NV40TCL_VTX_ATTR_4UB_Y_MASK 0x0000ff00 +#define NV40TCL_VTX_ATTR_4UB_X_SHIFT 0 +#define NV40TCL_VTX_ATTR_4UB_X_MASK 0x000000ff +#define NV40TCL_VTX_ATTR_4UB_W_SHIFT 24 +#define NV40TCL_VTX_ATTR_4UB_W_MASK 0xff000000 +#define NV40TCL_VTX_ATTR_4UB_Z_SHIFT 16 +#define NV40TCL_VTX_ATTR_4UB_Z_MASK 0x00ff0000 +#define NV40TCL_VTX_ATTR_4I_0(x) (0x00001980+((x)*8)) #define NV40TCL_VTX_ATTR_4I_0__SIZE 0x00000010 #define NV40TCL_VTX_ATTR_4I_0_Y_SHIFT 16 #define NV40TCL_VTX_ATTR_4I_0_Y_MASK 0xffff0000 #define NV40TCL_VTX_ATTR_4I_0_X_SHIFT 0 #define NV40TCL_VTX_ATTR_4I_0_X_MASK 0x0000ffff -#define NV40TCL_VTX_ATTR_4I_1(x) (0x00001904+((x)*8)) +#define NV40TCL_VTX_ATTR_4I_1(x) (0x00001984+((x)*8)) #define NV40TCL_VTX_ATTR_4I_1__SIZE 0x00000010 #define NV40TCL_VTX_ATTR_4I_1_W_SHIFT 16 #define NV40TCL_VTX_ATTR_4I_1_W_MASK 0xffff0000 #define NV40TCL_VTX_ATTR_4I_1_Z_SHIFT 0 #define NV40TCL_VTX_ATTR_4I_1_Z_MASK 0x0000ffff + #define NV40TCL_TEX_OFFSET(x) (0x00001a00+((x)*32)) #define NV40TCL_TEX_OFFSET__SIZE 0x00000010 #define NV40TCL_TEX_FORMAT(x) (0x00001a04+((x)*32)) @@ -4995,7 +5026,10 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_FP_CONTROL_KIL (1 << 7) #define NV40TCL_SEMAPHORE_OFFSET 0x00001d6c #define NV40TCL_SEMAPHORE_BACKENDWRITE_RELEASE 0x00001d70 +#define NV40TCL_SEMAPHORE_TEXTUREREAD_RELEASE 0x00001d74 #define NV40TCL_DEPTH_CONTROL 0x00001d78 +#define NV40TCL_ANTI_ALIASING_CONTROL 0x00001d7c +#define NV40TCL_ZCULL_ENABLE 0x00001d84 #define NV40TCL_SHADER_WINDOW 0x00001d88 #define NV40TCL_CLEAR_VALUE_DEPTH 0x00001d8c #define NV40TCL_CLEAR_VALUE_COLOR 0x00001d90 @@ -5012,10 +5046,17 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_LINE_STIPPLE_PATTERN_FACTOR_MASK 0x0000ffff #define NV40TCL_LINE_STIPPLE_PATTERN_PATTERN_SHIFT 16 #define NV40TCL_LINE_STIPPLE_PATTERN_PATTERN_MASK 0xffff0000 +#define NV40TCL_VTX_ATTR_1F_X(x) (0x00001c00+((x)*4)) +#define NV40TCL_VTX_ATTR_1F_X__SIZE 0x00000004 +#define NV40TCL_RENDER_ENABLE 0x00001e98 #define NV40TCL_VP_UPLOAD_FROM_ID 0x00001e9c #define NV40TCL_VP_START_FROM_ID 0x00001ea0 -#define NV40TCL_POINT_SIZE 0x00001ee0 -#define NV40TCL_POINT_SPRITE 0x00001ee8 +#define NV40TCL_ZCULL_CONTROL0 0x00001ea4 +#define NV40TCL_ZCULL_CONTROL1 0x00001ea8 +#define NV40TCL_SCULL_CONTROL 0x00001eac +#define NV40TCL_POINT_SIZE 0x00001ee0 +#define NV40TCL_POINT_PARAMS_ENABLE 0x00001ee4 +#define NV40TCL_POINT_SPRITE_CONTROL 0x00001ee8 #define NV40TCL_TRANSFORM_TIMEOUT 0x00001ef8 #define NV40TCL_VP_UPLOAD_CONST_ID 0x00001efc #define NV40TCL_VP_UPLOAD_CONST_X(x) (0x00001f00+((x)*16)) @@ -5027,6 +5068,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define NV40TCL_VP_UPLOAD_CONST_W(x) (0x00001f0c+((x)*16)) #define NV40TCL_VP_UPLOAD_CONST_W__SIZE 0x00000004 #define NV40TCL_TEX_CACHE_CTL 0x00001fd8 +#define NV40TCL_DST_COL_REDUCE 0x00001fe0 #define NV40TCL_VP_ATTRIB_EN 0x00001ff0 #define NV40TCL_VP_RESULT_EN 0x00001ff4 #define NV40TCL_VP_TRANSFORM_BRANCH_BITS 0x00001ff8 diff --git a/ppu/include/rsx/rsx.h b/ppu/include/rsx/rsx.h index 45713124..ce7d6d61 100644 --- a/ppu/include/rsx/rsx.h +++ b/ppu/include/rsx/rsx.h @@ -94,50 +94,49 @@ size is a multiple of 1 megabyte. This function initializes a heap structure in RSX memory space, allowing dynamic memory allocation using \ref rsxMalloc, \ref rsxMemalign and \ref rsxFree. +\param context Pointer to receive the address of the default command buffer \param cmdSize The command buffer size. \param ioSize The allocated IO buffer size. \param ioAddress Pointer to an allocated buffer of \p ioSize bytes. -\return Pointer to the allocated context structure. +\return zero if no error occured, nonzero otherwise. */ -gcmContextData* rsxInit(const u32 cmdSize,const u32 ioSize,const void *ioAddress); - -/*! \brief Flushes the RSX command buffer. +s32 rsxInit(gcmContextData **context,u32 cmdSize,u32 ioSize,const void *ioAddress); -This ensures all remaining commands in the command buffer are executed, and -that the buffer is empty when that function returns. -\param context Pointer to the context object. -*/ -void rsxFlushBuffer(gcmContextData *context); +void rsxSetupContextData(gcmContextData *context,const u32 *addr,u32 size,gcmContextCallback cb); +void rsxSetCurrentBuffer(gcmContextData **context,const u32 *addr,u32 size); +void rsxSetDefaultCommandBuffer(gcmContextData **context); +void rsxSetUserCallback(gcmContextCallback cb); +void rsxSetupContextData(gcmContextData *context,const u32 *addr,u32 size,gcmContextCallback cb); -/*! \brief Reset the RSX command buffer. -\param context Pointer to the context object. -*/ -void rsxResetCommandBuffer(gcmContextData *context); -void rsxFinish(gcmContextData *context,u32 ref_value); -void rsxSetupContextData(gcmContextData *context,const u32 *addr,const u32 size,gcmContextCallback cb); +u32* rsxGetCurrentBuffer(); /*! \brief Converts a pointer value in RSX memory to an offset. \param ptr The pointer whose value is to be converted. \param offset A pointer to the returned offset value. \return zero if no error occured, nonzero otherwise. */ -static inline s32 rsxAddressToOffset(void *ptr,u32 *offset) +static inline s32 rsxAddressToOffset(const void *ptr,u32 *offset) { return gcmAddressToOffset(ptr,offset); } /*! \brief Convert a floating point coordinate into 32-bit signed fixed point format. */ -static inline s32 rsxGetFixedSint32(const f32 f) +static inline s32 rsxGetFixedSint32(f32 f) { return (s32)(f*1048576.0f); } /*! \brief Convert a floating point coordinate into 16-bit unsigned fixed point format. */ -static inline u16 rsxGetFixedUint16(const f32 f) +static inline u16 rsxGetFixedUint16(f32 f) { return (u16)(f*16.0f); } +static inline u32 rsxAlign(u32 alignment, u32 value) +{ + return (alignment==0 ? value : (value==0 ? 0 : (((u32)((value - 1)/alignment) + 1)*alignment))); +} + #ifdef __cplusplus } #endif diff --git a/ppu/include/rsx/rsx_function_macros.h b/ppu/include/rsx/rsx_function_macros.h new file mode 100644 index 00000000..bffc3a14 --- /dev/null +++ b/ppu/include/rsx/rsx_function_macros.h @@ -0,0 +1,50 @@ +#ifdef RSX_FUNCTION_MACROS + +#if RSX_UNSAFE + #define RSX_FUNC(func) rsx##func##Unsafe +#else + #define RSX_FUNC(func) rsx##func +#endif + +#if RSX_INTERNAL + +#if RSX_UNSAFE + #define RSX_FUNC_INTERNAL(func) __rsx##func##Unsafe + #define RSX_CONTEXT_CURRENT_BEGIN(count) do {} while(0) +#else + s32 __attribute__((noinline)) rsxContextCallback(gcmContextData *context,u32 count) + { + register s32 result asm("r3"); + __asm__ __volatile__ ( + "stdu 1,-128(1)\n" + "mr 31,2\n" + "lwz 0,0(%3)\n" + "lwz 2,4(%3)\n" + "mtctr 0\n" + "bctrl\n" + "mr 2,31\n" + "addi 1,1,128\n" + : "+r"(result) + : "r"(context), "r"(count), "b"(context->callback) + : "r31", "r0", "lr" + ); + return result; + } + + #define RSX_FUNC_INTERNAL(func) __rsx##func + #define RSX_CONTEXT_CURRENT_BEGIN(count) do { \ + if((context->current + (count)) > context->end) { \ + if(rsxContextCallback(context,(count))!=0) return; \ + } \ + } while(0) +#endif + +#endif + +#endif + +#ifndef RSX_FUNCTION_MACROS +#undef RSX_CONTEXT_CURRENT_BEGIN +#undef RSX_FUNC +#undef RSX_FUNC_INTERNAL +#endif diff --git a/ppu/include/rsx/rsx_program.h b/ppu/include/rsx/rsx_program.h index a66d0976..3e16b0d9 100644 --- a/ppu/include/rsx/rsx_program.h +++ b/ppu/include/rsx/rsx_program.h @@ -8,15 +8,19 @@ #include #define PARAM_FLOAT 0 -#define PARAM_FLOAT2 1 -#define PARAM_FLOAT3 2 -#define PARAM_FLOAT4 3 -#define PARAM_FLOAT4x4 4 -#define PARAM_SAMPLER1D 5 -#define PARAM_SAMPLER2D 6 -#define PARAM_SAMPLER3D 7 -#define PARAM_SAMPLERCUBE 8 -#define PARAM_SAMPLERRECT 9 +#define PARAM_FLOAT1 1 +#define PARAM_FLOAT2 2 +#define PARAM_FLOAT3 3 +#define PARAM_FLOAT4 4 +#define PARAM_FLOAT3x4 5 +#define PARAM_FLOAT4x4 6 +#define PARAM_FLOAT3x3 7 +#define PARAM_FLOAT4x3 8 +#define PARAM_SAMPLER1D 9 +#define PARAM_SAMPLER2D 10 +#define PARAM_SAMPLER3D 11 +#define PARAM_SAMPLERCUBE 12 +#define PARAM_SAMPLERRECT 13 #define PARAM_UNKNOWN 0xff #ifdef __cplusplus @@ -29,19 +33,22 @@ This data structure is filled by cgcomp, the offline compiler for shader program typedef struct rsx_vp { u16 magic; /*!< \brief magic identifier */ - u16 num_attrib; /*!< \brief number of used input attributes in the vertex program */ - u32 attrib_off; /*!< \brief offset to the attribute name table */ + u16 _pad0; /*!< \brief unused padding word. most be 0 */ + + u16 num_regs; /*!< \brief number of used registers in the vertex program */ + u16 num_attr; /*!< \brief number of used input attributes in the vertex program */ + u16 num_const; /*!< \brief number of used constants in the vertex program */ + u16 num_insn; /*!< \brief number of vertex shader instructions */ + + u32 attr_off; /*!< \brief offset to the attribute name table */ + u32 const_off; /*!< \brief offset to the constant name table */ + u32 ucode_off; /*!< \brief offset to the shader's micro code */ u32 input_mask; /*!< \brief mask of input attributes in the vertex shader */ u32 output_mask; /*!< \brief mask of result attributes passed to the fragment shader */ u16 const_start; /*!< \brief start address in vertex shader's constant block memory */ - u16 num_const; /*!< \brief number of used constants in the vertex program */ - u32 const_off; /*!< \brief offset to the constant name table */ - - u16 start_insn; /*!< \brief start address to load the vertex program to */ - u16 num_insn; /*!< \brief number of vertex shader instructions */ - u32 ucode_off; /*!< \brief offset to the shader's micro code */ + u16 insn_start; /*!< \brief start address to load the vertex program to */ } rsxVertexProgram; /*! \brief Fragment program data structure. @@ -50,23 +57,23 @@ This data structure is filled by cgcomp, the offline compiler for shader program typedef struct rsx_fp { u16 magic; /*!< \brief magic identifier */ - u16 num_attrib; /*!< \brief number of used input attributes in the fragment program */ - u32 attrib_off; /*!< \brief offset to the attribute name table */ + u16 _pad0; /*!< \brief unused padding word. most be 0 */ + + u16 num_regs; /*!< \brief number of used registers in the fragment program */ + u16 num_attr; /*!< \brief number of used input attributes in the fragment program */ + u16 num_const; /*!< \brief number of used constants in the fragment program */ + u16 num_insn; /*!< \brief number of fragment program instructions */ + + u32 attr_off; /*!< \brief offset to the attribute name table */ + u32 const_off; /*!< \brief offset to the constant name table */ + u32 ucode_off; /*!< \brief offset to the shaders's micro code */ - u32 num_regs; /*!< \brief number of used registers in the fragment program */ u32 fp_control; /*!< \brief fragment program control mask */ u16 texcoords; /*!< \brief bit mask of all used texture coords in the fragment program */ u16 texcoord2D; /*!< \brief bit mask of used 2D texture coords in the fragment program */ u16 texcoord3D; /*!< \brief bit mask of used 3D texture coords in the fragment program */ - - u16 _pad0; /*!< \brief unused padding word. most be 0 */ - - u16 num_const; /*!< \brief number of used constants in the fragment program */ - u32 const_off; /*!< \brief offset to the constant name table */ - - u16 num_insn; /*!< \brief number of fragment program instructions */ - u32 ucode_off; /*!< \brief offset to the shaders's micro code */ + u16 _pad1; /*!< \brief unused padding word. most be 0 */ } rsxFragmentProgram; /*! \brief Program const data structure. */ @@ -109,74 +116,128 @@ typedef struct rsx_attrib /*! \brief Get Ucode from RSX vertex program. \param vp Pointer the to vertex program structure. -\return Pointer to the ucode. +\param ucode Pointer-pointer to receive the vertex program ucode. +\param size Pointer to receive the vertex program ucode size. */ -void* rsxVertexProgramGetUCode(rsxVertexProgram *vp); +void rsxVertexProgramGetUCode(const rsxVertexProgram *vp,void **ucode,u32 *size); + +/*! \brief Get the count of vertex program consts. +\param vp Pointer the to vertex program structure. +\return Count of constants in the vertex program. +*/ +u16 rsxVertexProgramGetNumConst(const rsxVertexProgram *vp); /*! \brief Get the list of vertex program consts. \param vp Pointer the to vertex program structure. \return Pointer to the list of program const structures. */ -rsxProgramConst* rsxVertexProgramGetConsts(rsxVertexProgram *vp); +rsxProgramConst* rsxVertexProgramGetConsts(const rsxVertexProgram *vp); -/*! \brief Get id of vertex program const from its name. +/*! \brief Get index of vertex program const from its name. \param vp Pointer the to vertex program structure. \param name Name of the vertex program const. \return The requested vertex program const id. */ -s32 rsxVertexProgramGetConst(rsxVertexProgram *vp,const char *name); +s32 rsxVertexProgramGetConstIndex(const rsxVertexProgram *vp,const char *name); + +/*! \brief Get const value of vertex program const from its name. +\param vp Pointer the to vertex program structure. +\param name Name of the vertex program const. +\return The requested vertex program const value. +*/ +rsxProgramConst* rsxVertexProgramGetConst(const rsxVertexProgram *vp,const char *name); + +/*! \brief Get the count of vertex program attributes. +\param vp Pointer the to vertex program structure. +\return Count of attributes in the vertex program. +*/ +u16 rsxVertexProgramGetNumAttrib(const rsxVertexProgram *vp); /*! \brief Get the list of vertex program attributes. \param vp Pointer the to vertex program structure. \return Pointer to the list of program attribute structures. */ -rsxProgramAttrib* rsxVertexProgramGetAttribs(rsxVertexProgram *vp); +rsxProgramAttrib* rsxVertexProgramGetAttribs(const rsxVertexProgram *vp); -/*! \brief Get id of vertex program attribute from its name. +/*! \brief Get attribute value of vertex program attribute from its name. \param vp Pointer the to vertex program structure. \param name Name of the vertex program attribute. -\return The requested vertex program attribute id. +\return The requested vertex program attribute value. */ -s32 rsxVertexProgramGetAttrib(rsxVertexProgram *vp,const char *name); +rsxProgramAttrib* rsxVertexProgramGetAttrib(const rsxVertexProgram *vp,const char *name); + +/*! \brief Get index of vertex program attribute from its name. +\param vp Pointer the to vertex program structure. +\param name Name of the vertex program attribute. +\return The requested vertex program attribute index. +*/ +s32 rsxVertexProgramGetAttribIndex(const rsxVertexProgram *vp,const char *name); /*! \brief Get Ucode from RSX fragment program. \param fp Pointer the to fragment program structure. -\return Pointer to the ucode. +\param ucode Pointer-pointer to receive the fragment program ucode. +\param size Pointer to receive the fragment program ucode size. */ -void* rsxFragmentProgramGetUCode(rsxFragmentProgram *fp,u32 *size); +void rsxFragmentProgramGetUCode(const rsxFragmentProgram *fp,void **ucode,u32 *size); + +/*! \brief Get the count of fragment program consts. +\param fp Pointer the to fragment program structure. +\return Count of constants in the fragment program. +*/ +u16 rsxFragmentProgramGetNumConst(const rsxFragmentProgram *fp); /*! \brief Get the list of fragment program consts. \param fp Pointer the to fragment program structure. \return Pointer to the list of program const structures. */ -rsxProgramConst* rsxFragmentProgramGetConsts(rsxFragmentProgram *fp); +rsxProgramConst* rsxFragmentProgramGetConsts(const rsxFragmentProgram *fp); -/*! \brief Get id of fragment program const from its name. +/*! \brief Get index of fragment program const from its name. \param fp Pointer the to fragment program structure. \param name Name of the fragment program const. -\return The requested fragment program const id. +\return The requested fragment program const index. */ -s32 rsxFragmentProgramGetConst(rsxFragmentProgram *fp,const char *name); +s32 rsxFragmentProgramGetConstIndex(const rsxFragmentProgram *fp,const char *name); + +/*! \brief Get const value of fragment program const from its name. +\param fp Pointer the to fragment program structure. +\param name Name of the fragment program const. +\return The requested fragment program const value. +*/ +rsxProgramConst* rsxFragmentProgramGetConst(const rsxFragmentProgram *fp,const char *name); + +/*! \brief Get the count of fragment program attributes. +\param fp Pointer the to fragment program structure. +\return Count of attributes in the fragment program. +*/ +u16 rsxFragmentProgramGetNumAttrib(const rsxFragmentProgram *fp); /*! \brief Get the list of fragment program attributes. \param fp Pointer the to fragment program structure. \return Pointer to the list of program attribute structures. */ -rsxProgramAttrib* rsxFragmentProgramGetAttribs(rsxFragmentProgram *fp); +rsxProgramAttrib* rsxFragmentProgramGetAttribs(const rsxFragmentProgram *fp); + +/*! \brief Get index of fragment program attribute from its name. +\param fp Pointer the to fragment program structure. +\param name Name of the fragment program attribute. +\return The requested fragment program attribute index. +*/ +s32 rsxFragmentProgramGetAttribIndex(const rsxFragmentProgram *fp,const char *name); -/*! \brief Get id of fragment program attribute from its name. +/*! \brief Get attribute value of fragment program attribute from its name. \param fp Pointer the to fragment program structure. \param name Name of the fragment program attribute. -\return The requested fragment program attribute id. +\return The requested fragment program attribute value. */ -s32 rsxFragmentProgramGetAttrib(rsxFragmentProgram *fp,const char *name); +rsxProgramAttrib* rsxFragmentProgramGetAttrib(const rsxFragmentProgram *fp,const char *name); /*! \brief Get const offset table from a fragment program. \param fp Pointer the to fragment program structure. \param table_off Offset of the const offset table. \return Pointer to the requested const offset table. */ -rsxConstOffsetTable* rsxFragmentProgramGetConstOffsetTable(rsxFragmentProgram *fp,u32 table_off); +rsxConstOffsetTable* rsxFragmentProgramGetConstOffsetTable(const rsxFragmentProgram *fp,u32 table_off); #ifdef __cplusplus } diff --git a/ppu/include/ssl/ssl.h b/ppu/include/ssl/ssl.h index 41b70a6e..d4d80844 100644 --- a/ppu/include/ssl/ssl.h +++ b/ppu/include/ssl/ssl.h @@ -166,17 +166,17 @@ typedef void* sslCert; typedef void* sslCertName; -int sslInit(void *pool, size_t poolSize); +int sslInit(void *pool, uint32_t poolSize); int sslEnd(void); /* SSL certificate loader */ -int sslCertificateLoader(uint64_t flag, char *buffer, size_t size, size_t *required); +int sslCertificateLoader(uint64_t flag, char *buffer, uint32_t size, uint32_t *required); /* SSL certificate information get functions */ -int sslCertGetSerialNumber(const sslCert cert, const uint8_t **sboData, size_t *sboLength); -int sslCertGetPublicKey(const sslCert cert, const uint8_t **sboData, size_t *sboLength); -int sslCertGetRsaPublicKeyModulus(const sslCert cert, const uint8_t **sboData, size_t *sboLength); -int sslCertGetRsaPublicKeyExponent(const sslCert cert, const uint8_t **sboData, size_t *sboLength); +int sslCertGetSerialNumber(const sslCert cert, const uint8_t **sboData, uint32_t *sboLength); +int sslCertGetPublicKey(const sslCert cert, const uint8_t **sboData, uint32_t *sboLength); +int sslCertGetRsaPublicKeyModulus(const sslCert cert, const uint8_t **sboData, uint32_t *sboLength); +int sslCertGetRsaPublicKeyExponent(const sslCert cert, const uint8_t **sboData, uint32_t *sboLength); //int sslCertGetNotBefore(const sslCert cert, CellRtcTick *begin); //int sslCertGetNotAfter(const sslCert cert, CellRtcTick *limit); @@ -184,7 +184,7 @@ int sslCertGetSubjectName(const sslCert cert, const sslCertName *name); int sslCertGetIssuerName(const sslCert cert, const sslCertName *name); int sslCertGetNameEntryCount(const sslCert cert, uint32_t *entryCount); -int sslCertGetNameEntryInfo(const sslCert cert, uint32_t entryNum, const char **oidName, const uint8_t **value, size_t *valueLength, int32_t flag); +int sslCertGetNameEntryInfo(const sslCert cert, uint32_t entryNum, const char **oidName, const uint8_t **value, uint32_t *valueLength, int32_t flag); int sslCertGetMd5Fingerprint(const sslCert cert, const uint8_t *buf, uint32_t *plen); @@ -193,4 +193,3 @@ int sslCertGetMd5Fingerprint(const sslCert cert, const uint8_t *buf, uint32_t *p #endif /* __cplusplus */ #endif /* __SSL_H__ */ - diff --git a/ppu/include/sys/atomic.h b/ppu/include/sys/atomic.h index ce7ec789..6ec725fc 100644 --- a/ppu/include/sys/atomic.h +++ b/ppu/include/sys/atomic.h @@ -19,7 +19,7 @@ #include typedef struct { volatile u32 counter; } atomic_t; -typedef struct { u64 counter; } atomic64_t; +typedef struct { volatile u64 counter; } atomic64_t; static inline u32 sysAtomicRead(const atomic_t *v) { @@ -232,7 +232,7 @@ static inline u32 __xchg(volatile void *ptr, u32 x, unsigned int size) * and return the old value of *p. */ static inline u64 -__cmpxchg_u32(volatile unsigned int *p, u64 old, u64 new) +__cmpxchg_u32(volatile unsigned int *p, u64 oldv, u64 newv) { unsigned int prev; @@ -245,14 +245,14 @@ __cmpxchg_u32(volatile unsigned int *p, u64 old, u64 new) "\n\ 2:" : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) + : "r" (p), "r" (oldv), "r" (newv) : "cc", "memory"); return prev; } static inline u64 -__cmpxchg_u64(volatile u64 *p, u64 old, u64 new) +__cmpxchg_u64(volatile u64 *p, u64 oldv, u64 newv) { u64 prev; @@ -265,7 +265,7 @@ __cmpxchg_u64(volatile u64 *p, u64 old, u64 new) "\n\ 2:" : "=&r" (prev), "+m" (*p) - : "r" (p), "r" (old), "r" (new) + : "r" (p), "r" (oldv), "r" (newv) : "cc", "memory"); return prev; @@ -276,17 +276,17 @@ __cmpxchg_u64(volatile u64 *p, u64 old, u64 new) extern void __cmpxchg_called_with_bad_pointer(void); static inline u64 -__cmpxchg(volatile void *ptr, u64 old, u64 new, +__cmpxchg(volatile void *ptr, u64 oldv, u64 newv, unsigned int size) { switch (size) { case 4: - return __cmpxchg_u32(ptr, old, new); + return __cmpxchg_u32((volatile u32*)ptr, oldv, newv); case 8: - return __cmpxchg_u64(ptr, old, new); + return __cmpxchg_u64((volatile u64*)ptr, oldv, newv); } __cmpxchg_called_with_bad_pointer(); - return old; + return oldv; } #define cmpxchg(ptr, o, n) \ @@ -298,7 +298,7 @@ __cmpxchg(volatile void *ptr, u64 old, u64 new, }) #define sysAtomicCompareAndSwap(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define sysAtomicSwap(v, new) (xchg(&((v)->counter), new)) +#define sysAtomicSwap(v, new) (xchg(&((v)->counter), newv)) /** * atomic_add_unless - add unless the number is a given value @@ -309,7 +309,7 @@ __cmpxchg(volatile void *ptr, u64 old, u64 new, * Atomically adds @a to @v, so long as it was not @u. * Returns non-zero if @v was not @u, and zero otherwise. */ -static inline u32 sysAtomicAddUnless(atomic_t *v, u32 a, int u) +static inline u32 sysAtomicAddUnless(atomic_t *v, u32 a, u32 u) { u32 t; @@ -530,7 +530,7 @@ static inline u64 sysAtomic64DecIfPositive(atomic64_t *v) } #define sysAtomic64CompareAndSwap(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) -#define sysAtomic64Swap(v, new) (xchg(&((v)->counter), new)) +#define sysAtomic64Swap(v, new) (xchg(&((v)->counter), newv)) /** * atomic64_add_unless - add unless the number is a given value diff --git a/ppu/include/sys/cond.h b/ppu/include/sys/cond.h index 8ebbe18b..26bf1d43 100644 --- a/ppu/include/sys/cond.h +++ b/ppu/include/sys/cond.h @@ -24,6 +24,14 @@ typedef struct sys_cond_attr char name[8]; /*!< Name. */ } sys_cond_attr_t; +#define sysCondAttrInitialize(x) \ + do { \ + x.attr_pshared = SYS_COND_ATTR_PSHARED; \ + x.key = 0; \ + x.flags = 0; \ + x.name[0] = '\0'; \ + } while(0) + /*! \brief Create a condition variable. \param cond Pointer to storage for the created condition variable identifier. \param mutex Pointer to the associated mutex. diff --git a/ppu/include/sys/event_queue.h b/ppu/include/sys/event_queue.h index 00c5f780..ec39e690 100644 --- a/ppu/include/sys/event_queue.h +++ b/ppu/include/sys/event_queue.h @@ -28,6 +28,9 @@ /*! \brief Used to auto create a event queue key. */ #define SYS_EVENT_QUEUE_KEY_LOCAL 0x00 +/*! \brief Force destruction of event queue. */ +#define SYS_EVENT_QUEUE_FORCE_DESTROY 0x01 + #ifdef __cplusplus extern "C" { #endif diff --git a/ppu/include/sys/mutex.h b/ppu/include/sys/mutex.h index d785abe6..f65d0954 100644 --- a/ppu/include/sys/mutex.h +++ b/ppu/include/sys/mutex.h @@ -21,7 +21,7 @@ #define SYS_MUTEX_ATTR_NOT_RECURSIVE 0x0020 /*! \brief Default sharing policy for mutex attributes. */ -#define SYS_MUTEX_ATTR_PSHARED 0x0200 +#define SYS_MUTEX_ATTR_NOT_PSHARED 0x0200 /*! \brief Mutex is adaptive. */ #define SYS_MUTEX_ATTR_ADAPTIVE 0x1000 @@ -69,6 +69,17 @@ typedef struct sys_mutex_attr char name[8]; } sys_mutex_attr_t; +#define sysMutexAttrInitialize(x) \ + do{ \ + x.attr_protocol = SYS_MUTEX_PROTOCOL_PRIO; \ + x.attr_recursive = SYS_MUTEX_ATTR_NOT_RECURSIVE; \ + x.attr_pshared = SYS_MUTEX_ATTR_NOT_PSHARED; \ + x.attr_adaptive = SYS_MUTEX_ATTR_NOT_ADAPTIVE; \ + x.key = 0; \ + x.flags = 0; \ + x.name[0] = '\0'; \ + }while(0) + /*! \brief Create a mutex. \param mutex Pointer to storage for the mutex id. \param attr Pointer to the mutex attributes. diff --git a/ppu/include/sys/spu.h b/ppu/include/sys/spu.h index ff38d771..337ae63a 100644 --- a/ppu/include/sys/spu.h +++ b/ppu/include/sys/spu.h @@ -122,6 +122,20 @@ to the Cell Broadband Engine documentation. #define SPU_Sig_Notify_1 0x1400C //!< Signal notification 1 #define SPU_Sig_Notify_2 0x1C00C //!< Signal notification 2 +#define SPU_THREAD_GROUP_TYPE_NORMAL 0x0 +#define SPU_THREAD_GROUP_TYPE_SEQUENTIAL 0x1 +#define SPU_THREAD_GROUP_TYPE_SYSTEM 0x2 +#define SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER 0x4 + +#define SPU_THREAD_GROUP_JOIN_GROUP_EXIT 0x0001 +#define SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT 0x0002 +#define SPU_THREAD_GROUP_JOIN_TERMINATED 0x0004 + +#define SPU_THREAD_GROUP_EVENT_RUN 0x1 +#define SPU_THREAD_GROUP_EVENT_RUN_KEY 0xFFFFFFFF53505500ULL +#define SPU_THREAD_GROUP_EVENT_EXCEPTION 0x2 +#define SPU_THREAD_GROUP_EVENT_EXCEPTION_KEY 0xFFFFFFFF53505503ULL + //! No thread attributes #define SPU_THREAD_ATTR_NONE 0x00 //! Enables interrupts. @@ -148,6 +162,19 @@ to the Cell Broadband Engine documentation. //! Configure signal notification register 2 to OR mode #define SPU_SIGNAL2_OR 0x02 +/* exception causes */ +#define SPU_EXCEPTION_DMA_ALIGNMENT 0x0001U +#define SPU_EXCEPTION_DMA_COMMAND 0x0002U +#define SPU_EXCEPTION_SPU_ERROR 0x0004U +#define SPU_EXCEPTION_MFC_FIR 0x0008U +#define SPU_EXCEPTION_MFC_SEGMENT 0x0010U +#define SPU_EXCEPTION_MFC_STORAGE 0x0020U +#define SPU_EXCEPTION_STOP_CALL 0x0100U +#define SPU_EXCEPTION_STOP_BREAK 0x0200U +#define SPU_EXCEPTION_HALT 0x0400U +#define SPU_EXCEPTION_UNKNOWN_SIGNAL 0x0800U +#define SPU_EXCEPTION_NO_VALUE 0x0U + //! Base of memory-mapped SPU thread resources #define SPU_THREAD_BASE 0xF0000000ULL //! Offset between resources for consecutive SPU threads @@ -211,20 +238,83 @@ typedef struct _sys_spu_thread_arg */ typedef struct _sys_spu_thread_attr { - u32 nameAddress; //!< Effective address of the thread's name string. - u32 nameSize; //!< Size of the name string in bytes (including terminating null byte). - u32 attribute; //!< OR'ed list of SPU thread attribute flags (or \ref SPU_THREAD_ATTR_NONE) + const char *name ATTRIBUTE_PRXPTR; //!< Effective address of the thread's name string. + u32 nsize; //!< Size of the name string in bytes (including terminating null byte). + u32 option; //!< OR'ed list of SPU thread attribute flags (or \ref SPU_THREAD_ATTR_NONE) } sysSpuThreadAttribute; //! A structure containing SPU thread group attributes. typedef struct _sys_spu_thread_group_attr { - u32 nameSize; //!< Size of the name string in bytes (including terminating null byte). - u32 nameAddress; //!< Effective address of the thread group's name string. - u32 groupType; //!< Thread group type (\c 0 for normal thread groups). - u32 memContainer; //!< Memory container id (\c 0 for normal thread groups). + u32 nsize; //!< Size of the name string in bytes (including terminating null byte). + const char *name ATTRIBUTE_PRXPTR; //!< Effective address of the thread group's name string. + u32 type; //!< Thread group type (\c 0 for normal thread groups). + union { + sys_mem_container_t ct; //!< Memory container id (\c 0 for normal thread groups). + } option; } sysSpuThreadGroupAttribute; +#define sysSpuThreadAttributeInitialize(x) \ + do { \ + x.name = NULL; \ + x.nsize = 0; \ + x.option = SPU_THREAD_ATTR_NONE; \ + } while(0) + +#define sysSpuThreadAttributeName(x, s) \ + do { \ + x.name = s; \ + if(s == NULL) { \ + x.nsize = 0; \ + } else { \ + int n = 0; \ + for(; (n<127) && (s[n] != '\0'); n++) \ + ; \ + x.nsize = n + 1; \ + } \ + } while(0) + +#define sysSpuThreadAttributeOption(x, f) \ + do { \ + x.option = f; \ + } while(0) + +#define sysSpuThreadArgumentInitialize(x) \ + do { \ + x.arg0 = x.arg1 = x.arg2 = x.arg3 = 0; \ + } while(0) + +#define sysSpuThreadGroupAttributeInitialize(x) \ + do { \ + x.name = NULL; \ + x.nsize = 0; \ + x.type = SPU_THREAD_GROUP_TYPE_NORMAL; \ + } while(0) + +#define sysSpuThreadGroupAttributeName(x, s) \ + do { \ + x.name = s; \ + if(s == NULL) { \ + x.nsize = 0; \ + } else { \ + int n = 0; \ + for(; (n<127) && (s[n] != '\0'); n++) \ + ; \ + x.nsize = n + 1; \ + } \ + } while(0) + +#define sysSpuThreadGroupAttributeType(x, t) \ + do { \ + x.type = t; \ + } while(0) + +#define sysSpuThreadGroupAttributeMemoryContainer(x, ct) \ + do { \ + x.type |= SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER; \ + x.option.ct = ct; \ + } while(0) + /*! \brief Initialize the SPU management. \param spus Total number of needed SPUs (from 1 to 6). diff --git a/ppu/include/sys/spu_thread_printf.h b/ppu/include/sys/spu_thread_printf.h new file mode 100644 index 00000000..ef3e51ac --- /dev/null +++ b/ppu/include/sys/spu_thread_printf.h @@ -0,0 +1,17 @@ +#ifndef __LV2_SPU_THREAD_PRINTF_H__ +#define __LV2_SPU_THREAD_PRINTF_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +s32 spu_thread_printf(sys_spu_thread_t id, u32 arg_addr); +s32 spu_thread_sprintf(char *buf, sys_spu_thread_t id, u32 arg_addr); + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/ppu/include/sysutil/video.h b/ppu/include/sysutil/video.h index 36534d90..6b22cab7 100644 --- a/ppu/include/sysutil/video.h +++ b/ppu/include/sysutil/video.h @@ -211,6 +211,7 @@ typedef struct _videoDeviceInfo videoKSVList ksvList; } videoDeviceInfo; +typedef s32 (*videoCallback)(u32 slot, u32 videoOut, u32 deviceIndex, u32 event, videoDeviceInfo *info, void *userData); /*! \brief Get video state @@ -251,9 +252,8 @@ s32 videoGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u s32 videoDebugSetMonitorType(u32 videoOut, u32 monitorType); s32 videoGetConvertCursorColorInfo(u8 *rgbOutputRange); -/* TODO: typedef int (*videoCallback)(u32 slot, u32 videoOut, u32 deviceIndex, u32 event, videoDeviceInfo *info, void *userData ); */ -/* TODO: s32 videoRegisterCallback(u32 slot, videoCallback function, void *userData); */ -/* TODO: s32 videoUnregisterCallback(u32 slot); */ +s32 videoRegisterCallback(u32 slot, videoCallback cbVideo, void *userData); +s32 videoUnregisterCallback(u32 slot); #ifdef __cplusplus } diff --git a/ppu/librsx/Makefile b/ppu/librsx/Makefile index 61472c3d..fcfc3615 100644 --- a/ppu/librsx/Makefile +++ b/ppu/librsx/Makefile @@ -44,7 +44,8 @@ VPATH := $(BASEDIR) #--------------------------------------------------------------------------------- OBJS := \ - init.o buffer.o commands.o mm.o vertex_program.o fragment_program.o + init.o buffer.o commands.o mm.o vertex_program.o fragment_program.o \ + rsx_internal.o all: ppu diff --git a/ppu/librsx/buffer.c b/ppu/librsx/buffer.c index 451b0630..1dfa80f8 100644 --- a/ppu/librsx/buffer.c +++ b/ppu/librsx/buffer.c @@ -4,34 +4,20 @@ #include #include -void rsxResetCommandBuffer(gcmContextData *context) -{ - u32 offset = 0x1000; // init state offset; - rsxSetJumpCommand(context,offset); +#define RSX_INTERNAL 0 - __sync(); - - gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); - ctrl->put = offset; - while(ctrl->get!=offset) usleep(30); -} - -void rsxFlushBuffer(gcmContextData *context) -{ - u32 offset = 0; - gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); - - __sync(); - gcmAddressToOffset(context->current,&offset); - ctrl->put = offset; -} - -void rsxFinish(gcmContextData *context,u32 ref_value) -{ - rsxSetReferenceCommand(context,ref_value); - rsxFlushBuffer(context); - - gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); - while(ctrl->ref!=ref_value) usleep(30); -} +#define RSX_UNSAFE 1 +#define RSX_FUNCTION_MACROS +#include +#include "buffer_impl.h" +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE +#define RSX_UNSAFE 0 +#define RSX_FUNCTION_MACROS +#include +#include "buffer_impl.h" +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE diff --git a/ppu/librsx/buffer_impl.h b/ppu/librsx/buffer_impl.h new file mode 100644 index 00000000..bb13d0ca --- /dev/null +++ b/ppu/librsx/buffer_impl.h @@ -0,0 +1,31 @@ +void RSX_FUNC(ResetCommandBuffer)(gcmContextData *context) +{ + u32 offset = 0x1000; // init state offset; + RSX_FUNC(SetJumpCommand)(context,offset); + + __sync(); + + gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); + ctrl->put = offset; + while(ctrl->get!=offset) usleep(30); +} + +void RSX_FUNC(FlushBuffer)(gcmContextData *context) +{ + u32 offset = 0; + gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); + + __sync(); + gcmAddressToOffset(context->current,&offset); + ctrl->put = offset; +} + +void RSX_FUNC(Finish)(gcmContextData *context,u32 ref_value) +{ + RSX_FUNC(SetReferenceCommand)(context,ref_value); + RSX_FUNC(FlushBuffer)(context); + + gcmControlRegister volatile *ctrl = gcmGetControlRegister(context); + while(ctrl->ref!=ref_value) usleep(30); +} + diff --git a/ppu/librsx/commands.c b/ppu/librsx/commands.c index 17ae1232..1a6ac57a 100644 --- a/ppu/librsx/commands.c +++ b/ppu/librsx/commands.c @@ -3,9 +3,10 @@ #include #include -#include "commands.h" #include "rsx_internal.h" +#define RSX_INTERNAL 1 + #ifndef RSX_MEMCPY #define RSX_MEMCPY __builtin_memcpy #endif @@ -18,1024 +19,20 @@ static __inline__ f32 swapF32_16(f32 v) return d.f; } -s32 __attribute__((noinline)) rsxContextCallback(gcmContextData *context,u32 count) -{ - register s32 result asm("r3"); - asm volatile ( - "stdu 1,-128(1)\n" - "mr 31,2\n" - "lwz 0,0(%1)\n" - "lwz 2,4(%1)\n" - "mtctr 0\n" - "bctrl\n" - "mr 2,31\n" - "addi 1,1,128\n" - : "+r"(result) - : "b"(context->callback) - : "r31", "r0", "lr" - ); - return result; -} - -void rsxSetReturnCommand(gcmContextData *context) -{ - RSX_CONTEXT_CURRENT_BEGIN(1); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_FLAG_RETURN; - RSX_CONTEXT_CURRENT_END(1); -} - -void rsxSetCallCommand(gcmContextData *context,u32 offset) -{ - RSX_CONTEXT_CURRENT_BEGIN(1); - RSX_CONTEXT_CURRENTP[0] = (offset | RSX_METHOD_FLAG_CALL); - RSX_CONTEXT_CURRENT_END(1); -} - -void rsxSetJumpCommand(gcmContextData *context,u32 offset) -{ - RSX_CONTEXT_CURRENT_BEGIN(1); - RSX_CONTEXT_CURRENTP[0] = (offset | RSX_METHOD_FLAG_JUMP); - RSX_CONTEXT_CURRENT_END(1); -} - -void rsxSetNopCommand(gcmContextData *context,u32 count) -{ - u32 i; - - RSX_CONTEXT_CURRENT_BEGIN(count); - for(i=0;i>16)&0xff) | ((value&0xff)<<16); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SEMAPHORE_OFFSET,1); - RSX_CONTEXT_CURRENTP[1] = offset; - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_SEMAPHORE_BACKENDWRITE_RELEASE,1); - RSX_CONTEXT_CURRENTP[3] = wvalue; - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxSetWaitLabel(gcmContextData *context,u8 index,u32 value) -{ - u32 offset = 0x10*index; - - RSX_CONTEXT_CURRENT_BEGIN(4); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV406ETCL_SEMAPHORE_OFFSET,1); - RSX_CONTEXT_CURRENTP[1] = offset; - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV406ETCL_SEMAPHORE_ACQUIRE,1); - RSX_CONTEXT_CURRENTP[3] = value; - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxSetWriteCommandLabel(gcmContextData *context,u8 index,u32 value) -{ - u32 offset = 0x10*index; - - RSX_CONTEXT_CURRENT_BEGIN(4); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV406ETCL_SEMAPHORE_OFFSET,1); - RSX_CONTEXT_CURRENTP[1] = offset; - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV406ETCL_SEMAPHORE_RELEASE,1); - RSX_CONTEXT_CURRENTP[3] = value; - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxSetSurface(gcmContextData *context,gcmSurface *surface) -{ - RSX_CONTEXT_CURRENT_BEGIN(32); - - u32 log2Width = 31 - __cntlzw(surface->width); - u32 log2Height = 31 - __cntlzw(surface->height); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DMA_COLOR0,1); - RSX_CONTEXT_CURRENTP[1] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[0]; - - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_DMA_COLOR1,1); - RSX_CONTEXT_CURRENTP[3] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[1]; - - RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_DMA_COLOR2,2); - RSX_CONTEXT_CURRENTP[5] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[2]; - RSX_CONTEXT_CURRENTP[6] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[3]; - - RSX_CONTEXT_CURRENTP[7] = RSX_METHOD(NV40TCL_DMA_ZETA,1); - RSX_CONTEXT_CURRENTP[8] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->depthLocation; - - RSX_CONTEXT_CURRENTP[9] = RSX_METHOD(NV40TCL_RT_FORMAT,6); - RSX_CONTEXT_CURRENTP[10] = ((log2Height<antiAlias<type<depthFormat<colorFormat<colorPitch[0]; - RSX_CONTEXT_CURRENTP[12] = surface->colorOffset[0]; - RSX_CONTEXT_CURRENTP[13] = surface->depthOffset; - RSX_CONTEXT_CURRENTP[14] = surface->colorOffset[1]; - RSX_CONTEXT_CURRENTP[15] = surface->colorPitch[1]; - - RSX_CONTEXT_CURRENTP[16] = RSX_METHOD(NV40TCL_ZETA_PITCH,1); - RSX_CONTEXT_CURRENTP[17] = surface->depthPitch; - - RSX_CONTEXT_CURRENTP[18] = RSX_METHOD(NV40TCL_COLOR2_PITCH,4); - RSX_CONTEXT_CURRENTP[19] = surface->colorPitch[2]; - RSX_CONTEXT_CURRENTP[20] = surface->colorPitch[3]; - RSX_CONTEXT_CURRENTP[21] = surface->colorOffset[2]; - RSX_CONTEXT_CURRENTP[22] = surface->colorOffset[3]; - - RSX_CONTEXT_CURRENTP[23] = RSX_METHOD(NV40TCL_RT_ENABLE,1); - RSX_CONTEXT_CURRENTP[24] = surface->colorTarget; - - RSX_CONTEXT_CURRENTP[25] = RSX_METHOD(NV40TCL_WINDOW_OFFSET,1); - RSX_CONTEXT_CURRENTP[26] = ((surface->y<<16) | surface->x); - - RSX_CONTEXT_CURRENTP[27] = RSX_METHOD(NV40TCL_RT_HORIZ,2); - RSX_CONTEXT_CURRENTP[28] = ((surface->width<<16) | surface->x); - RSX_CONTEXT_CURRENTP[29] = ((surface->height<<16) | surface->y); - - RSX_CONTEXT_CURRENTP[30] = RSX_METHOD(NV40TCL_SHADER_WINDOW,1); - RSX_CONTEXT_CURRENTP[31] = ((0<<16) | (1<<12) | surface->height); - - RSX_CONTEXT_CURRENT_END(32); -} - -void rsxSetColorMask(gcmContextData *context,u32 mask) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_COLOR_MASK,1); - RSX_CONTEXT_CURRENTP[1] = mask; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetColorMaskMRT(gcmContextData *context,u32 mask) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_MRT_COLOR_MASK,1); - RSX_CONTEXT_CURRENTP[1] = mask; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetShadeModel(gcmContextData *context,u32 shadeModel) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SHADE_MODEL,1); - RSX_CONTEXT_CURRENTP[1] = shadeModel; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetViewport(gcmContextData *context,u16 x,u16 y,u16 width,u16 height,f32 min,f32 max,const f32 scale[4],const f32 offset[4]) -{ - ieee32 _min,_max; - ieee32 _offset[4],_scale[4]; - - _min.f = min; - _max.f = max; - - _scale[0].f = scale[0]; - _scale[1].f = scale[1]; - _scale[2].f = scale[2]; - _scale[3].f = scale[3]; - - _offset[0].f = offset[0]; - _offset[1].f = offset[1]; - _offset[2].f = offset[2]; - _offset[3].f = offset[3]; - - RSX_CONTEXT_CURRENT_BEGIN(24); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VIEWPORT_HORIZ,2); - RSX_CONTEXT_CURRENTP[1] = ((width<<16) | x); - RSX_CONTEXT_CURRENTP[2] = ((height<<16) | y); - - RSX_CONTEXT_CURRENTP[3] = RSX_METHOD(NV40TCL_DEPTH_RANGE,2); - RSX_CONTEXT_CURRENTP[4] = _min.u; - RSX_CONTEXT_CURRENTP[5] = _max.u; - - RSX_CONTEXT_CURRENTP[6] = RSX_METHOD(NV40TCL_VIEWPORT_OFFSET,8); - RSX_CONTEXT_CURRENTP[7] = _offset[0].u; - RSX_CONTEXT_CURRENTP[8] = _offset[1].u; - RSX_CONTEXT_CURRENTP[9] = _offset[2].u; - RSX_CONTEXT_CURRENTP[10] = _offset[3].u; - RSX_CONTEXT_CURRENTP[11] = _scale[0].u; - RSX_CONTEXT_CURRENTP[12] = _scale[1].u; - RSX_CONTEXT_CURRENTP[13] = _scale[2].u; - RSX_CONTEXT_CURRENTP[14] = _scale[3].u; - - RSX_CONTEXT_CURRENTP[15] = RSX_METHOD(NV40TCL_VIEWPORT_OFFSET,8); - RSX_CONTEXT_CURRENTP[16] = _offset[0].u; - RSX_CONTEXT_CURRENTP[17] = _offset[1].u; - RSX_CONTEXT_CURRENTP[18] = _offset[2].u; - RSX_CONTEXT_CURRENTP[19] = _offset[3].u; - RSX_CONTEXT_CURRENTP[20] = _scale[0].u; - RSX_CONTEXT_CURRENTP[21] = _scale[1].u; - RSX_CONTEXT_CURRENTP[22] = _scale[2].u; - RSX_CONTEXT_CURRENTP[23] = _scale[3].u; - - RSX_CONTEXT_CURRENT_END(24); -} - -void rsxSetViewportClip(gcmContextData *context,u8 sel,u16 width,u16 height) -{ - RSX_CONTEXT_CURRENT_BEGIN(3); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VIEWPORT_CLIP_HORIZ(sel),2); - RSX_CONTEXT_CURRENTP[1] = ((width-1) << 16); - RSX_CONTEXT_CURRENTP[2] = ((height-1) << 16); - - RSX_CONTEXT_CURRENT_END(3); -} - -void rsxSetUserClipPlaneControl(gcmContextData *context,u32 plane0,u32 plane1,u32 plane2,u32 plane3,u32 plane4,u32 plane5) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CLIP_PLANE_ENABLE,1); - RSX_CONTEXT_CURRENTP[1] = ((plane5 << 20) | (plane4 << 16) | (plane3 << 12) | (plane2 << 8) | (plane1 << 4) | plane0); - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetDepthTestEnable(gcmContextData *context,u32 enable) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_TEST_ENABLE,1); - RSX_CONTEXT_CURRENTP[1] = enable; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetDepthFunc(gcmContextData *context,u32 func) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_FUNC,1); - RSX_CONTEXT_CURRENTP[1] = func; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetDepthWriteEnable(gcmContextData *context,u32 enable) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_WRITE_ENABLE,1); - RSX_CONTEXT_CURRENTP[1] = enable; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetCullFaceEnable(gcmContextData *context,u32 enable) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CULL_FACE_ENABLE,1); - RSX_CONTEXT_CURRENTP[1] = enable; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetCullFace(gcmContextData *context,u32 cull) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CULL_FACE,1); - RSX_CONTEXT_CURRENTP[1] = cull; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxSetFrontFace(gcmContextData *context,u32 dir) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FRONT_FACE,1); - RSX_CONTEXT_CURRENTP[1] = dir; - - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxClearSurface(gcmContextData *context,u32 clear_mask) -{ - RSX_CONTEXT_CURRENT_BEGIN(4); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CLEAR_BUFFERS,1); - RSX_CONTEXT_CURRENTP[1] = clear_mask; - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_NOP,1); - RSX_CONTEXT_CURRENTP[3] = 0; - - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxLoadVertexProgramBlock(gcmContextData *context,rsxVertexProgram *program,const void *ucode) -{ - u32 pos = 0; - const u32 *data = (const u32*)ucode; - u32 startIndex = program->start_insn; - u32 i,instCount = program->num_insn; - - RSX_CONTEXT_CURRENT_BEGIN(6+5*instCount); - - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV40TCL_VP_UPLOAD_FROM_ID,2); - RSX_CONTEXT_CURRENTP[pos++] = startIndex; - RSX_CONTEXT_CURRENTP[pos++] = startIndex; - - for(i=0;iinput_mask; - RSX_CONTEXT_CURRENTP[pos++] = program->output_mask; - - RSX_CONTEXT_CURRENT_END(6+5*instCount); -} - -void rsxLoadFragmentProgramLocation(gcmContextData *context,rsxFragmentProgram *program,u32 offset,u32 location) -{ - u32 i,fpcontrol; - u32 texcoords,texcoord2D,texcoord3D; - - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FP_ADDRESS,1); - RSX_CONTEXT_CURRENTP[1] = ((location + 1) | offset); - RSX_CONTEXT_CURRENT_END(2); - - texcoords = program->texcoords; - texcoord2D = program->texcoord2D; - texcoord3D = program->texcoord3D; - for(i=0;texcoords;i++) { - if(texcoords&1) { - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_COORD_CONTROL(i),1); - RSX_CONTEXT_CURRENTP[1] = (((texcoord3D&1) << 4) | (texcoord2D&1)); - RSX_CONTEXT_CURRENT_END(2); - } - texcoords >>= 1; - texcoord2D >>= 1; - texcoord3D >>= 1; - } - - { - RSX_CONTEXT_CURRENT_BEGIN(2); - - fpcontrol = program->fp_control | (program->num_regs << NV40TCL_FP_CONTROL_TEMP_COUNT_SHIFT); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FP_CONTROL,1); - RSX_CONTEXT_CURRENTP[1] = fpcontrol; - - RSX_CONTEXT_CURRENT_END(2); - } -} - -void rsxLoadVertexProgramParameterBlock(gcmContextData *context,u32 base_const,u32 const_cnt,const f32 *value) -{ - u32 i,curr = 0; - - RSX_CONTEXT_CURRENT_BEGIN(const_cnt*6); - - for(i=0;iconst_start; - rsxProgramConst *consts = rsxVertexProgramGetConsts(program); - - rsxLoadVertexProgramBlock(context,program,ucode); - - for(i=0;inum_const;i++) { - if(consts[i].is_internal) - rsxLoadVertexProgramParameterBlock(context,consts[i].index + base_const,1,(f32*)consts[i].values); - } -} - -void rsxSetVertexProgramParameter(gcmContextData *context,rsxVertexProgram *program,s32 index,const f32 *value) -{ - u32 base_const = program->const_start; - rsxProgramConst *consts = rsxVertexProgramGetConsts(program); - - rsxLoadVertexProgramParameterBlock(context,consts[index].index + base_const,consts[index].count,value); -} - -void rsxSetFragmentProgramParameter(gcmContextData *context,rsxFragmentProgram *program,s32 index,const f32 *value,u32 offset) -{ - s32 i; - f32 params[4] = {0.0f,0.0f,0.0f,0.0f}; - rsxProgramConst *consts = rsxFragmentProgramGetConsts(program); - - switch(consts[index].type) { - case PARAM_FLOAT4x4: - { - s32 j,cnt = consts[index].count; - for(j=0;jnum;i++) - rsxInlineTransfer(context,offset + co_table->offset[i],params,4,GCM_LOCATION_RSX); - } - } - return; - } - - case PARAM_FLOAT4: - params[3] = swapF32_16(value[3]); - case PARAM_FLOAT3: - params[2] = swapF32_16(value[2]); - case PARAM_FLOAT2: - params[1] = swapF32_16(value[1]); - case PARAM_FLOAT: - params[0] = swapF32_16(value[0]); - break; - } - - if(consts[index].index!=0xffffffff) { - rsxConstOffsetTable *co_table = rsxFragmentProgramGetConstOffsetTable(program,consts[index].index); - - for(i=0;inum;i++) - rsxInlineTransfer(context,offset + co_table->offset[i],params,4,GCM_LOCATION_RSX); - } -} - -void rsxDrawVertexBegin(gcmContextData *context,u32 type) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[1] = type; - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxDrawVertexEnd(gcmContextData *context) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxDrawVertex2f(gcmContextData *context,u8 idx,f32 x,f32 y) -{ - ieee32 d[2]; - d[0].f = x; d[1].f = y; - - RSX_CONTEXT_CURRENT_BEGIN(3); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_2F_X(idx),2); - RSX_CONTEXT_CURRENTP[1] = d[0].u; - RSX_CONTEXT_CURRENTP[2] = d[1].u; - - RSX_CONTEXT_CURRENT_END(3); -} - -void rsxDrawVertex3f(gcmContextData *context,u8 idx,f32 x,f32 y,f32 z) -{ - ieee32 d[3]; - d[0].f = x; d[1].f = y; d[2].f = z; - - RSX_CONTEXT_CURRENT_BEGIN(4); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_3F_X(idx),3); - RSX_CONTEXT_CURRENTP[1] = d[0].u; - RSX_CONTEXT_CURRENTP[2] = d[1].u; - RSX_CONTEXT_CURRENTP[3] = d[2].u; - - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxDrawVertex4f(gcmContextData *context,u8 idx,f32 x,f32 y,f32 z,f32 w) -{ - ieee32 d[4]; - d[0].f = x; d[1].f = y; d[2].f = z; d[3].f = w; - - RSX_CONTEXT_CURRENT_BEGIN(5); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_4F_X(idx),4); - RSX_CONTEXT_CURRENTP[1] = d[0].u; - RSX_CONTEXT_CURRENTP[2] = d[1].u; - RSX_CONTEXT_CURRENTP[3] = d[2].u; - RSX_CONTEXT_CURRENTP[4] = d[3].u; - - RSX_CONTEXT_CURRENT_END(5); -} - -void rsxInvalidateTextureCache(gcmContextData *context,u32 type) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_CACHE_CTL,1); - RSX_CONTEXT_CURRENTP[1] = type; - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxLoadTexture(gcmContextData *context,u8 index,const gcmTexture *texture) -{ - u32 format,offset,swizzle,size0,size1; - - RSX_CONTEXT_CURRENT_BEGIN(9); - - offset = texture->offset; - format = ((texture->location + 1) | (texture->cubemap << 2) | - (texture->dimension << NV40TCL_TEX_FORMAT_DIMS_SHIFT) | - (texture->format << NV40TCL_TEX_FORMAT_FORMAT_SHIFT) | - (texture->mipmap << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT) | - NV40TCL_TEX_FORMAT_NO_BORDER | 0x8000); - swizzle = texture->remap; - size0 = (texture->width << NV40TCL_TEX_SIZE0_W_SHIFT) | texture->height; - size1 = (texture->depth << NV40TCL_TEX_SIZE1_DEPTH_SHIFT) | texture->pitch; - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_OFFSET(index),2); // set offset and format for texture at once - RSX_CONTEXT_CURRENTP[1] = offset; - RSX_CONTEXT_CURRENTP[2] = format; - - RSX_CONTEXT_CURRENTP[3] = RSX_METHOD(NV40TCL_TEX_SWIZZLE(index),1); // set remap order or swizzle respectively for texture - RSX_CONTEXT_CURRENTP[4] = swizzle; - - RSX_CONTEXT_CURRENTP[5] = RSX_METHOD(NV40TCL_TEX_SIZE0(index),1); // set width and height for texture - RSX_CONTEXT_CURRENTP[6] = size0; - - RSX_CONTEXT_CURRENTP[7] = RSX_METHOD(NV40TCL_TEX_SIZE1(index),1); // set pitch and depth for texture - RSX_CONTEXT_CURRENTP[8] = size1; - - RSX_CONTEXT_CURRENT_END(9); -} - -void rsxTextureControl(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod,u8 maxaniso) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_ENABLE(index),1); - RSX_CONTEXT_CURRENTP[1] = ((enable << NV40TCL_TEX_ENABLE_SHIFT) | (minlod << NV40TCL_TEX_MINLOD_SHIFT) | (maxlod << NV40TCL_TEX_MAXLOD_SHIFT) | (maxaniso << NV40TCL_TEX_MAXANISO_SHIFT)); - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxTextureFilter(gcmContextData *context,u8 index,u8 min,u8 mag,u8 conv) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_FILTER(index),1); - RSX_CONTEXT_CURRENTP[1] = ((mag << NV40TCL_TEX_FILTER_MAG_SHIFT) | (min << NV40TCL_TEX_FILTER_MIN_SHIFT) | (conv << NV40TCL_TEX_FILTER_CONV_SHIFT)); - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxTextureWrapMode(gcmContextData *context,u8 index,u8 wraps,u8 wrapt,u8 wrapr,u8 unsignedRemap,u8 zfunc,u8 gamma) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_WRAP(index),1); - RSX_CONTEXT_CURRENTP[1] = ((wraps << NV40TCL_TEX_WRAP_S_SHIFT) | - (wrapt << NV40TCL_TEX_WRAP_T_SHIFT) | - (wrapr << NV40TCL_TEX_WRAP_R_SHIFT) | - (unsignedRemap << NV40TCL_TEX_UREMAP_SHIFT) | - (gamma << NV40TCL_TEX_GAMMA_SHIFT) | - (zfunc << NV40TCL_TEX_ZFUNC_SHIFT)); - RSX_CONTEXT_CURRENT_END(2); -} - -void rsxZControl(gcmContextData *context,u8 cullNearFar,u8 zClampEnable,u8 cullIgnoreW) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_CONTROL,1); - RSX_CONTEXT_CURRENTP[1] = (cullNearFar | (zClampEnable<<4) | (cullIgnoreW<<8)); - RSX_CONTEXT_CURRENT_END(2); -} +#define RSX_UNSAFE 1 +#define RSX_FUNCTION_MACROS +#include +#include "commands_impl.h" +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE -void rsxBindVertexArrayAttrib(gcmContextData *context,u8 attr,u32 offset,u8 stride,u8 elems,u8 dtype,u8 location) -{ - RSX_CONTEXT_CURRENT_BEGIN(4); +#define RSX_UNSAFE 0 +#define RSX_FUNCTION_MACROS +#include +#include "commands_impl.h" +#undef RSX_FUNCTION_MACROS +#include +#undef RSX_UNSAFE - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTXBUF_ADDRESS(attr),1); - RSX_CONTEXT_CURRENTP[1] = ((location << 31) | offset); - - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_VTXFMT(attr),1); - RSX_CONTEXT_CURRENTP[3] = ((stride << NV40TCL_VTXFMT_STRIDE_SHIFT) | (elems << NV40TCL_VTXFMT_SIZE_SHIFT) | dtype); - - RSX_CONTEXT_CURRENT_END(4); -} - -void rsxDrawVertexArray(gcmContextData *context,u32 type,u32 start,u32 count) -{ - RSX_CONTEXT_CURRENT_BEGIN(6); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE,3); - RSX_CONTEXT_CURRENTP[1] = 0; - RSX_CONTEXT_CURRENTP[2] = 0; - RSX_CONTEXT_CURRENTP[3] = 0; - - RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[5] = type; - - RSX_CONTEXT_CURRENT_END(6); - - while(count) { - u32 rem = count; - - if(rem>256) rem = 256; - - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VB_VERTEX_BATCH,1); - RSX_CONTEXT_CURRENTP[1] = (((rem - 1) << 24) | start); - RSX_CONTEXT_CURRENT_END(2); - - count -= rem; - start += rem; - } - - { - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; - - RSX_CONTEXT_CURRENT_END(2); - } -} - -void rsxDrawIndexArray(gcmContextData *context,u32 type,u32 offset,u32 count,u32 data_type,u32 location) -{ - u32 start; - - RSX_CONTEXT_CURRENT_BEGIN(7); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE,1); - RSX_CONTEXT_CURRENTP[1] = 0; - - RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_VB_INDEX_BATCH_OFFSET,2); - RSX_CONTEXT_CURRENTP[3] = offset; - RSX_CONTEXT_CURRENTP[4] = (((data_type) << 4) | location); - - RSX_CONTEXT_CURRENTP[5] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[6] = type; - - RSX_CONTEXT_CURRENT_END(7); - - start = 0; - while(count) { - u32 rem = count; - - if(rem>256) rem = 256; - - RSX_CONTEXT_CURRENT_BEGIN(2); - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VB_INDEX_BATCH_DRAW,1); - RSX_CONTEXT_CURRENTP[1] = (((rem - 1) << 24) | start); - RSX_CONTEXT_CURRENT_END(2); - - count -= rem; - start += rem; - } - - { - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); - RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; - - RSX_CONTEXT_CURRENT_END(2); - } -} - -void rsxSetScissor(gcmContextData *context,u16 x,u16 y,u16 w,u16 h) -{ - RSX_CONTEXT_CURRENT_BEGIN(3); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SCISSOR_HORIZ,2); - RSX_CONTEXT_CURRENTP[1] = ((w<<16) | x); - RSX_CONTEXT_CURRENTP[2] = ((h<<16) | y); - - RSX_CONTEXT_CURRENT_END(3); -} - -void rsxInlineTransfer(gcmContextData *context,const u32 dstOffset,const void *srcAddress,const u32 sizeInWords,const u8 location) -{ - u32 *src; - u32 pos,cnt; - u32 padSizeInWords; - u32 alignedVideoOffset; - u32 pixelShift; - - alignedVideoOffset = dstOffset&~0x3f; - pixelShift = (dstOffset&0x3f)>>2; - - padSizeInWords = (sizeInWords + 1)&~0x01; - - RSX_CONTEXT_CURRENT_BEGIN(12 + padSizeInWords); - - pos = 0; - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV3062TCL_SET_CONTEXT_DMA_IMAGE_DEST,1); - RSX_CONTEXT_CURRENTP[pos++] = GCM_DMA_MEMORY_FRAME_BUFFER + location; - - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV3062TCL_SET_OFFSET_DEST,1); - RSX_CONTEXT_CURRENTP[pos++] = alignedVideoOffset; - - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV3062TCL_SET_COLOR_FORMAT,2); - RSX_CONTEXT_CURRENTP[pos++] = GCM_TRANSFER_SURFACE_FORMAT_Y32; - RSX_CONTEXT_CURRENTP[pos++] = ((0x1000 << 16) | 0x1000); - - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV308ATCL_POINT,3); - RSX_CONTEXT_CURRENTP[pos++] = ((0 << 16) | pixelShift); - RSX_CONTEXT_CURRENTP[pos++] = ((1 << 16) | sizeInWords); - RSX_CONTEXT_CURRENTP[pos++] = ((1 << 16) | sizeInWords); - - RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV308ATCL_COLOR,padSizeInWords); - - cnt = 0; - src = (u32*)srcAddress; - while(cnt>4)) << 16) | (width + ((srcX+15)>>4))); - RSX_CONTEXT_CURRENTP[23] = (srcPitch | (GCM_TRANSFER_ORIGIN_CORNER << 16) | (GCM_TRANSFER_INTERPOLATOR_NEAREST << 24)); - RSX_CONTEXT_CURRENTP[24] = srcOffset; - RSX_CONTEXT_CURRENTP[25] = ((srcY << 16) | srcX); - - RSX_CONTEXT_CURRENT_END(26); -} - -void rsxSetTransferScaleMode(gcmContextData *context,const u8 mode,const u8 surface) -{ - RSX_CONTEXT_CURRENT_BEGIN(6); - - RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(6,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,1); - RSX_CONTEXT_CURRENTP[1] = (mode&0x01) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; - - RSX_CONTEXT_CURRENTP[2] = (surface==GCM_TRANSFER_SWIZZLE) ? RSX_SUBCHANNEL_METHOD(4,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,1) : RSX_SUBCHANNEL_METHOD(3,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_OUT,1); - RSX_CONTEXT_CURRENTP[3] = (mode&0x02) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; - - RSX_CONTEXT_CURRENTP[4] = RSX_SUBCHANNEL_METHOD(6,NV01_IMAGE_FROM_CPU_SURFACE,1); - RSX_CONTEXT_CURRENTP[5] = (surface==GCM_TRANSFER_SWIZZLE) ? GCM_CONTEXT_SWIZZLE2D : GCM_CONTEXT_SURFACE2D; - - RSX_CONTEXT_CURRENT_END(6); -} - -void rsxSetTransferScaleSurface(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSurface *surface) -{ - RSX_CONTEXT_CURRENT_BEGIN(20); - - RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(3,NV04_CONTEXT_SURFACES_2D_FORMAT,4); - RSX_CONTEXT_CURRENTP[1] = surface->format; - RSX_CONTEXT_CURRENTP[2] = ((surface->pitch << 16) | 0x40); // or'ing with 64 - why? - RSX_CONTEXT_CURRENTP[3] = 0; - RSX_CONTEXT_CURRENTP[4] = surface->offset; - - RSX_CONTEXT_CURRENTP[5] = RSX_SUBCHANNEL_METHOD(6,NV03_STRETCHED_IMAGE_FROM_CPU_OPERATION,9); - RSX_CONTEXT_CURRENTP[6] = scale->conversion; - RSX_CONTEXT_CURRENTP[7] = scale->format; - RSX_CONTEXT_CURRENTP[8] = scale->operation; - RSX_CONTEXT_CURRENTP[9] = ((scale->clipY << 16) | scale->clipX); - RSX_CONTEXT_CURRENTP[10] = ((scale->clipH << 16) | scale->clipW); - RSX_CONTEXT_CURRENTP[11] = ((scale->outY << 16) | scale->outX); - RSX_CONTEXT_CURRENTP[12] = ((scale->outH << 16) | scale->outW); - RSX_CONTEXT_CURRENTP[13] = scale->ratioX; - RSX_CONTEXT_CURRENTP[14] = scale->ratioY; - - RSX_CONTEXT_CURRENTP[15] = RSX_SUBCHANNEL_METHOD(6,NV03_SCALED_IMAGE_FROM_MEMORY_IMAGE_IN_SIZE,4); - RSX_CONTEXT_CURRENTP[16] = ((scale->inH << 16) | scale->inW); - RSX_CONTEXT_CURRENTP[17] = ((scale->pitch) | (scale->origin << 16) | (scale->interp << 24)); - RSX_CONTEXT_CURRENTP[18] = scale->offset; - RSX_CONTEXT_CURRENTP[19] = ((scale->inY << 16) | scale->inX); - - RSX_CONTEXT_CURRENT_END(20); -} - -#if 0 -// This is unfinished -void rsxSetTransferScaleSwizzle(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSwizzle *swizzle) -{ - RSX_CONTEXT_CURRENT_BEGIN(20); - - RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(4,0x300,2); - RSX_CONTEXT_CURRENTP[1] = (swizzle->format | (swizzle->width << 16) | (swizzle->height << 24)); - RSX_CONTEXT_CURRENTP[2] = swizzle->offset; - - RSX_CONTEXT_CURRENTP[3] = RSX_SUBCHANNEL_METHOD(6,0x2fc,9);; - RSX_CONTEXT_CURRENTP[4] = GCM_TRANSFER_CONVERSION_TRUNCATE; - RSX_CONTEXT_CURRENTP[5] = scale->format; - RSX_CONTEXT_CURRENTP[6] = GCM_TRANSFER_OPERATION_SRCCOPY; - RSX_CONTEXT_CURRENTP[7] = ((scale->clipY << 16) | scale->clipX); - RSX_CONTEXT_CURRENTP[8] = ((scale->clipH << 16) | scale->clipW); - RSX_CONTEXT_CURRENTP[9] = ((scale->outY << 16) | scale->outX); - RSX_CONTEXT_CURRENTP[10] = ((scale->outH << 16) | scale->outW); - RSX_CONTEXT_CURRENTP[11] = scale->ratioX; - RSX_CONTEXT_CURRENTP[12] = scale->ratioY; - - RSX_CONTEXT_CURRENTP[13] = RSX_SUBCHANNEL_METHOD(6,0x400,4); - RSX_CONTEXT_CURRENTP[14] = ((scale->inH << 16) | scale->inW); - RSX_CONTEXT_CURRENTP[15] = ((scale->pitch) | (scale->origin << 16) | (scale->interp << 24)); - RSX_CONTEXT_CURRENTP[16] = scale->offset; - RSX_CONTEXT_CURRENTP[17] = ((scale->inY << 16) | scale->inX); - - RSX_CONTEXT_CURRENT_END(20); -} -#endif - -void rsxSetTimeStamp(gcmContextData *context,u32 index) -{ - RSX_CONTEXT_CURRENT_BEGIN(2); - - RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_QUERY_GET,1); - RSX_CONTEXT_CURRENTP[2] = (((index << 4)&0x0fffffff) | 0x10000000); - - RSX_CONTEXT_CURRENT_END(2); -} +#undef RSX_INTERNAL diff --git a/ppu/librsx/commands_impl.h b/ppu/librsx/commands_impl.h new file mode 100644 index 00000000..2d10d85d --- /dev/null +++ b/ppu/librsx/commands_impl.h @@ -0,0 +1,2010 @@ +void RSX_FUNC(SetReturnCommand)(gcmContextData *context) +{ + RSX_CONTEXT_CURRENT_BEGIN(1); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_FLAG_RETURN; + RSX_CONTEXT_CURRENT_END(1); +} + +void RSX_FUNC(SetCallCommand)(gcmContextData *context,u32 offset) +{ + RSX_CONTEXT_CURRENT_BEGIN(1); + RSX_CONTEXT_CURRENTP[0] = (offset | RSX_METHOD_FLAG_CALL); + RSX_CONTEXT_CURRENT_END(1); +} + +void RSX_FUNC(SetJumpCommand)(gcmContextData *context,u32 offset) +{ + RSX_CONTEXT_CURRENT_BEGIN(1); + RSX_CONTEXT_CURRENTP[0] = (offset | RSX_METHOD_FLAG_JUMP); + RSX_CONTEXT_CURRENT_END(1); +} + +void RSX_FUNC(SetNopCommand)(gcmContextData *context,u32 count) +{ + u32 i; + + RSX_CONTEXT_CURRENT_BEGIN(count); + for(i=0;i>16)&0xff) | ((value&0xff)<<16); + + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SEMAPHORE_OFFSET,1); + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_SEMAPHORE_BACKENDWRITE_RELEASE,1); + RSX_CONTEXT_CURRENTP[3] = wvalue; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetWriteTextureLabel)(gcmContextData *context,u8 index,u32 value) +{ + u32 offset = 0x10*index; + + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SEMAPHORE_OFFSET,1); + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_SEMAPHORE_TEXTUREREAD_RELEASE,1); + RSX_CONTEXT_CURRENTP[3] = value; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetWaitLabel)(gcmContextData *context,u8 index,u32 value) +{ + u32 offset = 0x10*index; + + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV406ETCL_SEMAPHORE_OFFSET,1); + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV406ETCL_SEMAPHORE_ACQUIRE,1); + RSX_CONTEXT_CURRENTP[3] = value; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetWriteCommandLabel)(gcmContextData *context,u8 index,u32 value) +{ + u32 offset = 0x10*index; + + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV406ETCL_SEMAPHORE_OFFSET,1); + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV406ETCL_SEMAPHORE_RELEASE,1); + RSX_CONTEXT_CURRENTP[3] = value; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetSurface)(gcmContextData *context,const gcmSurface *surface) +{ + u32 log2Width = 31 - __cntlzw(surface->width); + u32 log2Height = 31 - __cntlzw(surface->height); + + RSX_CONTEXT_CURRENT_BEGIN(32); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DMA_COLOR0,1); + RSX_CONTEXT_CURRENTP[1] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[0]; + + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_DMA_COLOR1,1); + RSX_CONTEXT_CURRENTP[3] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[1]; + + RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_DMA_COLOR2,2); + RSX_CONTEXT_CURRENTP[5] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[2]; + RSX_CONTEXT_CURRENTP[6] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->colorLocation[3]; + + RSX_CONTEXT_CURRENTP[7] = RSX_METHOD(NV40TCL_DMA_ZETA,1); + RSX_CONTEXT_CURRENTP[8] = GCM_DMA_MEMORY_FRAME_BUFFER + surface->depthLocation; + + RSX_CONTEXT_CURRENTP[9] = RSX_METHOD(NV40TCL_RT_FORMAT,6); + RSX_CONTEXT_CURRENTP[10] = ((log2Height<antiAlias<type<depthFormat<colorFormat<colorPitch[0]; + RSX_CONTEXT_CURRENTP[12] = surface->colorOffset[0]; + RSX_CONTEXT_CURRENTP[13] = surface->depthOffset; + RSX_CONTEXT_CURRENTP[14] = surface->colorOffset[1]; + RSX_CONTEXT_CURRENTP[15] = surface->colorPitch[1]; + + RSX_CONTEXT_CURRENTP[16] = RSX_METHOD(NV40TCL_ZETA_PITCH,1); + RSX_CONTEXT_CURRENTP[17] = surface->depthPitch; + + RSX_CONTEXT_CURRENTP[18] = RSX_METHOD(NV40TCL_COLOR2_PITCH,4); + RSX_CONTEXT_CURRENTP[19] = surface->colorPitch[2]; + RSX_CONTEXT_CURRENTP[20] = surface->colorPitch[3]; + RSX_CONTEXT_CURRENTP[21] = surface->colorOffset[2]; + RSX_CONTEXT_CURRENTP[22] = surface->colorOffset[3]; + + RSX_CONTEXT_CURRENTP[23] = RSX_METHOD(NV40TCL_RT_ENABLE,1); + RSX_CONTEXT_CURRENTP[24] = surface->colorTarget; + + RSX_CONTEXT_CURRENTP[25] = RSX_METHOD(NV40TCL_WINDOW_OFFSET,1); + RSX_CONTEXT_CURRENTP[26] = ((surface->y<<16) | surface->x); + + RSX_CONTEXT_CURRENTP[27] = RSX_METHOD(NV40TCL_RT_HORIZ,2); + RSX_CONTEXT_CURRENTP[28] = ((surface->width<<16) | surface->x); + RSX_CONTEXT_CURRENTP[29] = ((surface->height<<16) | surface->y); + + RSX_CONTEXT_CURRENTP[30] = RSX_METHOD(NV40TCL_SHADER_WINDOW,1); + RSX_CONTEXT_CURRENTP[31] = ((0<<16) | (1<<12) | surface->height); + + RSX_CONTEXT_CURRENT_END(32); +} + +void RSX_FUNC(SetColorMask)(gcmContextData *context,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_COLOR_MASK,1); + RSX_CONTEXT_CURRENTP[1] = mask; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetColorMaskMRT)(gcmContextData *context,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_MRT_COLOR_MASK,1); + RSX_CONTEXT_CURRENTP[1] = mask; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetShadeModel)(gcmContextData *context,u32 shadeModel) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SHADE_MODEL,1); + RSX_CONTEXT_CURRENTP[1] = shadeModel; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetViewport)(gcmContextData *context,u16 x,u16 y,u16 width,u16 height,f32 min,f32 max,const f32 scale[4],const f32 offset[4]) +{ + ieee32 _min,_max; + ieee32 _offset[4],_scale[4]; + + _min.f = min; + _max.f = max; + + _scale[0].f = scale[0]; + _scale[1].f = scale[1]; + _scale[2].f = scale[2]; + _scale[3].f = scale[3]; + + _offset[0].f = offset[0]; + _offset[1].f = offset[1]; + _offset[2].f = offset[2]; + _offset[3].f = offset[3]; + + RSX_CONTEXT_CURRENT_BEGIN(24); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VIEWPORT_HORIZ,2); + RSX_CONTEXT_CURRENTP[1] = ((width<<16) | x); + RSX_CONTEXT_CURRENTP[2] = ((height<<16) | y); + + RSX_CONTEXT_CURRENTP[3] = RSX_METHOD(NV40TCL_DEPTH_RANGE,2); + RSX_CONTEXT_CURRENTP[4] = _min.u; + RSX_CONTEXT_CURRENTP[5] = _max.u; + + RSX_CONTEXT_CURRENTP[6] = RSX_METHOD(NV40TCL_VIEWPORT_OFFSET,8); + RSX_CONTEXT_CURRENTP[7] = _offset[0].u; + RSX_CONTEXT_CURRENTP[8] = _offset[1].u; + RSX_CONTEXT_CURRENTP[9] = _offset[2].u; + RSX_CONTEXT_CURRENTP[10] = _offset[3].u; + RSX_CONTEXT_CURRENTP[11] = _scale[0].u; + RSX_CONTEXT_CURRENTP[12] = _scale[1].u; + RSX_CONTEXT_CURRENTP[13] = _scale[2].u; + RSX_CONTEXT_CURRENTP[14] = _scale[3].u; + + RSX_CONTEXT_CURRENTP[15] = RSX_METHOD(NV40TCL_VIEWPORT_OFFSET,8); + RSX_CONTEXT_CURRENTP[16] = _offset[0].u; + RSX_CONTEXT_CURRENTP[17] = _offset[1].u; + RSX_CONTEXT_CURRENTP[18] = _offset[2].u; + RSX_CONTEXT_CURRENTP[19] = _offset[3].u; + RSX_CONTEXT_CURRENTP[20] = _scale[0].u; + RSX_CONTEXT_CURRENTP[21] = _scale[1].u; + RSX_CONTEXT_CURRENTP[22] = _scale[2].u; + RSX_CONTEXT_CURRENTP[23] = _scale[3].u; + + RSX_CONTEXT_CURRENT_END(24); +} + +void RSX_FUNC(SetViewportClip)(gcmContextData *context,u8 sel,u16 width,u16 height) +{ + RSX_CONTEXT_CURRENT_BEGIN(3); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VIEWPORT_CLIP_HORIZ(sel),2); + RSX_CONTEXT_CURRENTP[1] = ((width-1) << 16); + RSX_CONTEXT_CURRENTP[2] = ((height-1) << 16); + + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(SetUserClipPlaneControl)(gcmContextData *context,u32 plane0,u32 plane1,u32 plane2,u32 plane3,u32 plane4,u32 plane5) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CLIP_PLANE_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = ((plane5 << 20) | (plane4 << 16) | (plane3 << 12) | (plane2 << 8) | (plane1 << 4) | plane0); + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetDepthTestEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_TEST_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetDepthFunc)(gcmContextData *context,u32 func) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_FUNC,1); + RSX_CONTEXT_CURRENTP[1] = func; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetDepthWriteEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_WRITE_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetCullFaceEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CULL_FACE_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetCullFace)(gcmContextData *context,u32 cull) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CULL_FACE,1); + RSX_CONTEXT_CURRENTP[1] = cull; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetFrontFace)(gcmContextData *context,u32 dir) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FRONT_FACE,1); + RSX_CONTEXT_CURRENTP[1] = dir; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetFrontPolygonMode)(gcmContextData *context,u32 mode) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_POLYGON_MODE_FRONT,1); + RSX_CONTEXT_CURRENTP[1] = mode; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetBackPolygonMode)(gcmContextData *context,u32 mode) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_POLYGON_MODE_BACK,1); + RSX_CONTEXT_CURRENTP[1] = mode; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetPolygonOffsetFillEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_POLYGON_OFFSET_FILL_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetPolygonOffset)(gcmContextData *context,f32 factor,f32 units) +{ + ieee32 d0,d1; + + d0.f = factor; + d1.f = units; + + RSX_CONTEXT_CURRENT_BEGIN(3); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_POLYGON_OFFSET_FACTOR,2); + RSX_CONTEXT_CURRENTP[1] = d0.u; + RSX_CONTEXT_CURRENTP[2] = d1.u; + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(ClearSurface)(gcmContextData *context,u32 clear_mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CLEAR_BUFFERS,1); + RSX_CONTEXT_CURRENTP[1] = clear_mask; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_NOP,1); + RSX_CONTEXT_CURRENTP[3] = 0; + + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetCylindricalWrap)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CYLINDRICAL_WRAP,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetTwoSideLightEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TWO_SIDE_LIGHT_EN,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetStencilFunc)(gcmContextData *context,u32 func,u32 ref,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_BACK_FUNC_FUNC,3); + RSX_CONTEXT_CURRENTP[1] = func; + RSX_CONTEXT_CURRENTP[2] = ref; + RSX_CONTEXT_CURRENTP[3] = mask; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetStencilMask)(gcmContextData *context,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_BACK_MASK,1); + RSX_CONTEXT_CURRENTP[1] = mask; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetStencilOp)(gcmContextData *context,u32 fail,u32 depthFail,u32 depthPass) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_BACK_OP_FAIL,3); + RSX_CONTEXT_CURRENTP[1] = fail; + RSX_CONTEXT_CURRENTP[2] = depthFail; + RSX_CONTEXT_CURRENTP[3] = depthPass; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetStencilTestEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_BACK_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetBackStencilFunc)(gcmContextData *context,u32 func,u32 ref,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_FRONT_FUNC_FUNC,3); + RSX_CONTEXT_CURRENTP[1] = func; + RSX_CONTEXT_CURRENTP[2] = ref; + RSX_CONTEXT_CURRENTP[3] = mask; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetBackStencilMask)(gcmContextData *context,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_FRONT_MASK,1); + RSX_CONTEXT_CURRENTP[1] = mask; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetBackStencilOp)(gcmContextData *context,u32 fail,u32 depthFail,u32 depthPass) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_FRONT_OP_FAIL,3); + RSX_CONTEXT_CURRENTP[1] = fail; + RSX_CONTEXT_CURRENTP[2] = depthFail; + RSX_CONTEXT_CURRENTP[3] = depthPass; + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(SetTwoSidedStencilTestEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_STENCIL_FRONT_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetRenderEnable)(gcmContextData *context,u8 mode,u32 index) +{ + u32 offset = 0x10*index; + + if(mode == GCM_CONDITIONAL) { + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_NOP,1); + RSX_CONTEXT_CURRENTP[1] = 0; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_RENDER_ENABLE,1); + RSX_CONTEXT_CURRENTP[3] = (0x2000000 | offset); + RSX_CONTEXT_CURRENT_END(4); + } else { + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_RENDER_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = 0x1000000; + RSX_CONTEXT_CURRENT_END(2); + } +} + +void RSX_FUNC(SetReport)(gcmContextData *context,u32 type,u32 index) +{ + u32 offset = 0x10*index; + + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_QUERY_GET,1); + RSX_CONTEXT_CURRENTP[1] = ((type<<24) | offset); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetClearReport)(gcmContextData *context,u32 type) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_QUERY_RESET,1); + RSX_CONTEXT_CURRENTP[1] = type; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZPixelCountEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_QUERY_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetSCullControl)(gcmContextData *context,u8 sFunc,u8 sRef,u8 sMask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SCULL_CONTROL,1); + RSX_CONTEXT_CURRENTP[1] = ((sMask<<24) | (sRef<<16) | sFunc); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZCullLimit)(gcmContextData *context,u16 moveforwardlimit,u16 pushbacklimit) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_ZCULL_CONTROL1,1); + RSX_CONTEXT_CURRENTP[1] = ((moveforwardlimit<<16) | pushbacklimit); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZCullStatsEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_ZCULL_STATS_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZCullControl)(gcmContextData *context,u8 zculldir,u8 zcullformat) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_ZCULL_CONTROL0,1); + RSX_CONTEXT_CURRENTP[1] = ((zcullformat<<4) | zculldir); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetClearZCullSurface)(gcmContextData *context,u32 depth,u32 stencil) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_CLEAR_ZCULL_SURFACE,1); + RSX_CONTEXT_CURRENTP[1] = ((stencil<<1) | depth); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZCullEnable)(gcmContextData *context,u32 depth,u32 stencil) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_ZCULL_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = ((stencil<<1) | depth); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetPolygonSmoothEnable)(gcmContextData *context,u32 enable) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_POLYGON_SMOOTH_ENABLE,1); + RSX_CONTEXT_CURRENTP[1] = enable; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(LoadVertexProgramBlock)(gcmContextData *context,const rsxVertexProgram *program,const void *ucode) +{ + u32 pos = 0; + u32 loop, rest; + const u32 *data = (const u32*)ucode; + u32 startIndex = program->insn_start; + u32 i,j,instCount = program->num_insn; + + loop = instCount/8; + rest = (instCount%8)*4; + + RSX_CONTEXT_CURRENT_BEGIN(9 + loop*33 + (rest!=0 ? rest + 1 : 0)); + + RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV40TCL_VP_UPLOAD_FROM_ID,2); + RSX_CONTEXT_CURRENTP[pos++] = startIndex; + RSX_CONTEXT_CURRENTP[pos++] = startIndex; + + for(i=0;i0) { + RSX_CONTEXT_CURRENTP[pos] = RSX_METHOD(NV40TCL_VP_UPLOAD_INST(0),rest); + for(j=0;jinput_mask; + RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV40TCL_VP_RESULT_EN,1); + RSX_CONTEXT_CURRENTP[pos++] = (program->output_mask | GCM_ATTRIB_OUTPUT_MASK_POINTSIZE); + + RSX_CONTEXT_CURRENTP[pos++] = RSX_METHOD(NV40TCL_TRANSFORM_TIMEOUT,1); + if(program->num_regs<=32) + RSX_CONTEXT_CURRENTP[pos++] = 0x0020FFFF; + else + RSX_CONTEXT_CURRENTP[pos++] = 0x0030FFFF; + + RSX_CONTEXT_CURRENT_END(9 + loop*33 + (rest!=0 ? rest + 1 : 0)); +} + +void RSX_FUNC(LoadFragmentProgramLocation)(gcmContextData *context,const rsxFragmentProgram *program,u32 offset,u32 location) +{ + u32 i; + u32 texcoords,texcoord2D,texcoord3D; + + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FP_ADDRESS,1); + RSX_CONTEXT_CURRENTP[1] = ((location + 1) | offset); + RSX_CONTEXT_CURRENT_END(2); + + texcoords = program->texcoords; + texcoord2D = program->texcoord2D; + texcoord3D = program->texcoord3D; + for(i=0;texcoords;i++) { + if(texcoords&1) { + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_COORD_CONTROL(i),1); + RSX_CONTEXT_CURRENTP[1] = (((texcoord3D&1) << 4) | (texcoord2D&1)); + RSX_CONTEXT_CURRENT_END(2); + } + texcoords >>= 1; + texcoord2D >>= 1; + texcoord3D >>= 1; + } + + { + u32 num_regs = program->num_regs > 2 ? program->num_regs : 2; + u32 fpcontrol = program->fp_control | (num_regs << NV40TCL_FP_CONTROL_TEMP_COUNT_SHIFT) | (1<<10); + + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FP_CONTROL,1); + RSX_CONTEXT_CURRENTP[1] = fpcontrol; + RSX_CONTEXT_CURRENT_END(2); + } +} + +void RSX_FUNC(UpdateFragmentProgramLocation)(gcmContextData *context,u32 offset,u32 location) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_FP_ADDRESS,1); + RSX_CONTEXT_CURRENTP[1] = ((location + 1) | offset); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(LoadVertexProgramParameterBlock)(gcmContextData *context,u32 base_const,u32 const_cnt,const f32 *value) +{ + u32 i,curr = 0; + + RSX_CONTEXT_CURRENT_BEGIN(const_cnt*6); + + for(i=0;iconst_start; + rsxProgramConst *consts = rsxVertexProgramGetConsts(program); + + RSX_FUNC(LoadVertexProgramBlock)(context,program,ucode); + + for(i=0;inum_const;i++) { + if(consts[i].is_internal) + RSX_FUNC(LoadVertexProgramParameterBlock)(context,consts[i].index + base_const,1,(f32*)consts[i].values); + } +} + +static inline __attribute__((always_inline)) void RSX_FUNC_INTERNAL(SetVertexProgramParameter)(gcmContextData *context,const rsxVertexProgram *program,const rsxProgramConst *param,const f32 *value) +{ + u32 base_const = program->const_start; + f32 params[4] = {0.0f,0.0f,0.0f,0.0f}; + + switch(param->type) { + case PARAM_FLOAT3x4: + case PARAM_FLOAT4x4: + RSX_FUNC(LoadVertexProgramParameterBlock)(context,param->index + base_const,param->count,value); + return; + case PARAM_FLOAT3x3: + case PARAM_FLOAT4x3: + { + u32 i; + + for(i=0;icount;i++,value+=3) { + params[0] = value[0]; + params[1] = value[1]; + params[2] = value[2]; + RSX_FUNC(LoadVertexProgramParameterBlock)(context,param->index + base_const + i,1,params); + } + return; + } + + case PARAM_FLOAT4: + RSX_FUNC(LoadVertexProgramParameterBlock)(context,param->index + base_const,1,value); + return; + case PARAM_FLOAT3: + params[2] = value[2]; + case PARAM_FLOAT2: + params[1] = value[1]; + case PARAM_FLOAT: + case PARAM_FLOAT1: + params[0] = value[0]; + } + RSX_FUNC(LoadVertexProgramParameterBlock)(context,param->index + base_const,1,params); +} + +void RSX_FUNC(SetVertexProgramParameter)(gcmContextData *context,const rsxVertexProgram *program,const rsxProgramConst *param,const f32 *value) +{ + RSX_FUNC_INTERNAL(SetVertexProgramParameter)(context, program, param, value); +} + +void RSX_FUNC(SetVertexProgramParameterByIndex)(gcmContextData *context,const rsxVertexProgram *program,s32 index,const f32 *value) +{ + rsxProgramConst *consts = rsxVertexProgramGetConsts(program); + RSX_FUNC_INTERNAL(SetVertexProgramParameter)(context, program, &consts[index], value); +} + +void RSX_FUNC(SetVertexAttribOutputMask)(gcmContextData *context,u32 mask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_RESULT_EN,1); + RSX_CONTEXT_CURRENTP[1] = mask; + RSX_CONTEXT_CURRENT_END(2); +} + +static inline __attribute__((always_inline)) void RSX_FUNC_INTERNAL(SetFragmentProgramParameter)(gcmContextData *context,const rsxFragmentProgram *program,const rsxProgramConst *param,const f32 *value,u32 offset,u32 location) +{ + s32 i; + f32 params[4] = {0.0f,0.0f,0.0f,0.0f}; + + switch(param->type) { + case PARAM_FLOAT3x4: + case PARAM_FLOAT4x4: + { + s32 j,cnt = param->count; + for(j=0;jnum;i++) + RSX_FUNC(InlineTransfer)(context,offset + co_table->offset[i],params,4,location); + } + } + return; + } + + case PARAM_FLOAT3x3: + case PARAM_FLOAT4x3: + { + s32 j,cnt = param->count; + for(j=0;jnum;i++) + RSX_FUNC(InlineTransfer)(context,offset + co_table->offset[i],params,4,location); + } + } + return; + } + + case PARAM_FLOAT4: + params[3] = swapF32_16(value[3]); + case PARAM_FLOAT3: + params[2] = swapF32_16(value[2]); + case PARAM_FLOAT2: + params[1] = swapF32_16(value[1]); + case PARAM_FLOAT: + params[0] = swapF32_16(value[0]); + break; + } + + if(param->index!=0xffffffff) { + rsxConstOffsetTable *co_table = rsxFragmentProgramGetConstOffsetTable(program,param->index); + + for(i=0;inum;i++) + RSX_FUNC(InlineTransfer)(context,offset + co_table->offset[i],params,4,location); + } +} + +void RSX_FUNC(SetFragmentProgramParameter)(gcmContextData *context,const rsxFragmentProgram *program,const rsxProgramConst *param,const f32 *value,u32 offset,u32 location) +{ + RSX_FUNC_INTERNAL(SetFragmentProgramParameter)(context, program, param, value, offset, location); +} + +void RSX_FUNC(SetFragmentProgramParameterByIndex)(gcmContextData *context,const rsxFragmentProgram *program,s32 index,const f32 *value,u32 offset,u32 location) +{ + rsxProgramConst *consts = rsxFragmentProgramGetConsts(program); + RSX_FUNC_INTERNAL(SetFragmentProgramParameter)(context, program, &consts[index], value, offset, location); +} + +void RSX_FUNC(DrawVertexBegin)(gcmContextData *context,u32 type) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); + RSX_CONTEXT_CURRENTP[1] = type; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawVertexEnd)(gcmContextData *context) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END,1); + RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawVertex1f)(gcmContextData *context,u8 idx,f32 v) +{ + ieee32 d; + d.f = v; + + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_1F_X(idx),1); + RSX_CONTEXT_CURRENTP[1] = d.u; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawVertex2f)(gcmContextData *context,u8 idx,const f32 v[2]) +{ + RSX_CONTEXT_CURRENT_BEGIN(3); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_2F_X(idx),2); + RSX_MEMCPY(&RSX_CONTEXT_CURRENTP[1],v,sizeof(f32)*2); + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(DrawVertex3f)(gcmContextData *context,u8 idx,const f32 v[3]) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_3F_X(idx),3); + RSX_MEMCPY(&RSX_CONTEXT_CURRENTP[1],v,sizeof(f32)*3); + RSX_CONTEXT_CURRENT_END(4); +} + +void RSX_FUNC(DrawVertex4f)(gcmContextData *context,u8 idx,const f32 v[4]) +{ + RSX_CONTEXT_CURRENT_BEGIN(5); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_4F_X(idx),4); + RSX_MEMCPY(&RSX_CONTEXT_CURRENTP[1],v,sizeof(f32)*4); + RSX_CONTEXT_CURRENT_END(5); +} + +void RSX_FUNC(DrawVertex4s)(gcmContextData *context,u8 idx,const s16 v[4]) +{ + RSX_CONTEXT_CURRENT_BEGIN(3); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_4I_0(idx),2); + RSX_CONTEXT_CURRENTP[1] = (v[0] | (v[1]<<16)); + RSX_CONTEXT_CURRENTP[2] = (v[2] | (v[3]<<16)); + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(DrawVertexScaled4s)(gcmContextData *context,u8 idx,const s16 v[4]) +{ + RSX_CONTEXT_CURRENT_BEGIN(3); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_4I_SCALED_0(idx),2); + RSX_CONTEXT_CURRENTP[1] = (v[0] | (v[1]<<16)); + RSX_CONTEXT_CURRENTP[2] = (v[2] | (v[3]<<16)); + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(DrawVertex2s)(gcmContextData *context,u8 idx,const s16 v[2]) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_2I(idx),1); + RSX_CONTEXT_CURRENTP[1] = (v[0] | (v[1]<<16)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawVertex4ub)(gcmContextData *context,u8 idx,const u8 v[4]) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_ATTR_4UB(idx),1); + RSX_CONTEXT_CURRENTP[1] = (v[0] | (v[1]<<8) | (v[2]<<16) | (v[3]<<24)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(InvalidateVertexCache)(gcmContextData *context) +{ + RSX_CONTEXT_CURRENT_BEGIN(8); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE2,1); + RSX_CONTEXT_CURRENTP[1] = 0; + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE,1); + RSX_CONTEXT_CURRENTP[3] = 0; + RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE,1); + RSX_CONTEXT_CURRENTP[5] = 0; + RSX_CONTEXT_CURRENTP[6] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE,1); + RSX_CONTEXT_CURRENTP[7] = 0; + RSX_CONTEXT_CURRENT_END(8); +} + +void RSX_FUNC(InvalidateTextureCache)(gcmContextData *context,u32 type) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_CACHE_CTL,1); + RSX_CONTEXT_CURRENTP[1] = type; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(LoadTexture)(gcmContextData *context,u8 index,const gcmTexture *texture) +{ + u32 format,offset,swizzle,size0,size1; + + RSX_CONTEXT_CURRENT_BEGIN(9); + + offset = texture->offset; + format = ((texture->location + 1) | (texture->cubemap << 2) | + (texture->dimension << NV40TCL_TEX_FORMAT_DIMS_SHIFT) | + (texture->format << NV40TCL_TEX_FORMAT_FORMAT_SHIFT) | + (texture->mipmap << NV40TCL_TEX_FORMAT_MIPMAP_COUNT_SHIFT) | + NV40TCL_TEX_FORMAT_NO_BORDER | 0x8000); + swizzle = texture->remap; + size0 = (texture->width << NV40TCL_TEX_SIZE0_W_SHIFT) | texture->height; + size1 = (texture->depth << NV40TCL_TEX_SIZE1_DEPTH_SHIFT) | texture->pitch; + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_OFFSET(index),2); // set offset and format for texture at once + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = format; + + RSX_CONTEXT_CURRENTP[3] = RSX_METHOD(NV40TCL_TEX_SWIZZLE(index),1); // set remap order or swizzle respectively for texture + RSX_CONTEXT_CURRENTP[4] = swizzle; + + RSX_CONTEXT_CURRENTP[5] = RSX_METHOD(NV40TCL_TEX_SIZE0(index),1); // set width and height for texture + RSX_CONTEXT_CURRENTP[6] = size0; + + RSX_CONTEXT_CURRENTP[7] = RSX_METHOD(NV40TCL_TEX_SIZE1(index),1); // set pitch and depth for texture + RSX_CONTEXT_CURRENTP[8] = size1; + + RSX_CONTEXT_CURRENT_END(9); +} + +void RSX_FUNC(LoadVertexTexture)(gcmContextData *context,u8 index,const gcmTexture *texture) +{ + u32 format,offset,control,imagerect; + + offset = texture->offset; + format = (texture->location + 1) | (texture->dimension << 4) | + (texture->format << 8) | (texture->mipmap << 16); + imagerect = texture->height | (texture->width << 16); + control = texture->pitch; + + RSX_CONTEXT_CURRENT_BEGIN(7); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_TEXTURE_OFFSET(index),2); // set offset and format for texture at once + RSX_CONTEXT_CURRENTP[1] = offset; + RSX_CONTEXT_CURRENTP[2] = format; + + RSX_CONTEXT_CURRENTP[3] = RSX_METHOD(NV40TCL_VP_TEXTURE_CONTROL3(index),1); // set pitch for texture + RSX_CONTEXT_CURRENTP[4] = control; + + RSX_CONTEXT_CURRENTP[5] = RSX_METHOD(NV40TCL_VP_TEXTURE_IMAGE_RECT(index),1); // set width and height for texture + RSX_CONTEXT_CURRENTP[6] = imagerect; + + RSX_CONTEXT_CURRENT_END(7); +} + +void RSX_FUNC(TextureControl)(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod,u8 maxaniso) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_ENABLE(index),1); + RSX_CONTEXT_CURRENTP[1] = ((enable << NV40TCL_TEX_ENABLE_SHIFT) | (minlod << NV40TCL_TEX_MINLOD_SHIFT) | (maxlod << NV40TCL_TEX_MAXLOD_SHIFT) | (maxaniso << NV40TCL_TEX_MAXANISO_SHIFT)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(VertexTextureControl)(gcmContextData *context,u8 index,u32 enable,u16 minlod,u16 maxlod) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_TEXTURE_CONTROL0(index),1); + RSX_CONTEXT_CURRENTP[1] = ((enable << NV40TCL_TEX_ENABLE_SHIFT) | ((minlod&0xfff) << NV40TCL_TEX_MINLOD_SHIFT) | ((maxlod&0xfff) << NV40TCL_TEX_MAXLOD_SHIFT)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(TextureFilter)(gcmContextData *context,u8 index,u16 bias,u8 min,u8 mag,u8 conv) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_FILTER(index),1); + RSX_CONTEXT_CURRENTP[1] = ((mag << NV40TCL_TEX_FILTER_MAG_SHIFT) | (min << NV40TCL_TEX_FILTER_MIN_SHIFT) | (conv << NV40TCL_TEX_FILTER_CONV_SHIFT) | (bias&0x1fff)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(VertexTextureFilter)(gcmContextData *context,u8 index,u16 bias) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_TEXTURE_FILTER(index),1); + RSX_CONTEXT_CURRENTP[1] = bias; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(TextureWrapMode)(gcmContextData *context,u8 index,u8 wraps,u8 wrapt,u8 wrapr,u8 unsignedRemap,u8 zfunc,u8 gamma) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_WRAP(index),1); + RSX_CONTEXT_CURRENTP[1] = ((wraps << NV40TCL_TEX_WRAP_S_SHIFT) | + (wrapt << NV40TCL_TEX_WRAP_T_SHIFT) | + (wrapr << NV40TCL_TEX_WRAP_R_SHIFT) | + (unsignedRemap << NV40TCL_TEX_UREMAP_SHIFT) | + (gamma << NV40TCL_TEX_GAMMA_SHIFT) | + (zfunc << NV40TCL_TEX_ZFUNC_SHIFT)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(VertexTextureWrapMode)(gcmContextData *context,u8 index,u8 wraps,u8 wrapt) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_TEXTURE_ADDRESS(index),1); + RSX_CONTEXT_CURRENTP[1] = (wraps | (wrapt<<8)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(TextureBorderColor)(gcmContextData *context,u8 index,u32 color) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_BORDER_COLOR(index),1); + RSX_CONTEXT_CURRENTP[1] = color; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(VertexTextureBorderColor)(gcmContextData *context,u8 index,u32 color) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VP_TEXTURE_BORDER_COLOR(index),1); + RSX_CONTEXT_CURRENTP[1] = color; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(TextureOptimization)(gcmContextData *context,u8 index,u8 slope,u8 iso,u8 aniso) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_CONTROL2(index),1); + RSX_CONTEXT_CURRENTP[1] = ((0x2d<<8) | (aniso<<7) | (iso<<6) | slope); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(TextureAnisoSpread)(gcmContextData *context,u8 index,u8 reduceSamplesEnable,u8 hReduceSamplesEnable,u8 vReduceSamplesEnable,u8 spacingSelect,u8 hSpacingSelect,u8 vSpacingSelect) +{ + u32 val = ((spacingSelect&0x7)<<0) | (( reduceSamplesEnable&0x1)<<4) | + ((hSpacingSelect&0x7)<<8) | ((hReduceSamplesEnable&0x1)<<12) | + ((vSpacingSelect&0x7)<<16) | ((vReduceSamplesEnable&0x1)<<20); + + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_TEX_ANISO_SPREAD(index),1); + RSX_CONTEXT_CURRENTP[1] = val; + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetZControl)(gcmContextData *context,u8 cullNearFar,u8 zClampEnable,u8 cullIgnoreW) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_DEPTH_CONTROL,1); + RSX_CONTEXT_CURRENTP[1] = (cullNearFar | (zClampEnable<<4) | (cullIgnoreW<<8)); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(BindVertexArrayAttrib)(gcmContextData *context,u8 attr,u16 frequency,u32 offset,u8 stride,u8 elems,u8 dtype,u8 location) +{ + RSX_CONTEXT_CURRENT_BEGIN(4); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTXFMT(attr),1); + RSX_CONTEXT_CURRENTP[1] = ((frequency << 16) | (stride << NV40TCL_VTXFMT_STRIDE_SHIFT) | (elems << NV40TCL_VTXFMT_SIZE_SHIFT) | dtype); + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_VTXBUF_ADDRESS(attr),1); + RSX_CONTEXT_CURRENTP[3] = ((location << 31) | offset); + RSX_CONTEXT_CURRENT_END(4); +} + +static inline __attribute__((always_inline)) void RSX_FUNC_INTERNAL(DrawVertexArray)(gcmContextData *context,u32 type,u32 start,u32 count) +{ + u32 i,j,lcount,loop,rest; + + --count; + lcount = count&0xff; + count >>= 8; + + loop = count/RSX_MAX_METHOD_COUNT; + rest = count%RSX_MAX_METHOD_COUNT; + + RSX_CONTEXT_CURRENT_BEGIN(8); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VTX_CACHE_INVALIDATE,3); + RSX_CONTEXT_CURRENTP[1] = 0; + RSX_CONTEXT_CURRENTP[2] = 0; + RSX_CONTEXT_CURRENTP[3] = 0; + + RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_BEGIN_END,1); + RSX_CONTEXT_CURRENTP[5] = type; + + RSX_CONTEXT_CURRENTP[6] = RSX_METHOD(NV40TCL_VB_VERTEX_BATCH,1); + RSX_CONTEXT_CURRENTP[7] = ((lcount<<24) | start); + + RSX_CONTEXT_CURRENT_END(8); + + start += (lcount + 1); + for(i=0;i < loop;i++) { + RSX_CONTEXT_CURRENT_BEGIN(1 + RSX_MAX_METHOD_COUNT); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_VERTEX_BATCH, RSX_MAX_METHOD_COUNT); + RSX_CONTEXT_CURRENTP++; + + for(j=0;j>2; + else + misalignedcount = (((offset + 127)&~127) - offset)>>1; + + odd = (misalignedcount && misalignedcount < count) ? 1 : 0; + + RSX_CONTEXT_CURRENT_BEGIN(7 + odd*2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_VTX_CACHE_INVALIDATE, 1); + RSX_CONTEXT_CURRENTP[1] = 0; + + RSX_CONTEXT_CURRENTP[2] = RSX_METHOD(NV40TCL_VB_INDEX_BATCH_OFFSET, 2); + RSX_CONTEXT_CURRENTP[3] = offset; + RSX_CONTEXT_CURRENTP[4] = (((data_type) << 4) | location); + + RSX_CONTEXT_CURRENTP[5] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[6] = type; + + start = 0; + if(odd) { + u32 tmp = misalignedcount - 1; + + RSX_CONTEXT_CURRENTP[7] = RSX_METHOD(NV40TCL_VB_INDEX_BATCH_DRAW, 1); + RSX_CONTEXT_CURRENTP[8] = ((tmp<<24) | start); + + start += misalignedcount; + count -= misalignedcount; + } + + RSX_CONTEXT_CURRENT_END(7 + odd*2); + + while(count > 0x7ff00) { + RSX_CONTEXT_CURRENT_BEGIN(1 + RSX_MAX_METHOD_COUNT); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_INDEX_BATCH_DRAW, RSX_MAX_METHOD_COUNT); + RSX_CONTEXT_CURRENTP++; + + for(i=0;i < RSX_MAX_METHOD_COUNT;i++) { + RSX_CONTEXT_CURRENTP[0] = (0xff000000 | start); + RSX_CONTEXT_CURRENTP++; + start += 0x100; + } + + count -= 0x7ff00; + } + + mcount = (count + 0xff)>>8; + + RSX_CONTEXT_CURRENT_BEGIN(1 + mcount); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_INDEX_BATCH_DRAW, mcount); + RSX_CONTEXT_CURRENTP++; + + while(count > 0x100) { + RSX_CONTEXT_CURRENTP[0] = (0xff000000 | start); + RSX_CONTEXT_CURRENTP++; + start += 0x100; + count -= 0x100; + } + + if(count) { + --count; + RSX_CONTEXT_CURRENTP[0] = ((count<<24) | start); + RSX_CONTEXT_CURRENTP++; + } + + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawIndexArray)(gcmContextData *context,u8 type,u32 offset,u32 count,u8 data_type,u8 location) +{ + RSX_FUNC_INTERNAL(DrawIndexArray)(context,type,offset,count,data_type,location); +} + +void RSX_FUNC(DrawInlineIndexArray16)(gcmContextData *context,u8 type,u32 start,u32 count,const u16 *data) +{ + u32 odd,lcount; + u32 loop,rest,i,j; + + if(count&1) { + odd = 1; + lcount = count - 1; + } else { + odd = 0; + lcount = count; + } + + data = data + start; + loop = (lcount>>1)/RSX_MAX_METHOD_COUNT; + rest = (lcount>>1)%RSX_MAX_METHOD_COUNT; + + RSX_CONTEXT_CURRENT_BEGIN(6 + odd*2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VTX_CACHE_INVALIDATE, 3); + RSX_CONTEXT_CURRENTP[1] = 0; + RSX_CONTEXT_CURRENTP[2] = 0; + RSX_CONTEXT_CURRENTP[3] = 0; + + RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[5] = type; + + if(odd) { + RSX_CONTEXT_CURRENTP[6] = RSX_METHOD_NI(NV40TCL_VB_ELEMENT_U32, 1); + RSX_CONTEXT_CURRENTP[7] = data[0]; + data++; + } + + RSX_CONTEXT_CURRENT_END(6 + odd*2); + + for(i=0;i < loop;i++) { + RSX_CONTEXT_CURRENT_BEGIN(1 + RSX_MAX_METHOD_COUNT); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_ELEMENT_U16, RSX_MAX_METHOD_COUNT); + RSX_CONTEXT_CURRENTP++; + + for(j=0;j < RSX_MAX_METHOD_COUNT;j++) { + RSX_CONTEXT_CURRENTP[0] = (data[0] | (data[1]<<16)); + RSX_CONTEXT_CURRENTP++; + data += 2; + } + } + + if(rest) { + RSX_CONTEXT_CURRENT_BEGIN(1 + rest); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_ELEMENT_U16, rest); + RSX_CONTEXT_CURRENTP++; + + for(j=0;j < rest;j++) { + RSX_CONTEXT_CURRENTP[0] = (data[0] | (data[1]<<16)); + RSX_CONTEXT_CURRENTP++; + data += 2; + } + } + + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(DrawInlineIndexArray32)(gcmContextData *context,u8 type,u32 start,u32 count,const u32 *data) +{ + u32 i,j; + u32 loop,rest; + + data = data + start; + loop = count/RSX_MAX_METHOD_COUNT; + rest = count%RSX_MAX_METHOD_COUNT; + + RSX_CONTEXT_CURRENT_BEGIN(6); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VTX_CACHE_INVALIDATE, 3); + RSX_CONTEXT_CURRENTP[1] = 0; + RSX_CONTEXT_CURRENTP[2] = 0; + RSX_CONTEXT_CURRENTP[3] = 0; + + RSX_CONTEXT_CURRENTP[4] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[5] = type; + + RSX_CONTEXT_CURRENT_END(6); + + for(i=0;i < loop;i++) { + RSX_CONTEXT_CURRENT_BEGIN(1 + RSX_MAX_METHOD_COUNT); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_ELEMENT_U32, RSX_MAX_METHOD_COUNT); + RSX_CONTEXT_CURRENTP++; + + for(j=0;j < RSX_MAX_METHOD_COUNT;j++) { + RSX_CONTEXT_CURRENTP[0] = *data; + RSX_CONTEXT_CURRENTP++; + data++; + } + } + + if(rest) { + RSX_CONTEXT_CURRENT_BEGIN(1 + rest); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD_NI(NV40TCL_VB_ELEMENT_U32, rest); + RSX_CONTEXT_CURRENTP++; + + for(j=0;j < rest;j++) { + RSX_CONTEXT_CURRENTP[0] = *data; + RSX_CONTEXT_CURRENTP++; + data++; + } + } + + RSX_CONTEXT_CURRENT_BEGIN(2); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_BEGIN_END, 1); + RSX_CONTEXT_CURRENTP[1] = NV40TCL_BEGIN_END_STOP; + + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(SetScissor)(gcmContextData *context,u16 x,u16 y,u16 w,u16 h) +{ + RSX_CONTEXT_CURRENT_BEGIN(3); + + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_SCISSOR_HORIZ,2); + RSX_CONTEXT_CURRENTP[1] = ((w<<16) | x); + RSX_CONTEXT_CURRENTP[2] = ((h<<16) | y); + + RSX_CONTEXT_CURRENT_END(3); +} + +void RSX_FUNC(SetAntialiasingControl)(gcmContextData *context,u32 enable,u32 alphaToCoverage,u32 alphaToOne,u32 sampleMask) +{ + RSX_CONTEXT_CURRENT_BEGIN(2); + RSX_CONTEXT_CURRENTP[0] = RSX_METHOD(NV40TCL_ANTI_ALIASING_CONTROL,1); + RSX_CONTEXT_CURRENTP[1] = ((sampleMask<<16) | (alphaToOne<<8) | (alphaToCoverage<<4) | enable); + RSX_CONTEXT_CURRENT_END(2); +} + +void RSX_FUNC(InlineTransfer)(gcmContextData *context,u32 dstOffset,const void *srcAddress,u32 sizeInWords,u8 location) +{ + u32 *src; + u32 pixelShift; + u32 cnt,pos = 0; + u32 padSizeInWords; + u32 alignedVideoOffset; + + alignedVideoOffset = dstOffset&~0x3f; + pixelShift = (dstOffset&0x3f)>>2; + + padSizeInWords = (sizeInWords + 1)&~0x01; + + RSX_CONTEXT_CURRENT_BEGIN(12 + padSizeInWords); + + RSX_CONTEXT_CURRENTP[pos++] = RSX_SUBCHANNEL_METHOD(3,NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_DESTIN,1); + RSX_CONTEXT_CURRENTP[pos++] = GCM_DMA_MEMORY_FRAME_BUFFER + location; + + RSX_CONTEXT_CURRENTP[pos++] = RSX_SUBCHANNEL_METHOD(3,NV04_CONTEXT_SURFACES_2D_OFFSET_DESTIN,1); + RSX_CONTEXT_CURRENTP[pos++] = alignedVideoOffset; + + RSX_CONTEXT_CURRENTP[pos++] = RSX_SUBCHANNEL_METHOD(3,NV04_CONTEXT_SURFACES_2D_FORMAT,2); + RSX_CONTEXT_CURRENTP[pos++] = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32; + RSX_CONTEXT_CURRENTP[pos++] = ((0x1000 << 16) | 0x1000); + + RSX_CONTEXT_CURRENTP[pos++] = RSX_SUBCHANNEL_METHOD(5,NV01_IMAGE_FROM_CPU_POINT,3); + RSX_CONTEXT_CURRENTP[pos++] = ((0 << 16) | pixelShift); + RSX_CONTEXT_CURRENTP[pos++] = ((1 << 16) | sizeInWords); + RSX_CONTEXT_CURRENTP[pos++] = ((1 << 16) | sizeInWords); + + RSX_CONTEXT_CURRENTP[pos++] = RSX_SUBCHANNEL_METHOD(5,NV01_IMAGE_FROM_CPU_COLOR(0),padSizeInWords); + + cnt = 0; + src = (u32*)srcAddress; + while(cnt>4)) << 16) | (width + ((srcX+15)>>4))); + RSX_CONTEXT_CURRENTP[23] = (srcPitch | (GCM_TRANSFER_ORIGIN_CORNER << 16) | (GCM_TRANSFER_INTERPOLATOR_NEAREST << 24)); + RSX_CONTEXT_CURRENTP[24] = srcOffset; + RSX_CONTEXT_CURRENTP[25] = ((srcY << 16) | srcX); + + RSX_CONTEXT_CURRENT_END(26); +} + +void RSX_FUNC(SetTransferScaleMode)(gcmContextData *context,u8 mode,u8 surface) +{ + RSX_CONTEXT_CURRENT_BEGIN(6); + + RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(6,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,1); + RSX_CONTEXT_CURRENTP[1] = (mode&0x01) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; + + RSX_CONTEXT_CURRENTP[2] = (surface==GCM_TRANSFER_SWIZZLE) ? RSX_SUBCHANNEL_METHOD(4,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,1) : RSX_SUBCHANNEL_METHOD(3,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_OUT,1); + RSX_CONTEXT_CURRENTP[3] = (mode&0x02) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; + + RSX_CONTEXT_CURRENTP[4] = RSX_SUBCHANNEL_METHOD(6,NV01_IMAGE_FROM_CPU_SURFACE,1); + RSX_CONTEXT_CURRENTP[5] = (surface==GCM_TRANSFER_SWIZZLE) ? GCM_CONTEXT_SWIZZLE2D : GCM_CONTEXT_SURFACE2D; + + RSX_CONTEXT_CURRENT_END(6); +} + +void RSX_FUNC(SetTransferScaleSurface)(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSurface *surface) +{ + RSX_CONTEXT_CURRENT_BEGIN(20); + + RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(3,NV04_CONTEXT_SURFACES_2D_FORMAT,4); + RSX_CONTEXT_CURRENTP[1] = surface->format; + RSX_CONTEXT_CURRENTP[2] = ((surface->pitch << 16) | 0x40); // or'ing with 64 - why? + RSX_CONTEXT_CURRENTP[3] = 0; + RSX_CONTEXT_CURRENTP[4] = surface->offset; + + RSX_CONTEXT_CURRENTP[5] = RSX_SUBCHANNEL_METHOD(6,NV03_STRETCHED_IMAGE_FROM_CPU_OPERATION,9); + RSX_CONTEXT_CURRENTP[6] = scale->conversion; + RSX_CONTEXT_CURRENTP[7] = scale->format; + RSX_CONTEXT_CURRENTP[8] = scale->operation; + RSX_CONTEXT_CURRENTP[9] = ((scale->clipY << 16) | scale->clipX); + RSX_CONTEXT_CURRENTP[10] = ((scale->clipH << 16) | scale->clipW); + RSX_CONTEXT_CURRENTP[11] = ((scale->outY << 16) | scale->outX); + RSX_CONTEXT_CURRENTP[12] = ((scale->outH << 16) | scale->outW); + RSX_CONTEXT_CURRENTP[13] = scale->ratioX; + RSX_CONTEXT_CURRENTP[14] = scale->ratioY; + + RSX_CONTEXT_CURRENTP[15] = RSX_SUBCHANNEL_METHOD(6,NV03_SCALED_IMAGE_FROM_MEMORY_IMAGE_IN_SIZE,4); + RSX_CONTEXT_CURRENTP[16] = ((scale->inH << 16) | scale->inW); + RSX_CONTEXT_CURRENTP[17] = ((scale->pitch) | (scale->origin << 16) | (scale->interp << 24)); + RSX_CONTEXT_CURRENTP[18] = scale->offset; + RSX_CONTEXT_CURRENTP[19] = ((scale->inY << 16) | scale->inX); + + RSX_CONTEXT_CURRENT_END(20); +} + +void RSX_FUNC(SetTransferScaleSwizzle)(gcmContextData *context,const gcmTransferScale *scale,const gcmTransferSwizzle *swizzle) +{ + RSX_CONTEXT_CURRENT_BEGIN(18); + + RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(4,NV04_SWIZZLED_SURFACE_FORMAT,2); + RSX_CONTEXT_CURRENTP[1] = ((swizzle->height << 24) | (swizzle->width << 16) | swizzle->format); + RSX_CONTEXT_CURRENTP[2] = swizzle->offset; + + RSX_CONTEXT_CURRENTP[3] = RSX_SUBCHANNEL_METHOD(6,NV04_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION,9);; + RSX_CONTEXT_CURRENTP[4] = GCM_TRANSFER_CONVERSION_TRUNCATE; + RSX_CONTEXT_CURRENTP[5] = scale->format; + RSX_CONTEXT_CURRENTP[6] = GCM_TRANSFER_OPERATION_SRCCOPY; + RSX_CONTEXT_CURRENTP[7] = ((scale->clipY << 16) | scale->clipX); + RSX_CONTEXT_CURRENTP[8] = ((scale->clipH << 16) | scale->clipW); + RSX_CONTEXT_CURRENTP[9] = ((scale->outY << 16) | scale->outX); + RSX_CONTEXT_CURRENTP[10] = ((scale->outH << 16) | scale->outW); + RSX_CONTEXT_CURRENTP[11] = scale->ratioX; + RSX_CONTEXT_CURRENTP[12] = scale->ratioY; + + RSX_CONTEXT_CURRENTP[13] = RSX_SUBCHANNEL_METHOD(6,NV04_SCALED_IMAGE_FROM_MEMORY_SIZE,4); + RSX_CONTEXT_CURRENTP[14] = ((scale->inH << 16) | scale->inW); + RSX_CONTEXT_CURRENTP[15] = ((scale->interp << 24) | (scale->origin << 16) | (scale->pitch)); + RSX_CONTEXT_CURRENTP[16] = scale->offset; + RSX_CONTEXT_CURRENTP[17] = ((scale->inY << 16) | scale->inX); + + RSX_CONTEXT_CURRENT_END(18); +} + +static inline __attribute__((always_inline)) void RSX_FUNC_INTERNAL(SetConvertSwizzleFormat)(gcmContextData *context,u32 dstOffset,u32 dstWidth,u32 dstHeight,u32 dstX,u32 dstY,u32 srcOffset,u32 srcPitch,u32 srcX,u32 srcY,u32 width,u32 height,u32 bytesPerPixel,u32 mode) +{ + const u32 NV_MEM2MEM_MAX_HEIGHT_VALUE = 2047; + const u32 NV_SURFACE_SWIZZLED_MAX_DIM = 10; + u32 dstwlog2 = 31 - __cntlzw(dstWidth); + u32 dsthlog2 = 31 - __cntlzw(dstHeight); + + switch(bytesPerPixel) { + case 2: + case 4: + break; + case 8: + dstWidth <<= 1; + dstX <<= 1; + srcX <<= 1; + width <<= 1; + bytesPerPixel >>= 1; + dstwlog2 += 1; + break; + case 16: + dstWidth <<= 2; + dstX <<= 2; + srcX <<= 2; + width <<= 2; + bytesPerPixel >>= 2; + dstwlog2 += 2; + break; + default: + return; + } + + if((dstwlog2 <= 1) || (dsthlog2 == 0)) { + u32 dstPitch; + u32 linesLeft; + + dstPitch = bytesPerPixel< NV_MEM2MEM_MAX_HEIGHT_VALUE) ? NV_MEM2MEM_MAX_HEIGHT_VALUE : linesLeft; + + // todo: this is incorrect for the vid->vid case + rsxSetTransferData(context,mode,dstOffset,dstPitch,srcOffset,srcPitch,width*bytesPerPixel,actualHeight); + + srcOffset = srcOffset + actualHeight*srcPitch; + dstOffset = dstOffset + actualHeight*dstPitch; + linesLeft -= actualHeight; + } + return; + } else { + u32 yTop,xEnd,yEnd,x,y; + u32 srcFormat,dstFormat,logWidthLimit,logHeightLimit; + u32 srcHandle = (mode&0x01) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; + u32 dstHandle = (mode&0x02) ? GCM_DMA_MEMORY_HOST_BUFFER : GCM_DMA_MEMORY_FRAME_BUFFER; + + RSX_CONTEXT_CURRENT_BEGIN(6); + RSX_CONTEXT_CURRENTP[0] = RSX_SUBCHANNEL_METHOD(4,NV_MEMORY_TO_MEMORY_FORMAT_DMA_BUFFER_IN,1); + RSX_CONTEXT_CURRENTP[1] = dstHandle; + RSX_CONTEXT_CURRENTP[2] = RSX_SUBCHANNEL_METHOD(6,NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE,1); + RSX_CONTEXT_CURRENTP[3] = srcHandle; + RSX_CONTEXT_CURRENTP[4] = RSX_SUBCHANNEL_METHOD(6,NV01_IMAGE_FROM_CPU_SURFACE,1); + RSX_CONTEXT_CURRENTP[5] = GCM_CONTEXT_SWIZZLE2D; + RSX_CONTEXT_CURRENT_END(6); + + switch(bytesPerPixel) + { + case 2: + srcFormat = GCM_TRANSFER_SCALE_FORMAT_R5G6B5; + dstFormat = GCM_TRANSFER_SURFACE_FORMAT_R5G6B5; + break; + case 4: + srcFormat = GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8; + dstFormat = GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8; + break; + case 1: + default: + return; + } + + logWidthLimit = (dstwlog2 > NV_SURFACE_SWIZZLED_MAX_DIM) ? NV_SURFACE_SWIZZLED_MAX_DIM : dstwlog2; + logHeightLimit = (dsthlog2 > NV_SURFACE_SWIZZLED_MAX_DIM) ? NV_SURFACE_SWIZZLED_MAX_DIM : dsthlog2; + + srcOffset += (srcX - dstX)*bytesPerPixel + (srcY - dstY)*srcPitch; + + xEnd = dstX + width; + yEnd = dstY + height; + + yTop = dstY&~((1<< NV_SURFACE_SWIZZLED_MAX_DIM) - 1); + for(y=dstY;y < yEnd;) { + u32 xLeft; + u32 yBottom; + u32 bltHeight; + + yBottom = yTop + (1< (1ul << dsthlog2)) { + yBottom = (1< yEnd) ? yEnd - y : yBottom - y; + + xLeft = dstX&~((1< xEnd ) ? xEnd - x : xRight - x; + + if(!dstwlog2) + blockDstOffset = dstOffset + yTop*bytesPerPixel; + else if(!dsthlog2) + blockDstOffset = dstOffset + xLeft*bytesPerPixel; + else { + u32 log = (dstwlog2 < dsthlog2) ? dstwlog2 : dsthlog2; + u32 doubleLog = log<<1; + u32 upperMask = ~((1<num_insn*sizeof(u32)*4; - return (void*)(((u8*)fp) + fp->ucode_off); + *ucode = (void*)(((u8*)fp) + fp->ucode_off); } -rsxProgramConst* rsxFragmentProgramGetConsts(rsxFragmentProgram *fp) +u16 rsxFragmentProgramGetNumConst(const rsxFragmentProgram *fp) { - return (rsxProgramConst*)(((u8*)fp) + fp->const_off); + return fp->num_const; } -s32 rsxFragmentProgramGetConst(rsxFragmentProgram *fp,const char *name) +rsxProgramConst* rsxFragmentProgramGetConsts(const rsxFragmentProgram *fp) { - u32 i; - rsxProgramConst *fpc = rsxFragmentProgramGetConsts(fp); + return __rsxGetConsts((rsxProgram*) fp); +} + +s32 rsxFragmentProgramGetConstIndex(const rsxFragmentProgram *fp,const char *name) +{ + return __rsxGetConstIndex((rsxProgram*) fp, name); +} - for(i=0;inum_const;i++) { - char *namePtr; +rsxProgramConst* rsxFragmentProgramGetConst(const rsxFragmentProgram *fp,const char *name) +{ + rsxProgramConst *fpc = __rsxGetConsts((rsxProgram*) fp); + s32 index = __rsxGetConstIndex((rsxProgram*) fp, name); - if(!fpc[i].name_off) continue; + if (index == -1) return NULL; - namePtr = ((char*)fp) + fpc[i].name_off; - if(strcasecmp(name,namePtr)==0) - return i; - } - return -1; + return &fpc[index]; } -rsxProgramAttrib* rsxFragmentProgramGetAttribs(rsxFragmentProgram *fp) +u16 rsxFragmentProgramGetNumAttrib(const rsxFragmentProgram *fp) { - return (rsxProgramAttrib*)(((u8*)fp) + fp->attrib_off); + return fp->num_attr; } -s32 rsxFragmentProgramGetAttrib(rsxFragmentProgram *fp,const char *name) +rsxProgramAttrib* rsxFragmentProgramGetAttribs(const rsxFragmentProgram *fp) { - u32 i; - rsxProgramAttrib *attribs = rsxFragmentProgramGetAttribs(fp); - - for(i=0;inum_attrib;i++) { - char *namePtr; + return __rsxGetAttrs((rsxProgram*) fp); +} - if(!attribs[i].name_off) continue; +s32 rsxFragmentProgramGetAttribIndex(const rsxFragmentProgram *fp,const char *name) +{ + rsxProgramAttrib *attr = __rsxGetAttr((rsxProgram*) fp, name); + + if (attr != NULL) + return attr->index; - namePtr = ((char*)fp) + attribs[i].name_off; - if(strcasecmp(name,namePtr)==0) - return attribs[i].index; - } return -1; } -rsxConstOffsetTable* rsxFragmentProgramGetConstOffsetTable(rsxFragmentProgram *fp,u32 table_off) +rsxProgramAttrib* rsxFragmentProgramGetAttrib(const rsxFragmentProgram *fp,const char *name) +{ + return __rsxGetAttr((rsxProgram*) fp, name); +} + +rsxConstOffsetTable* rsxFragmentProgramGetConstOffsetTable(const rsxFragmentProgram *fp,u32 table_off) { return (rsxConstOffsetTable*)(((u8*)fp) + table_off); } diff --git a/ppu/librsx/init.c b/ppu/librsx/init.c index ba7852ef..24cc4137 100644 --- a/ppu/librsx/init.c +++ b/ppu/librsx/init.c @@ -2,20 +2,32 @@ #include #include -gcmContextData* rsxInit(const u32 cmdSize,const u32 ioSize,const void *ioAddress) +static gcmContextData *gGcmContext ATTRIBUTE_PRXPTR = NULL; +static gcmContextData sUserContext = +{ + NULL, + NULL, + NULL, + NULL +}; + +extern s32 gcmInitBodyEx(gcmContextData* ATTRIBUTE_PRXPTR *ctx,const u32 cmdSize,const u32 ioSize,const void *ioAddress); + +s32 rsxInit(gcmContextData **context,u32 cmdSize,u32 ioSize,const void *ioAddress) { s32 ret = -1; - gcmContextData *context ATTRIBUTE_PRXPTR; - ret = gcmInitBody(&context,cmdSize,ioSize,ioAddress); + if(context == NULL) return -1; + + ret = gcmInitBodyEx(&gGcmContext,cmdSize,ioSize,ioAddress); if(ret==0) { rsxHeapInit(); - return context; + *context = gGcmContext; } - return NULL; + return ret; } -void rsxSetupContextData(gcmContextData *context,const u32 *addr,const u32 size,gcmContextCallback cb) +void rsxSetupContextData(gcmContextData *context,const u32 *addr,u32 size,gcmContextCallback cb) { u32 alignedSize = size&~0x3; @@ -24,3 +36,33 @@ void rsxSetupContextData(gcmContextData *context,const u32 *addr,const u32 size, context->end = (u32*)(addr + alignedSize - 4); context->callback = (gcmContextCallback)__get_opd32(cb); } + +void rsxSetCurrentBuffer(gcmContextData **context,const u32 *addr,u32 size) +{ + u32 alignedSize = size&~0x3; + + gGcmContext = &sUserContext; + + sUserContext.begin = (u32*)addr; + sUserContext.current = (u32*)addr; + sUserContext.end = (u32*)((u64)addr + alignedSize - 4); + + *context = gGcmContext; +} + +void rsxSetDefaultCommandBuffer(gcmContextData **context) +{ + gcmSetDefaultCommandBuffer(); + *context = gGcmContext; +} + +void rsxSetUserCallback(gcmContextCallback cb) +{ + sUserContext.callback = cb; +} + +u32* rsxGetCurrentBuffer() +{ + return gGcmContext->current; +} + diff --git a/ppu/librsx/rsx_internal.c b/ppu/librsx/rsx_internal.c new file mode 100644 index 00000000..d562190b --- /dev/null +++ b/ppu/librsx/rsx_internal.c @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + +#include "rsx_internal.h" + +rsxProgramAttrib* __rsxGetAttrs(const rsxProgram *prg) +{ + return (rsxProgramAttrib*)(((u8*)prg) + prg->attr_off);; +} + +rsxProgramAttrib* __rsxGetAttr(const rsxProgram *prg, const char *name) +{ + u32 i; + rsxProgramAttrib *attribs = __rsxGetAttrs(prg); + for(i=0;inum_attr;i++) { + char *namePtr; + + if(!attribs[i].name_off) continue; + + namePtr = ((char*)prg) + attribs[i].name_off; + if(strcasecmp(name,namePtr)==0) + return &attribs[i]; + } + return NULL; +} + +rsxProgramConst* __rsxGetConsts(const rsxProgram *prg) +{ + return (rsxProgramConst*)(((u8*)prg) + prg->const_off); +} + +s32 __rsxGetConstIndex(const rsxProgram *prg, const char *name) +{ + u32 i; + rsxProgramConst *consts = __rsxGetConsts(prg); + for(i=0;inum_const;i++) { + char *namePtr; + + if(!consts[i].name_off) continue; + + namePtr = ((char*)prg) + consts[i].name_off; + if(strcasecmp(name,namePtr)==0) + return i; + } + return -1; +} diff --git a/ppu/librsx/rsx_internal.h b/ppu/librsx/rsx_internal.h index bb97d3d8..95115e8a 100644 --- a/ppu/librsx/rsx_internal.h +++ b/ppu/librsx/rsx_internal.h @@ -4,29 +4,42 @@ #include #include -#define RSX_METHOD_FLAG_NO_INCREMENT (0x40000000) -#define RSX_METHOD_FLAG_JUMP (0x20000000) -#define RSX_METHOD_FLAG_CALL (0x00000002) -#define RSX_METHOD_FLAG_RETURN (0x00020000) +#define RSX_METHOD_FLAG_NO_INCREMENT (0x40000000) +#define RSX_METHOD_FLAG_JUMP (0x20000000) +#define RSX_METHOD_FLAG_CALL (0x00000002) +#define RSX_METHOD_FLAG_RETURN (0x00020000) -#define RSX_MAX_METHOD_COUNT 0x7ff +#define RSX_MAX_METHOD_COUNT 0x7ff -#define RSX_CONTEXT_CURRENTP (context->current) +#define RSX_CONTEXT_CURRENTP (context->current) +#define RSX_CONTEXT_CURRENT_END(x) context->current += (x) -#define RSX_CONTEXT_CURRENT_BEGIN(count) do { \ - if((context->current + (count)) > context->end) { \ - if(rsxContextCallback(context,(count))!=0) return; \ - } \ -} while(0) +#define RSX_METHOD_COUNT_SHIFT (18) +#define RSX_METHOD(method,count) (((count)<current += (x) +#define RSX_SUBCHANNEL_SHIFT (13) +#define RSX_SUBCHANNEL_METHOD(channel,method,count) (((count)<ucode_off); + *size = vp->num_insn*sizeof(u32)*4; + *ucode = (void*)(((u8*)vp) + vp->ucode_off); } -rsxProgramConst* rsxVertexProgramGetConsts(rsxVertexProgram *vp) +u16 rsxVertexProgramGetNumConst(const rsxVertexProgram *vp) { - return (rsxProgramConst*)(((u8*)vp) + vp->const_off); + return vp->num_const; } -s32 rsxVertexProgramGetConst(rsxVertexProgram *vp,const char *name) +u16 rsxVertexProgramGetNumAttrib(const rsxVertexProgram *vp) { - u32 i; - rsxProgramConst *vpc = rsxVertexProgramGetConsts(vp); + return vp->num_attr; +} - for(i=0;inum_const;i++) { - char *namePtr; +rsxProgramConst* rsxVertexProgramGetConsts(const rsxVertexProgram *vp) +{ + return __rsxGetConsts((rsxProgram*) vp); +} - if(!vpc[i].name_off) continue; +rsxProgramConst* rsxVertexProgramGetConst(const rsxVertexProgram *vp,const char *name) +{ + rsxProgramConst *vpc = __rsxGetConsts((rsxProgram*) vp); + s32 index = __rsxGetConstIndex((rsxProgram*) vp, name); - namePtr = ((char*)vp) + vpc[i].name_off; - if(strcasecmp(name,namePtr)==0) - return i; - } - return -1; + if (index == -1) return NULL; + + return &vpc[index]; } -rsxProgramAttrib* rsxVertexProgramGetAttribs(rsxVertexProgram *vp) +s32 rsxVertexProgramGetConstIndex(const rsxVertexProgram *vp,const char *name) { - return (rsxProgramAttrib*)(((u8*)vp) + vp->attrib_off); + return __rsxGetConstIndex((rsxProgram*) vp, name); } -s32 rsxVertexProgramGetAttrib(rsxVertexProgram *vp,const char *name) +rsxProgramAttrib* rsxVertexProgramGetAttribs(const rsxVertexProgram *vp) { - u32 i; - rsxProgramAttrib *attribs = rsxVertexProgramGetAttribs(vp); + return __rsxGetAttrs((rsxProgram*) vp); +} - for(i=0;inum_attrib;i++) { - char *namePtr; +rsxProgramAttrib* rsxVertexProgramGetAttrib(const rsxVertexProgram *vp,const char *name) +{ + return __rsxGetAttr((rsxProgram*) vp, name); +} - if(!attribs[i].name_off) continue; +s32 rsxVertexProgramGetAttribIndex(const rsxVertexProgram *vp,const char *name) +{ + rsxProgramAttrib *attr = __rsxGetAttr((rsxProgram*) vp, name); + + if (attr != NULL) + return attr->index; - namePtr = ((char*)vp) + attribs[i].name_off; - if(strcasecmp(name,namePtr)==0) - return attribs[i].index; - } return -1; } diff --git a/ppu/librt/sbrk.c b/ppu/librt/sbrk.c index db63dd78..cc953039 100644 --- a/ppu/librt/sbrk.c +++ b/ppu/librt/sbrk.c @@ -81,7 +81,7 @@ static void sbrk_init() appear after crtbegin.o in the link order, this will place the call to sbrk_deinit() after the call to __do_global_dtors_aux(), which is what we want. */ -asm ("\t.section\t.fini\n\tbl .sbrk_deinit\n\tnop\n\t.previous"); +asm ("\t.section\t.fini\n\tbl sbrk_deinit\n\tnop\n\t.previous"); static void sbrk_deinit() __attribute__((used)); static void sbrk_deinit() { diff --git a/ppu/sprx/Makefile b/ppu/sprx/Makefile index 886efb58..ca837e33 100644 --- a/ppu/sprx/Makefile +++ b/ppu/sprx/Makefile @@ -20,6 +20,8 @@ all: @$(MAKE) -C libvdec --no-print-directory @$(MAKE) -C libusb --no-print-directory @$(MAKE) -C libspurs --no-print-directory + @$(MAKE) -C libfont --no-print-directory + @$(MAKE) -C libfontFT --no-print-directory install: @$(MAKE) -C libio install --no-print-directory @@ -43,6 +45,8 @@ install: @$(MAKE) -C libvdec install --no-print-directory @$(MAKE) -C libusb install --no-print-directory @$(MAKE) -C libspurs install --no-print-directory + @$(MAKE) -C libfont install --no-print-directory + @$(MAKE) -C libfontFT install --no-print-directory clean: @$(MAKE) -C libio clean --no-print-directory @@ -66,5 +70,7 @@ clean: @$(MAKE) -C libvdec clean --no-print-directory @$(MAKE) -C libusb clean --no-print-directory @$(MAKE) -C libspurs clean --no-print-directory + @$(MAKE) -C libfont clean --no-print-directory + @$(MAKE) -C libfontFT clean --no-print-directory .PHONY: all clean install diff --git a/ppu/sprx/common/exports.S b/ppu/sprx/common/exports.S index bb492b8f..efa42fa7 100644 --- a/ppu/sprx/common/exports.S +++ b/ppu/sprx/common/exports.S @@ -1,6 +1,10 @@ #include "config.h" #include +#define GP_ARG_MIN_REG 3 +#define GP_ARG_MAX_REG 10 +#define GP_ARG_NUM_REG (GP_ARG_MAX_REG - GP_ARG_MIN_REG + 1) + .align 2 .section ".rodata.sceFNID","a" .globl LIBRARY_SYMBOL @@ -13,16 +17,16 @@ LIBRARY_SYMBOL: __##name: \ mflr r0; \ std r0,16(r1); \ + std r2,40(r1); \ stdu r1,-128(r1); \ - std r2,112(r1); \ lis r12,name##_stub@ha; \ lwz r12,name##_stub@l(r12); \ lwz r0,0(r12); \ lwz r2,4(r12); \ mtctr r0; \ bctrl; \ - ld r2,112(r1); \ addi r1,r1,128; \ + ld r2,40(r1); \ ld r0,16(r1); \ mtlr r0; \ blr; \ @@ -32,4 +36,48 @@ __##name: \ name: \ .quad __##name,.TOC.@tocbase,0 +#define EXPORT_VA(name,fnid,argc) \ + .align 2; \ + .section ".sceStub.text","ax"; \ + .globl __##name; \ +__##name: \ + mflr r0; \ + std r0,16(r1); \ + std r2,40(r1); \ + std r30,-16(r1); \ + std r31,-8(r1); \ + stdu r1,-160(r1); \ + li r12,(argc - GP_ARG_NUM_REG); \ + extsh. r12,r12; \ + ble 1f; \ + li r31,276; \ + li r30,112; \ + mtctr r12; \ +2: \ + lwzx r12,r31,r1; \ + clrldi r12,r12,32; \ + stdx r12,r30,r1; \ + addi r31,r31,8; \ + addi r30,r30,8; \ + bdnz 2b; \ +1: \ + lis r12,name##_stub@ha; \ + lwz r12,name##_stub@l(r12); \ + lwz r0,0(r12); \ + lwz r2,4(r12); \ + mtctr r0; \ + bctrl; \ + addi r1,r1,160; \ + ld r30,-16(r1); \ + ld r31,-8(r1); \ + ld r2,40(r1); \ + ld r0,16(r1); \ + mtlr r0; \ + blr; \ + .align 3; \ + .section ".opd","aw"; \ + .globl name; \ +name: \ + .quad __##name,.TOC.@tocbase,0 + #include "exports.h" diff --git a/ppu/sprx/common/libexport.c b/ppu/sprx/common/libexport.c index 613d5b10..4781b544 100644 --- a/ppu/sprx/common/libexport.c +++ b/ppu/sprx/common/libexport.c @@ -42,4 +42,10 @@ static prx_header header __attribute__((section(".lib.stub"))) = { const void* name##_stub __attribute__((section(".data.sceFStub." LIBRARY_NAME))) = &__##name; \ const uint32_t name##_fnid __attribute__((section(".rodata.sceFNID"))) = fnid +// duplicate the macro impl, as i don't know whether macro substitution works properly, with strigify, or not. +#define EXPORT_VA(name, fnid, argc) \ + extern void* __##name; \ + const void* name##_stub __attribute__((section(".data.sceFStub." LIBRARY_NAME))) = &__##name; \ + const uint32_t name##_fnid __attribute__((section(".rodata.sceFNID"))) = fnid + #include "exports.h" diff --git a/ppu/sprx/libfont/Makefile b/ppu/sprx/libfont/Makefile new file mode 100644 index 00000000..0be145cb --- /dev/null +++ b/ppu/sprx/libfont/Makefile @@ -0,0 +1,101 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +BUILD := build +SOURCES := ../common . +INCLUDES := . + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPS := $(BASEDIR)/deps +export LIBS := $(BASEDIR)/lib + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +export CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +export CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +export sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +export SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ + -I$(BASEDIR)/../../include + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBS)/$(PLATFORM) +export DEPSDIR := $(DEPS)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + + +LIBRARY := $(LIBDIR)/libfont + +#--------------------------------------------------------------------------------- +LD := $(PREFIX)ld + +CFLAGS := -O2 -mregnames -Wall -mcpu=cell -DSPRX_INTERNAL $(MACHDEP) $(INCLUDE) -Wa,-mcell +ASFLAGS := $(MACHDEP) -mregnames -mcpu=cell -DSPRX_INTERNAL -D__ASSEMBLY__ -Wa,-mcell $(INCLUDE) + +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- + +all: ppu + +#--------------------------------------------------------------------------------- +ppu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBS)/ppu ] || mkdir -p $(LIBS)/ppu + @[ -d $(DEPS)/ppu ] || mkdir -p $(DEPS)/ppu + @[ -d ppu ] || mkdir -p ppu + @$(MAKE) PLATFORM=ppu lib -C ppu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install: all +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/ppu/lib ] || mkdir -p $(PSL1GHT)/ppu/lib + @cp -frv $(CURDIR)/lib/ppu/*.a $(PSL1GHT)/ppu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: sprx.o font_wrapper.o +#--------------------------------------------------------------------------------- + +.PHONY: lib ppu install + +#--------------------------------------------------------------------------------- +lib: $(LIBRARY).a +#--------------------------------------------------------------------------------- + +libexport.o: libexport.c + @$(CC) $(DEPSOPT) -S -m32 $(INCLUDE) $< -o libexport.S + @$(CC) $(DEPSOPT) -c libexport.S -o $@ + +sprx.o: exports.o libexport.o + @$(LD) -r exports.o libexport.o -o $@ +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf ppu + @rm -rf $(DEPS) + @rm -rf $(LIBS) + +-include $(DEPSDIR)/*.d diff --git a/ppu/sprx/libfont/config.h b/ppu/sprx/libfont/config.h new file mode 100644 index 00000000..9a9a0e02 --- /dev/null +++ b/ppu/sprx/libfont/config.h @@ -0,0 +1,5 @@ +#define LIBRARY_NAME "cellFont" +#define LIBRARY_SYMBOL cellFont + +#define LIBRARY_HEADER_1 0x2c000001 +#define LIBRARY_HEADER_2 0x0009 diff --git a/ppu/sprx/libfont/exports.h b/ppu/sprx/libfont/exports.h new file mode 100644 index 00000000..08e9086b --- /dev/null +++ b/ppu/sprx/libfont/exports.h @@ -0,0 +1,67 @@ +#ifndef __EXPORTS_H__ +#define __EXPORTS_H__ + +EXPORT(fontGetRenderEffectWeight, 0x0109f3d3); +EXPORT(fontCreateRenderer, 0x042e74e3); +EXPORT(fontGetKerning, 0x06be743d); +EXPORT(fontOpenFontsetOnMemory, 0x073fa321); +EXPORT(fontOpenFontFile, 0x0a7306a4); +EXPORT(fontGetRenderScaledKerning, 0x0baf90fe); +EXPORT(fontGetRenderScalePixel, 0x0d106a11); +EXPORT(fontGetHorizontalLayout, 0x1387c45c); +EXPORT(fontRenderCharGlyphImageHorizontal, 0x1a218fe4); +EXPORT(fontDestroyRenderer, 0x21ebb248); +EXPORT(fontSetupRenderScalePixel, 0x227e1e3c); +EXPORT(fontGlyphGetHorizontalShift, 0x231d5941); +EXPORT(fontSetEffectWeight, 0x25253fe4); +EXPORT(fontGetEffectWeight, 0x25dbeff9); +EXPORT(fontGetScalePixel, 0x285d30d6); +EXPORT(fontOpenFontInstance, 0x29329541); +EXPORT(fontSetScalePixel, 0x297f0e93); +EXPORT(fontGetRenderCharGlyphMetrics, 0x2da9fd9d); +EXPORT(fontEndLibrary, 0x40d40544); +EXPORT(fontAdjustFontScaling, 0x47ca71ef); +EXPORT(fontSetupRenderScalePoint, 0x4d19c631); +EXPORT(fontGlyphGetVerticalShift, 0x534e785f); +EXPORT(fontGetGlyphExpandBufferInfo, 0x59ef0073); +EXPORT(fontGetLibraryEx, 0x5abd8b1e); +EXPORT(fontBindRenderer, 0x66a23100); +EXPORT(fontGetVerticalLayout, 0x698897f8); +EXPORT(fontGetRenderCharGlyphMetricsVertical, 0x700e6223); +EXPORT(fontSetScalePoint, 0x70f3e728); +EXPORT(fontSetupRenderEffectSlant, 0x78d05e08); +EXPORT(fontEnd, 0x7ab47f7e); +EXPORT(fontGetInitializedRevisionFlags, 0x7c5df0d8); +EXPORT(fontSetEffectSlant, 0x8657c8f5); +EXPORT(fontRenderCharGlyphImage, 0x88be4799); +EXPORT(fontGetResolutionDpi, 0x8a632038); +EXPORT(fontGlyphRenderImageVertical, 0x8e3f2c40); +EXPORT(fontRenderSurfaceInit, 0x90b9465e); +EXPORT(fontGlyphRenderImageHorizontal, 0x97b95244); +EXPORT(fontGetFontIdCode, 0x98ac5524); +EXPORT(fontOpenFontMemory, 0x9e19072b); +EXPORT(fontAdjustGlyphExpandBuffer, 0x9e3b1e16); +EXPORT(fontGetRenderScalePoint, 0xa165daae); +EXPORT(fontSetupRenderEffectWeight, 0xa6dc25d1); +EXPORT(fontDelete, 0xa7b2103a); +EXPORT(fontOpenFontset, 0xa885cc9b); +EXPORT(fontGetRevisionFlags, 0xb015a84e); +EXPORT(fontCloseFont, 0xb276f1f6); +EXPORT(fontPatchWorks, 0xb3d304b2); +EXPORT(fontRenderSurfaceSetScissor, 0xb422b005); +EXPORT(fontGenerateCharGlyphEx, 0xc17259de); +EXPORT(fontGetBindingRendererEx, 0xc91c8ece); +EXPORT(fontGenerateCharGlyphVerticalEx, 0xcaed32c1); +EXPORT(fontGetRenderEffectSlant, 0xced4dda9); +EXPORT(fontDeleteGlyph, 0xd62f5d76); +EXPORT(fontGetCharGlyphMetrics, 0xd8eaee9f); +EXPORT(fontGlyphRenderImage, 0xe01b199e); +EXPORT(fontGetEffectSlant, 0xe16e679a); +EXPORT(fontRenderCharGlyphImageVertical, 0xe857a0ca); +EXPORT(fontInitializeWithRevision, 0xf03dcc29); +EXPORT(fontUnbindRenderer, 0xf16379fa); +EXPORT(fontGetScalePoint, 0xf7a19060); +EXPORT(fontSetResolutionDpi, 0xfb3341ba); +EXPORT(fontGetCharGlyphMetricsVertical, 0xfe9a6dd7); + +#endif diff --git a/ppu/sprx/libfont/font_wrapper.c b/ppu/sprx/libfont/font_wrapper.c new file mode 100644 index 00000000..4816e2f2 --- /dev/null +++ b/ppu/sprx/libfont/font_wrapper.c @@ -0,0 +1,70 @@ +#include +#include + +#include + +extern s32 fontGetLibraryEx(font *f,const fontLibrary* ATTRIBUTE_PRXPTR *lib,u32 *type); +extern s32 fontGetBindingRendererEx(font *f,fontRenderer* ATTRIBUTE_PRXPTR *renderer); +extern s32 fontGenerateCharGlyphEx(font *f,u32 code,fontGlyph* ATTRIBUTE_PRXPTR *glyph); +extern s32 fontGenerateCharGlyphVerticalEx(font *f,u32 code,fontGlyph* ATTRIBUTE_PRXPTR *glyph); + +void fontGetStubRevisionFlags(u64 *revisionFlags) +{ + if(revisionFlags == NULL) return; + *revisionFlags = 0x14; +} + +s32 fontGetLibrary(font *f,const fontLibrary **lib,u32 *type) +{ + s32 ret; + const fontLibrary *l ATTRIBUTE_PRXPTR; + + if(f == NULL || lib == NULL || type == NULL) return 0x80540002; + + ret = fontGetLibraryEx(f,&l,type); + *lib = ret == 0 ? l : NULL; + + return ret; +} + +s32 fontGetBindingRenderer(font *f,fontRenderer **renderer) +{ + s32 ret; + fontRenderer *r ATTRIBUTE_PRXPTR; + + if(f == NULL || renderer == NULL) return 0x80540002; + + ret = fontGetBindingRendererEx(f,&r); + *renderer = ret == 0 ? r : NULL; + + return ret; +} + +s32 fontGenerateCharGlyph(font *f,u32 code,fontGlyph **glyph) +{ + s32 ret; + fontGlyph *g ATTRIBUTE_PRXPTR; + + if(f == NULL || glyph == NULL) return 0x80540002; + + ret = fontGenerateCharGlyphEx(f,code,&g); + *glyph = ret == 0 ? g : NULL; + + return ret; +} + +s32 fontGenerateCharGlyphVertical(font *f,u32 code,fontGlyph **glyph) +{ + s32 ret; + fontGlyph *g ATTRIBUTE_PRXPTR; + + if(f == NULL || glyph == NULL) return 0x80540002; + + ret = fontGenerateCharGlyphVerticalEx(f,code,&g); + *glyph = ret == 0 ? g : NULL; + + return ret; +} + + + diff --git a/ppu/sprx/libfontFT/Makefile b/ppu/sprx/libfontFT/Makefile new file mode 100644 index 00000000..c6a478ee --- /dev/null +++ b/ppu/sprx/libfontFT/Makefile @@ -0,0 +1,101 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +BUILD := build +SOURCES := ../common . +INCLUDES := . + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPS := $(BASEDIR)/deps +export LIBS := $(BASEDIR)/lib + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +export CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +export CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +export sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +export SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export INCLUDE := $(foreach dir,$(INCLUDES), -iquote $(CURDIR)/$(dir)) \ + -I$(BASEDIR)/../../include + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBS)/$(PLATFORM) +export DEPSDIR := $(DEPS)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + + +LIBRARY := $(LIBDIR)/libfontFT + +#--------------------------------------------------------------------------------- +LD := $(PREFIX)ld + +CFLAGS := -O2 -mregnames -Wall -mcpu=cell -DSPRX_INTERNAL $(MACHDEP) $(INCLUDE) -Wa,-mcell +ASFLAGS := $(MACHDEP) -mregnames -mcpu=cell -DSPRX_INTERNAL -D__ASSEMBLY__ -Wa,-mcell $(INCLUDE) + +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- + +all: ppu + +#--------------------------------------------------------------------------------- +ppu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBS)/ppu ] || mkdir -p $(LIBS)/ppu + @[ -d $(DEPS)/ppu ] || mkdir -p $(DEPS)/ppu + @[ -d ppu ] || mkdir -p ppu + @$(MAKE) PLATFORM=ppu lib -C ppu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install: all +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/ppu/lib ] || mkdir -p $(PSL1GHT)/ppu/lib + @cp -frv $(CURDIR)/lib/ppu/*.a $(PSL1GHT)/ppu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: sprx.o fontft_wrapper.o +#--------------------------------------------------------------------------------- + +.PHONY: lib ppu install + +#--------------------------------------------------------------------------------- +lib: $(LIBRARY).a +#--------------------------------------------------------------------------------- + +libexport.o: libexport.c + @$(CC) $(DEPSOPT) -S -m32 $(INCLUDE) $< -o libexport.S + @$(CC) $(DEPSOPT) -c libexport.S -o $@ + +sprx.o: exports.o libexport.o + @$(LD) -r exports.o libexport.o -o $@ +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf ppu + @rm -rf $(DEPS) + @rm -rf $(LIBS) + +-include $(DEPSDIR)/*.d diff --git a/ppu/sprx/libfontFT/config.h b/ppu/sprx/libfontFT/config.h new file mode 100644 index 00000000..79b106be --- /dev/null +++ b/ppu/sprx/libfontFT/config.h @@ -0,0 +1,5 @@ +#define LIBRARY_NAME "cellFontFT" +#define LIBRARY_SYMBOL cellFontFT + +#define LIBRARY_HEADER_1 0x2c000001 +#define LIBRARY_HEADER_2 0x0009 diff --git a/ppu/sprx/libfontFT/exports.h b/ppu/sprx/libfontFT/exports.h new file mode 100644 index 00000000..7ae76089 --- /dev/null +++ b/ppu/sprx/libfontFT/exports.h @@ -0,0 +1,8 @@ +#ifndef __EXPORTS_H__ +#define __EXPORTS_H__ + +EXPORT(fontInitLibraryFreeTypeWithRevision, 0x7a0a83c4); +EXPORT(fontFTGetRevisionFlags, 0xec89a187); +EXPORT(fontFTGetInitializedRevisionFlags, 0xfa0c2de0); + +#endif diff --git a/ppu/sprx/libfontFT/fontft_wrapper.c b/ppu/sprx/libfontFT/fontft_wrapper.c new file mode 100644 index 00000000..00297222 --- /dev/null +++ b/ppu/sprx/libfontFT/fontft_wrapper.c @@ -0,0 +1,29 @@ +#include +#include + +#include +#include + +extern s32 fontInitLibraryFreeTypeWithRevision(u64 revisionFlags,fontLibraryConfigFT *config,const fontLibrary* ATTRIBUTE_PRXPTR *lib); + +void fontFTGetStubRevisionFlags(u64 *revisionFlags) +{ + if(revisionFlags == NULL) return; + *revisionFlags = 0x14; +} + +s32 fontInitLibraryFreeType(fontLibraryConfigFT *config,const fontLibrary **lib) +{ + s32 ret; + u64 revisionFlags = 0LL; + const fontLibrary *l ATTRIBUTE_PRXPTR; + + if(config == NULL || lib == NULL) return 0x80540002; + + fontFTGetStubRevisionFlags(&revisionFlags); + + ret = fontInitLibraryFreeTypeWithRevision(revisionFlags,config,&l); + *lib = ret == 0 ? l : NULL; + + return ret; +} diff --git a/ppu/sprx/libgcm_sys/exports.h b/ppu/sprx/libgcm_sys/exports.h index 9cc4ae69..100c69b8 100644 --- a/ppu/sprx/libgcm_sys/exports.h +++ b/ppu/sprx/libgcm_sys/exports.h @@ -1,7 +1,7 @@ #ifndef __EXPORTS_H__ #define __EXPORTS_H__ -EXPORT(gcmInitBody, 0x15bae46b); +EXPORT(gcmInitBodyEx, 0x15bae46b); EXPORT(gcmSetDisplayBuffer, 0xa53d12ae); EXPORT(gcmGetControlRegister, 0xa547adde); EXPORT(gcmAddressToOffset, 0x21ac3697); @@ -27,8 +27,8 @@ EXPORT(gcmGetReport, 0x99d397ac); EXPORT(gcmSetTile, 0xd0b1d189); EXPORT(gcmBindTile, 0x4524cccd); EXPORT(gcmUnbindTile, 0xd9b7653e); -EXPORT(gcmSetZcull, 0xd34a420d); -EXPORT(gcmBindZcull, 0x9dc04436); +EXPORT_VA(gcmSetZcull, 0xd34a420d, 12); +EXPORT_VA(gcmBindZcull, 0x9dc04436, 12); EXPORT(gcmUnbindZcull, 0xa75640e8); EXPORT(gcmGetTimeStamp, 0x5a41c10f); EXPORT(gcmSetVBlankFrequency, 0xffe0160e); @@ -44,7 +44,7 @@ EXPORT(gcmMapMainMemory, 0xa114ec67); EXPORT(gcmMapEaIoAddress, 0x63441cb4); EXPORT(gcmUnmapEaIoAddress, 0xefd00f54); EXPORT(gcmUnmapIoAddress, 0xdb23e867); -EXPORT(gcmIoOffsetToAddress, 0x2a6fba9c); +EXPORT(gcmIoOffsetToAddressEx, 0x2a6fba9c); EXPORT(gcmSetDefaultCommandBuffer, 0xbc982946); EXPORT(gcmSetTileInfo, 0xbd100dbc); EXPORT(gcmGetTiledPitchSize, 0x055bd74d); @@ -57,16 +57,14 @@ EXPORT(gcmGetOffsetTable, 0x2922aed0); EXPORT(gcmGetLastSecondVTime, 0x23ae55a3); EXPORT(gcmSortRemapEaIoAddress, 0x25b40ab4); EXPORT(gcmGetDisplayBufferByFlipIndex, 0x371674cf); -EXPORT(gcmGcmGetDefaultCommandWordSize, 0x5e2ee0f0); -EXPORT(gcmGcmGetDefaultSegmentWordSize, 0x8cdf8c70); +EXPORT(gcmGetDefaultCommandWordSize, 0x5e2ee0f0); +EXPORT(gcmGetDefaultSegmentWordSize, 0x8cdf8c70); EXPORT(gcmSetDefaultCommandBufferAndSegmentWordSize, 0x172c3197); EXPORT(gcmGetDisplayInfo, 0x0e6b0dae); EXPORT(gcmDumpGraphicsError, 0x1f61b3ff); EXPORT(gcmFunc38, 0x688b8ac9); EXPORT(gcmGetCurrentDisplayBufferId, 0x93806525); -EXPORT(gcmGetDefaultCommandWordSize, 0x5e2ee0f0); -EXPORT(gcmGetDefaultSegmentWordSize, 0x8cdf8c70); EXPORT(gcmGetMaxIoMapSize, 0xfb81c03e); EXPORT(gcmGetNotifyDataAddress, 0x21cee035); EXPORT(gcmGetReportDataAddress, 0x9a0159af); diff --git a/ppu/sprx/libgcm_sys/gcm_wrapper.c b/ppu/sprx/libgcm_sys/gcm_wrapper.c index 66d0d6af..2902db71 100644 --- a/ppu/sprx/libgcm_sys/gcm_wrapper.c +++ b/ppu/sprx/libgcm_sys/gcm_wrapper.c @@ -8,6 +8,34 @@ extern void gcmSetSecondVHandlerEx(opd32 *opd); extern void gcmSetUserHandlerEx(opd32 *opd); extern void gcmSetQueueHandlerEx(opd32 *opd); extern void gcmSetUserCommandEx(opd32 *opd); +extern s32 gcmIoOffsetToAddressEx(u32 offset,void* ATTRIBUTE_PRXPTR *address); +extern s32 gcmInitBodyEx(gcmContextData* ATTRIBUTE_PRXPTR *ctx,const u32 cmdSize,const u32 ioSize,const void *ioAddress); + +s32 gcmInitBody(gcmContextData **ctx,const u32 cmdSize,const u32 ioSize,const void *ioAddress) +{ + s32 ret; + gcmContextData *context ATTRIBUTE_PRXPTR; + + if(ctx == NULL) return -1; + + ret = gcmInitBodyEx(&context,cmdSize,ioSize,ioAddress); + *ctx = ret == 0 ? context : NULL; + + return ret; +} + +s32 gcmIoOffsetToAddress(u32 offset,void **address) +{ + s32 ret; + void *addr ATTRIBUTE_PRXPTR; + + if(address == NULL) return -1; + + ret = gcmIoOffsetToAddressEx(offset,&addr); + *address = ret == 0 ? addr : NULL; + + return ret; +} void gcmSetVBlankHandler(void (*handler)(const u32 head)) { diff --git a/ppu/sprx/libhttp/http_wrapper.c b/ppu/sprx/libhttp/http_wrapper.c index 1b81c0ef..5008a921 100644 --- a/ppu/sprx/libhttp/http_wrapper.c +++ b/ppu/sprx/libhttp/http_wrapper.c @@ -13,36 +13,36 @@ extern s32 httpClientSetCookieRecvCallbackEx(httpClientId cid, opd32 *opd, void s32 httpClientSetAuthenticationCallback(httpClientId cid,httpAuthenticationCallback cb,void *arg) { - printf ( "IN: httpClientSetAuthenticationStateCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetAuthenticationStateCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetAuthenticationCallbackEx(cid,(opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetAuthenticationStateCallback(%d, %p, %p)\n", cid, cb, arg) ; + printf ( "OUT: httpClientSetAuthenticationStateCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetAuthenticationCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } s32 httpClientSetTransactionStateCallback(httpClientId cid,httpTransactionStateCallback cb,void *arg) { - printf ( "IN: httpClientSetTransactionStateCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetTransactionStateCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetTransactionStateCallbackEx(cid,(opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetTransactionStateCallback(%d, %p, %p)\n", cid, cb, arg) ; + printf ( "OUT: httpClientSetTransactionStateCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetTransactionStateCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } s32 httpClientSetRedirectCallback(httpClientId cid,httpRedirectCallback cb,void *arg) { - printf ( "IN: httpClientSetRedirectCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetRedirectCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetRedirectCallbackEx(cid,(opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetRedirectCallback(%d, %p, %p)\n", cid, cb, arg) ; + printf ( "OUT: httpClientSetRedirectCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetRedirectCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } s32 httpClientSetCookieSendCallback(httpClientId cid, httpCookieSendCallback cb, void *arg) { - printf ( "IN: httpClientSetCookieSendCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetCookieSendCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetCookieSendCallbackEx(cid, (opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetCookieSendCallback(%d, %p, %p)\n", cid, cb, arg ) ; + printf ( "OUT: httpClientSetCookieSendCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetCookieSendCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } s32 httpClientSetCookieRecvCallback(httpClientId cid, httpCookieRecvCallback cb, void *arg) { - printf ( "IN: httpClientSetCookieRecvCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetCookieRecvCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetCookieRecvCallbackEx(cid, (opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetCookieRecvCallback(%d, %p, %p)\n", cid, cb, arg ) ; + printf ( "OUT: httpClientSetCookieRecvCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetCookieRecvCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } diff --git a/ppu/sprx/libhttp/https_wrapper.c b/ppu/sprx/libhttp/https_wrapper.c index d073d3c1..761e3812 100644 --- a/ppu/sprx/libhttp/https_wrapper.c +++ b/ppu/sprx/libhttp/https_wrapper.c @@ -9,8 +9,8 @@ extern s32 httpClientSetSslCallbackEx(httpClientId cid, opd32 *opd, void *userAr s32 httpClientSetSslCallback(httpClientId cid, httpsSslCallback cb, void *arg) { - printf ( "IN: httpClientSetSslCallback(%p, %p, %p)\n", cid, cb, arg ) ; - printf ( "OUT: httpClientSetSslCallbackEx(%p, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg ) ; - return httpClientSetSslCallbackEx(cid, (opd32*)__get_opd32(cb),arg); + printf ( "IN: httpClientSetSslCallback(%d, %p, %p)\n", cid, cb, arg) ; + printf ( "OUT: httpClientSetSslCallbackEx(%d, %p, %p)\n", cid, (opd32*)__get_opd32(cb), arg) ; + return httpClientSetSslCallbackEx(cid, (opd32*)__get_opd32(cb), arg); } diff --git a/ppu/sprx/libjpgdec/exports.h b/ppu/sprx/libjpgdec/exports.h index 0154aea7..9f78f1de 100644 --- a/ppu/sprx/libjpgdec/exports.h +++ b/ppu/sprx/libjpgdec/exports.h @@ -9,4 +9,9 @@ EXPORT(jpgDecReadHeader, 0x6d9ebccf); EXPORT(jpgDecDecodeData, 0xaf8bb012); EXPORT(jpgDecSetParameter, 0xe08f3910); +EXPORT(jpgDecExtSetParameter, 0x65cbbb16); +EXPORT(jpgDecExtDecodeData, 0x716f8792); +EXPORT(jpgDecExtOpen, 0xa9f703e3); +EXPORT(jpgDecExtReadHeader, 0xb91eb3d2); + #endif diff --git a/ppu/sprx/libjpgdec/jpgdec.c b/ppu/sprx/libjpgdec/jpgdec.c index a2f218fc..d44ae3ee 100644 --- a/ppu/sprx/libjpgdec/jpgdec.c +++ b/ppu/sprx/libjpgdec/jpgdec.c @@ -45,53 +45,56 @@ static void jpg_free(void *ptr,void *usrdata) static s32 decodeJPEG(jpgDecSource *src,jpgData *out) { s32 mHandle,sHandle,ret; - u32 space_allocated; - u64 bytes_per_line; jpgDecInfo DecInfo; jpgDecInParam inParam; + jpgDecOpnInfo openInfo; jpgDecOutParam outParam; jpgDecDataInfo DecDataInfo; jpgDecThreadInParam InThdParam; jpgDecThreadOutParam OutThdParam; + jpgDecDataCtrlParam dataCtrlParam; + jpgCbCtrlMalloc fnMalloc = jpg_malloc; + jpgCbCtrlFree fnFree = jpg_free; - InThdParam.enable = 0; + InThdParam.spu_enable = JPGDEC_SPU_THREAD_DISABLE; InThdParam.ppu_prio = 512; InThdParam.spu_prio = 200; - InThdParam.malloc_func = __get_addr32(__get_opd32(jpg_malloc)); - InThdParam.malloc_arg = 0; // no args - InThdParam.free_func = __get_addr32(__get_opd32(jpg_free)); - InThdParam.free_arg = 0; // no args + InThdParam.malloc_func = (jpgCbCtrlMalloc)__get_opd32(fnMalloc); + InThdParam.malloc_arg = NULL; + InThdParam.free_func = (jpgCbCtrlFree)__get_opd32(fnFree); + InThdParam.free_arg = NULL; ret = jpgDecCreate(&mHandle,&InThdParam,&OutThdParam); out->bmp_out = NULL; if(ret==0) { - ret = jpgDecOpen(mHandle,&sHandle,src,&space_allocated); + ret = jpgDecOpen(mHandle,&sHandle,src,&openInfo); if(ret==0) { ret = jpgDecReadHeader(mHandle,sHandle,&DecInfo); - if(ret==0 && DecInfo.space==0) ret = -1; + if(ret==0 && DecInfo.color_space==0) ret = -1; if(ret==0) { - inParam.cmd_ptr = 0; + inParam.cmd_ptr = NULL; inParam.down_scale = 1; - inParam.quality = JPGDEC_LOW_QUALITY; - inParam.mode = JPGDEC_TOP_TO_BOTTOM; - inParam.space = JPGDEC_ARGB; + inParam.quality_mode = JPGDEC_FAST; + inParam.output_mode = JPGDEC_TOP_TO_BOTTOM; + inParam.color_space = JPGDEC_ARGB; inParam.alpha = 0xff; ret = jpgDecSetParameter(mHandle,sHandle,&inParam,&outParam); } if(ret==0) { - out->pitch = bytes_per_line = outParam.width*4; - out->bmp_out = malloc(bytes_per_line*outParam.height); + out->pitch = outParam.width*4; + out->bmp_out = malloc(out->pitch*outParam.height); if(!out->bmp_out) ret = -1; else { - memset(out->bmp_out,0,(bytes_per_line*outParam.height)); + memset(out->bmp_out,0,(out->pitch*outParam.height)); - ret = jpgDecDecodeData(mHandle,sHandle,out->bmp_out,&bytes_per_line,&DecDataInfo); - if(ret==0 && DecDataInfo.status==0) { + dataCtrlParam.output_bytes_per_line = out->pitch; + ret = jpgDecDecodeData(mHandle,sHandle,out->bmp_out,&dataCtrlParam,&DecDataInfo); + if(ret==0 && DecDataInfo.decode_status==0) { out->width = outParam.width; out->height = outParam.height; @@ -117,9 +120,9 @@ s32 jpgLoadFromFile(const char *filename,jpgData *out) memset(&source,0,sizeof(jpgDecSource)); - source.stream = JPGDEC_FILE; - source.file_name = __get_addr32(filename); - source.enable = JPGDEC_DISABLE; + source.stream_sel = JPGDEC_FILE; + source.file_name = filename; + source.spu_enable = JPGDEC_SPU_THREAD_DISABLE; return decodeJPEG(&source,out); } @@ -130,10 +133,10 @@ s32 jpgLoadFromBuffer(const void *buffer,u32 size,jpgData *out) memset(&source,0,sizeof(jpgDecSource)); - source.stream = JPGDEC_BUFFER; - source.stream_ptr = __get_addr32(buffer); + source.stream_sel = JPGDEC_BUFFER; + source.stream_ptr = (void*)buffer; source.stream_size = size; - source.enable = JPGDEC_DISABLE; + source.spu_enable = JPGDEC_SPU_THREAD_DISABLE; return decodeJPEG(&source,out); } diff --git a/ppu/sprx/liblv2/Makefile b/ppu/sprx/liblv2/Makefile index 71060056..9da9e180 100644 --- a/ppu/sprx/liblv2/Makefile +++ b/ppu/sprx/liblv2/Makefile @@ -76,7 +76,8 @@ install: all @cp -frv $(CURDIR)/lib/ppu/*.a $(PSL1GHT)/ppu/lib #--------------------------------------------------------------------------------- -$(LIBRARY).a: sprx.o thread_wrapper.o spu_printf_wrapper.o process_wrapper.o +$(LIBRARY).a: sprx.o thread_wrapper.o spu_printf_wrapper.o process_wrapper.o \ + spu_thread_printf.o sys_spu_wrapper.o #--------------------------------------------------------------------------------- .PHONY: lib ppu install diff --git a/ppu/sprx/liblv2/exports.h b/ppu/sprx/liblv2/exports.h index 43801fcd..ba362e3a 100644 --- a/ppu/sprx/liblv2/exports.h +++ b/ppu/sprx/liblv2/exports.h @@ -139,12 +139,14 @@ EXPORT(sysSpuRawLoad, 0x893305fa); EXPORT(sysSpuRawImageLoad, 0xb995662e); EXPORT(sysSpuImageClose, 0xe0da8efd); EXPORT(sysSpuImageImport, 0xebe5f72f); -EXPORT(sysSpuPrintfAttachGroup, 0xdd0c1e09); /* sysPrxForUser */ -EXPORT(sysSpuPrintfAttachThread, 0x1ae10b92); /* sysPrxForUser */ -EXPORT(sysSpuPrintfDetachGroup, 0x5fdfb2fe); /* sysPrxForUser */ -EXPORT(sysSpuPrintfDetach_Tread, 0xb3bbcf2a); /* sysPrxForUser */ -EXPORT(sysSpuPrintfFinalize, 0xdd3b27ac); /* sysPrxForUser */ -EXPORT(sysSpuPrintfInitialize, 0x45fe2fce); /* sysPrxForUser */ + +/* the following exports are renamed due to our own _working_ implementation */ +EXPORT(sysSpuPrintfAttachGroupEx, 0xdd0c1e09); /* sysPrxForUser */ +EXPORT(sysSpuPrintfAttachThreadEx, 0x1ae10b92); /* sysPrxForUser */ +EXPORT(sysSpuPrintfDetachGroupEx, 0x5fdfb2fe); /* sysPrxForUser */ +EXPORT(sysSpuPrintfDetachThreadEx, 0xb3bbcf2a); /* sysPrxForUser */ +EXPORT(sysSpuPrintfFinalizeEx, 0xdd3b27ac); /* sysPrxForUser */ +EXPORT(sysSpuPrintfInitializeEx, 0x45fe2fce); /* sysPrxForUser */ /* console */ EXPORT(sysConsoleGetc, 0x8a2f159b); /* sysPrxForUser */ diff --git a/ppu/sprx/liblv2/spu_printf_wrapper.c b/ppu/sprx/liblv2/spu_printf_wrapper.c index 837179b2..55a12c15 100644 --- a/ppu/sprx/liblv2/spu_printf_wrapper.c +++ b/ppu/sprx/liblv2/spu_printf_wrapper.c @@ -1,12 +1,179 @@ #include #include #include -#include +#include +#include +#include +#include +#define SPU_PORT_PRINTF 1 +#define MAX_QUEUE_SIZE 127 +#define TERMINATING_PORT_NAME 0xFEE1DEAD -extern s32 sysSpuPrintfInitializeEx(int prio, opd32 *opdentry); +static u32 spu_printf_initialized = 0; -s32 sysSpuPrintfInitialize(int prio,void (*entry)(void*)) +static sys_event_queue_t eventQ; +static sys_ppu_thread_t spu_printf_handler; +static sys_event_port_t terminating_port; + +static void spu_printf_handler_entry(void *arg) +{ + int ret; + + (void)arg; + + for(;;) { + sys_event_t event; + sys_spu_thread_t thread_id; + + ret = sysEventQueueReceive(eventQ, &event, 0); + + + if (event.source == TERMINATING_PORT_NAME) { + sysThreadExit(0); + } + thread_id = event.data_1; + int sret = spu_thread_printf(thread_id, event.data_3); + ret = sysSpuThreadWriteMb(thread_id, sret); + if (ret) { + sysThreadExit(-1); + } + } + + sysThreadExit(0); +} + +s32 sysSpuPrintfInitialize(int prio, void (*entry)(void*)) +{ + s32 ret; + void (*run_entry)(void*) = entry; + sys_event_queue_attr_t evQAttr = { SYS_EVENT_QUEUE_PRIO, SYS_EVENT_QUEUE_PPU, "" }; + + if(spu_printf_initialized) + return 0; + + if(run_entry == NULL) + run_entry = spu_printf_handler_entry; + + ret = sysEventQueueCreate(&eventQ, &evQAttr, SYS_EVENT_QUEUE_KEY_LOCAL, MAX_QUEUE_SIZE); + if (ret) { + return ret; + } + + ret = sysThreadCreate(&spu_printf_handler, run_entry, &eventQ, 200, 4096, THREAD_JOINABLE, "spu_printf_handler"); + if (ret) { + return ret; + } + + ret = sysEventPortCreate(&terminating_port, SYS_EVENT_PORT_LOCAL, TERMINATING_PORT_NAME); + if (ret) { + return ret; + } + + ret = sysEventPortConnectLocal(terminating_port, eventQ); + if (ret) { + return ret; + } + + spu_printf_initialized = 1; + return 0; +} + +s32 sysSpuPrintfAttachThread(sys_spu_thread_t thread) { - return sysSpuPrintfInitializeEx(prio,(opd32*)__get_opd32(entry)); + int ret; + + if(!spu_printf_initialized) + return -1; + + /*attach event_port for spu_printf to thread*/ + ret = sysSpuThreadConnectEvent(thread, eventQ, SPU_THREAD_EVENT_USER, SPU_PORT_PRINTF); + if (ret) { + return ret; + } + return 0; +} + +s32 sysSpuPrintfDetachThread(sys_spu_thread_t thread) +{ + s32 ret; + + if(!spu_printf_initialized) + return -1; + + /*dettach event_port for spu_printf from thread*/ + ret = sysSpuThreadDisconnectEvent(thread, SPU_THREAD_EVENT_USER, SPU_PORT_PRINTF); + if (ret) { + return ret; + } + return 0; +} + +s32 sysSpuPrintfAttachGroup(sys_spu_group_t group) +{ + int ret; + + if(!spu_printf_initialized) + return -1; + + ret = sysSpuThreadGroupConnectEvent(group, eventQ, SPU_THREAD_EVENT_USER); + if (ret) { + return ret; + } + return 0; +} + +s32 sysSpuPrintfDetachGroup(sys_spu_group_t group) +{ + int ret; + + if(!spu_printf_initialized) + return -1; + + ret = sysSpuThreadGroupDisconnectEvent(group, SPU_THREAD_EVENT_USER); + if (ret) { + return ret; + } + return 0; +} + +s32 sysSpuPrintfFinalize() +{ + s32 ret; + u64 exit_code; + + if(!spu_printf_initialized) + return 0; + + /* + * send event for temination. + */ + ret = sysEventPortSend(terminating_port, 0, 0, 0); + if (ret) { + return ret; + } + /* wait for termination of the handler thread */ + ret = sysThreadJoin(spu_printf_handler, &exit_code); + if (ret) { + return ret; + } + + /* Disconnect and destroy the terminating port */ + ret = sysEventPortDisconnect(terminating_port); + if (ret) { + return ret; + } + ret = sysEventPortDestroy(terminating_port); + if (ret) { + return ret; + } + + /* clean event_queue for spu_printf */ + ret = sysEventQueueDestroy(eventQ, 0); + if (ret) { + return ret; + } + + spu_printf_initialized = 0; + return 0; } diff --git a/ppu/sprx/liblv2/spu_thread_printf.c b/ppu/sprx/liblv2/spu_thread_printf.c new file mode 100644 index 00000000..42d91106 --- /dev/null +++ b/ppu/sprx/liblv2/spu_thread_printf.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include +#include + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +#define __DOUTBUFSIZE 256 + +#define do_div(n,base) \ +({ \ + s64 _res; \ + _res = ((u64)n)%(unsigned)base; \ + n = ((u64)n)/(unsigned)base; \ + _res; \ +}) + +#define GET_CHAR(pos) \ +({ \ + u64 _rval; \ + sysSpuThreadReadLocalStorage(id, pos, &_rval, sizeof(char)); \ + (char)_rval; \ +}) + +#define GET_ARG(pos, type) \ +({ \ + u64 _rval; \ + sysSpuThreadReadLocalStorage(id, arg_addr + (1 + pos)*16, &_rval, sizeof(type)); \ + (type)_rval; \ +}) + +static char __outstr[__DOUTBUFSIZE] __attribute__((aligned(16))); + +static int skip_atoi(sys_spu_thread_t id, u64 *fmt_addr) +{ + char c; + int i = 0; + + while(is_digit((c=GET_CHAR(*fmt_addr)))) { + i = i*10 + c - '0'; + (*fmt_addr)++; + } + + return i; +} + +static int __strnlen(sys_spu_thread_t id, u32 arg_addr, s32 maxlen) +{ + char c; + int len = 0; + + for(;;) { + c = GET_CHAR(arg_addr++); + if(c == 0) break; + if(maxlen > -1 && len >= maxlen) break; + len++; + } + return len; +} + +static char* print_string(sys_spu_thread_t id, char *str, u32 arg_addr, s32 field_width, s32 precision, u32 flags) +{ + int i, len; + const char *nil = ""; + + if(arg_addr == 0) { + len = strnlen(nil, precision); + + if(!(flags&LEFT)) + while(len < field_width--) + *str++ = ' '; + for(i=0;i < len;i++) + *str++ = *nil++; + while(len < field_width--) + *str++ = ' '; + return str; + } + + len = __strnlen(id, arg_addr, precision); + if(!(flags&LEFT)) + while(len < field_width--) + *str++ = ' '; + for(i=0;i < len;i++) + *str++ = GET_CHAR(arg_addr++); + while(len < field_width--) + *str++ = ' '; + return str; +} + +static char* number(char *str, s64 num, s32 base, s32 size, s32 precision, s32 type) +{ + int i; + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + + if(type&LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if(type&LEFT) + type &= ~ZEROPAD; + if(base < 2 || base > 36) + return NULL; + + sign = 0; + c = (type&ZEROPAD) ? '0' : ' '; + if(type&SIGN) { + if(num < 0) { + sign = '-';sys_mem_container_t + num = -num; + size--; + } else if(type&PLUS) { + sign = '+'; + size--; + } else if(type&SPACE) { + sign = ' '; + size--; + } + } + if(type&SPECIAL) { + if(base == 16) + size -= 2; + else if(base == 8) + size--; + } + + i = 0; + if(num == 0) + tmp[i++] = '0'; + else while(num != 0) + tmp[i++] = digits[do_div(num,base)]; + + if(i > precision) + precision = i; + size -= precision; + + if(!(type&(ZEROPAD + LEFT))) + while(size-- > 0) + *str++ = ' '; + + if(sign) + *str++ = sign; + + if(type&SPECIAL) { + if(base == 8) + *str++ = '0'; + else if(base == 16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + + if(!(type&LEFT)) + while(size-- > 0) + *str++ = c; + while(i < precision--) + *str++ = '0'; + while(i-- > 0) + *str++ = tmp[i]; + while(size-- > 0) + *str++ = ' '; + + return str; +} + +static char* number_double(char *str, double num, s32 size, s32 precision, s32 type) +{ + return NULL; +} + +s32 spu_thread_sprintf(char *buf, sys_spu_thread_t id, u32 arg_addr) +{ + u64 num; + s32 base; + u32 flags; + char *str; + u32 arg_pos; + u64 fmt_addr; + s32 qualifier; + s32 precision; + s32 field_width; + ieee32 v; + + sysSpuThreadReadLocalStorage(id, arg_addr, &fmt_addr, sizeof(u32)); + + arg_pos = 0; + for(str=buf;;fmt_addr++) { + char c; + + c = GET_CHAR(fmt_addr); + if(c == 0) break; + + if(c != '%') { + *str++ = c; + continue; + } + + flags = 0; +repeat: + ++fmt_addr; + switch(GET_CHAR(fmt_addr)) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + field_width = -1; + c = GET_CHAR(fmt_addr); + if(is_digit(c)) + field_width = skip_atoi(id, &fmt_addr); + else if(c == '*') { + ++fmt_addr; + + field_width = GET_ARG(arg_pos++, int); + if(field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + precision = -1; + c = GET_CHAR(fmt_addr); + if(c == '.') { + ++fmt_addr; + c = GET_CHAR(fmt_addr); + if(is_digit(c)) { + precision = skip_atoi(id, &fmt_addr); + } else if(c == '*') { + ++fmt_addr; + precision = GET_ARG(arg_pos++, int); + } + if(precision < 0) + precision = 0; + } + + qualifier = -1; + c = GET_CHAR(fmt_addr); + if(c == 'h' || c == 'l' || c == 'L') { + qualifier = c; + ++fmt_addr; + } + + base = 10; + c = GET_CHAR(fmt_addr); + switch(c) { + case 'c': + if(!(flags&LEFT)) + while(--field_width>0) + *str++ = ' '; + *str++ = GET_ARG(arg_pos++, char); + while(--field_width>0) + *str++ = ' '; + continue; + case 's': + str = print_string(id, str, GET_ARG(arg_pos++, u64), field_width, precision, flags); + continue; + case '%': + *str++ = '%'; + continue; + case 'o': + base = 8; + break; + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + case 'f': + v.u = GET_ARG(arg_pos++, unsigned int); + str = number_double(str, v.f, field_width, precision, flags); + break; + default: + *str++ = '%'; + if(c) + *str++ = c; + else + --fmt_addr; + continue; + } + if(qualifier == 'l') + num = GET_ARG(arg_pos++, u64); + else if(qualifier == 'h') { + num = GET_ARG(arg_pos++, u16); + if(flags&SIGN) + num = (s16)num; + } else if(flags&SIGN) + num = GET_ARG(arg_pos++, s32); + else + num = GET_ARG(arg_pos++, u32); + str = number(str, num, base, field_width, precision, flags); + } + + *str = '\0'; + return str - buf; +} + +s32 spu_thread_printf(sys_spu_thread_t id, u32 arg_addr) +{ + int len; + + len = spu_thread_sprintf(__outstr, id, arg_addr); + fwrite(__outstr, 1, len, stdout); + + return len; +} diff --git a/ppu/sprx/liblv2/sys_spu_wrapper.c b/ppu/sprx/liblv2/sys_spu_wrapper.c new file mode 100644 index 00000000..4a2bb836 --- /dev/null +++ b/ppu/sprx/liblv2/sys_spu_wrapper.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include + +s32 sysSpuImageOpenELF(sysSpuImage* image, const char* path) +{ + s32 ret = -1; + FILE *fd = NULL; + size_t fsize = 0; + void *data = NULL; + + fd = fopen(path, "rb"); + if(fd != NULL) { + fseek(fd,0,SEEK_END); + fsize = ftell(fd); + fseek(fd,0,SEEK_SET); + + data = malloc(fsize); + if(data != NULL) { + fread(data,1,fsize,fd); + ret = sysSpuImageImport(image,data,SPU_IMAGE_PROTECT); + free(data); + } + fclose(fd); + } + + return ret; +} diff --git a/ppu/sprx/libpngdec/pngdec.c b/ppu/sprx/libpngdec/pngdec.c index c51cea2d..74ec5eb8 100644 --- a/ppu/sprx/libpngdec/pngdec.c +++ b/ppu/sprx/libpngdec/pngdec.c @@ -45,37 +45,39 @@ static void png_free(void *ptr,void *usrdata) static s32 decodePNG(pngDecSource *src,pngData *out) { s32 mHandle,sHandle,ret; - u32 space_allocated; - u64 bytes_per_line; pngDecInfo DecInfo; + pngDecOpnInfo openInfo; pngDecInParam inParam; pngDecOutParam outParam; pngDecDataInfo DecDataInfo; pngDecThreadInParam InThdParam; pngDecThreadOutParam OutThdParam; + pngDecDataCtrlParam dataCtrlParam; + pngCbCtrlMalloc fnMalloc = png_malloc; + pngCbCtrlFree fnFree = png_free; - InThdParam.enable = 0; + InThdParam.spu_enable = PNGDEC_SPU_THREAD_DISABLE; InThdParam.ppu_prio = 512; InThdParam.spu_prio = 200; - InThdParam.malloc_func = __get_addr32(__get_opd32(png_malloc)); - InThdParam.malloc_arg = 0; // no args - InThdParam.free_func = __get_addr32(__get_opd32(png_free)); - InThdParam.free_arg = 0; // no args + InThdParam.malloc_func = (pngCbCtrlMalloc)__get_opd32(fnMalloc); + InThdParam.malloc_arg = NULL; + InThdParam.free_func = (pngCbCtrlFree)__get_opd32(fnFree); + InThdParam.free_arg = NULL; ret= pngDecCreate(&mHandle, &InThdParam, &OutThdParam); out->bmp_out = NULL; if(ret==0) { - ret = pngDecOpen(mHandle,&sHandle,src,&space_allocated); + ret = pngDecOpen(mHandle,&sHandle,src,&openInfo); if(ret==0) { ret = pngDecReadHeader(mHandle,sHandle,&DecInfo); if(ret==0) { inParam.cmd_ptr = 0; - inParam.mode = PNGDEC_TOP_TO_BOTTOM; - inParam.space = PNGDEC_ARGB; + inParam.output_mode = PNGDEC_TOP_TO_BOTTOM; + inParam.color_space = PNGDEC_ARGB; inParam.bit_depth = 8; - inParam.pack_flag = 1; - if(DecInfo.space==PNGDEC_GRAYSCALE_ALPHA || DecInfo.space==PNGDEC_RGBA || DecInfo.chunk_info&0x10) + inParam.pack_flag = PNGDEC_1BYTE_PER_1PIXEL; + if(DecInfo.color_space==PNGDEC_GRAYSCALE_ALPHA || DecInfo.color_space==PNGDEC_RGBA || DecInfo.chunk_info&0x10) inParam.alpha_select = 0; else inParam.alpha_select = 1; @@ -86,15 +88,16 @@ static s32 decodePNG(pngDecSource *src,pngData *out) } if(ret==0) { - out->pitch = bytes_per_line = outParam.width*4; + out->pitch = outParam.width*4; out->bmp_out = malloc(out->pitch*outParam.height); if(!out->bmp_out) ret = -1; else { - memset(out->bmp_out,0,(bytes_per_line*outParam.height)); + memset(out->bmp_out,0,(out->pitch*outParam.height)); - ret = pngDecDecodeData(mHandle,sHandle,out->bmp_out,&bytes_per_line,&DecDataInfo); - if(ret==0 && DecDataInfo.status==0) { + dataCtrlParam.output_bytes_per_line = out->pitch; + ret = pngDecDecodeData(mHandle,sHandle,out->bmp_out,&dataCtrlParam,&DecDataInfo); + if(ret==0 && DecDataInfo.decode_status==0) { out->width = outParam.width; out->height = outParam.height; @@ -120,9 +123,9 @@ s32 pngLoadFromFile(const char *filename,pngData *out) memset(&source,0,sizeof(pngDecSource)); - source.stream = PNGDEC_FILE; - source.file_name = __get_addr32(filename); - source.enable = PNGDEC_DISABLE; + source.stream_sel = PNGDEC_FILE; + source.file_name = filename; + source.spu_enable = PNGDEC_SPU_THREAD_DISABLE; return decodePNG(&source,out); } @@ -133,10 +136,10 @@ s32 pngLoadFromBuffer(const void *buffer,u32 size,pngData *out) memset(&source,0,sizeof(pngDecSource)); - source.stream = PNGDEC_BUFFER; - source.stream_ptr = __get_addr32(buffer); + source.stream_sel = PNGDEC_BUFFER; + source.stream_ptr = (void*)buffer; source.stream_size = size; - source.enable = PNGDEC_DISABLE; + source.spu_enable = PNGDEC_SPU_THREAD_DISABLE; return decodePNG(&source,out); } diff --git a/ppu/sprx/libsysutil/sysutil_wrapper.c b/ppu/sprx/libsysutil/sysutil_wrapper.c index 55e37d06..2e36a764 100644 --- a/ppu/sprx/libsysutil/sysutil_wrapper.c +++ b/ppu/sprx/libsysutil/sysutil_wrapper.c @@ -7,6 +7,7 @@ #include #include #include +#include /* sysUtil functions */ extern s32 sysUtilRegisterCallbackEx(s32 slot,opd32 *opd,void *usrdata); @@ -53,10 +54,13 @@ extern s32 sysGameDiscRegisterDiscChangeCallbackEx(sysGameDiscEjectCallback cbEj /* Disc utility support */ extern s32 sysDiscRegisterDiscChangeCallbackEx(opd32 *cbEject,opd32 *cbInsert); +/* video system function */ +extern s32 videoRegisterCallbackEx(u32 slot, opd32 *cbVideo, void *userData); + /* sysUtil wrapper functions */ s32 sysUtilRegisterCallback(s32 slot,sysutilCallback cb,void *usrdata) { - return sysUtilRegisterCallbackEx(slot,(opd32*)__get_opd32(cb),usrdata); + return sysUtilRegisterCallbackEx(slot, (opd32*)__get_opd32(cb),usrdata); } /* msgDialog wraper functions */ @@ -229,3 +233,8 @@ s32 sysDiscRegisterDiscChangeCallback(sysDiscEjectCallback cbEject,sysDiscInsert return sysDiscRegisterDiscChangeCallbackEx((opd32*)__get_opd32(cbEject),(opd32*)__get_opd32(cbInsert)); } +/* video system functions */ +s32 videoRegisterCallback(u32 slot, videoCallback cbVideo, void *userData) +{ + return videoRegisterCallbackEx(slot, (opd32*)__get_opd32(cbVideo), userData); +} diff --git a/ppu_rules b/ppu_rules index c14c8e69..91dd077a 100644 --- a/ppu_rules +++ b/ppu_rules @@ -29,7 +29,7 @@ PS3LOADAPP := ps3load$(POSTFIX) RAW2H := raw2h$(POSTFIX) # fake SELF type4 / type8 tools -FSELF := fself.py +FSELF := fself FSELF_NPDRM := $(FSELF) -n # signed SELF type4 / type8 tools diff --git a/samples/graphics/blitting/Makefile b/samples/graphics/blitting/Makefile index 6eb1b48f..106e4b0b 100644 --- a/samples/graphics/blitting/Makefile +++ b/samples/graphics/blitting/Makefile @@ -18,14 +18,17 @@ include $(PSL1GHT)/ppu_rules TARGET := $(notdir $(CURDIR)) BUILD := build SOURCES := source -DATA := data INCLUDES := include +TITLE := Blitting Test - PSL1GHT +APPID := BLT00001 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) CXXFLAGS = $(CFLAGS) LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map @@ -110,17 +113,19 @@ clean: run: ps3load $(OUTPUT).self +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg #--------------------------------------------------------------------------------- else -DEPENDS := $(OFILES:.o=.d) +DEPENDS := $(OFILES:.o=.d) #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- $(OUTPUT).self: $(OUTPUT).elf -$(OUTPUT).elf: $(OFILES) +$(OUTPUT).elf: $(OFILES) #--------------------------------------------------------------------------------- # This rule links in binary data with the .bin extension diff --git a/samples/graphics/blitting/include/bitmap.h b/samples/graphics/blitting/include/bitmap.h index 08f1f6b3..3f857107 100644 --- a/samples/graphics/blitting/include/bitmap.h +++ b/samples/graphics/blitting/include/bitmap.h @@ -1,5 +1,7 @@ +#ifndef __BITMAP_H__ +#define __BITMAP_H__ - +#include typedef struct { u32 width; @@ -12,4 +14,6 @@ void bitmapInit(Bitmap *bitmap, u32 width, u32 height); void bitmapDestroy(Bitmap *bitmap); -void bitmapSetXpm(Bitmap *bitmap, char * xpm[]); +void bitmapSetXpm(Bitmap *bitmap, const char* xpm[]); + +#endif // __BITMAP_H__ \ No newline at end of file diff --git a/samples/graphics/blitting/include/psl1ght.xpm b/samples/graphics/blitting/include/psl1ght.xpm index aca4641f..b033e161 100644 --- a/samples/graphics/blitting/include/psl1ght.xpm +++ b/samples/graphics/blitting/include/psl1ght.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char * psl1ght_xpm[] = { +static const char * psl1ght_xpm[] = { "224 40 16 1", " c #000000", ". c #210000", diff --git a/samples/graphics/blitting/include/rsxutil.h b/samples/graphics/blitting/include/rsxutil.h new file mode 100644 index 00000000..2b13486c --- /dev/null +++ b/samples/graphics/blitting/include/rsxutil.h @@ -0,0 +1,27 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include + +#include + +#define CB_SIZE 0x100000 +#define HOST_SIZE (32*1024*1024) + +extern gcmContextData *context; +extern u32 display_width; +extern u32 display_height; +extern u32 curr_fb; + +extern u32 color_pitch; +extern u32 color_offset[2]; + +extern u32 depth_pitch; +extern u32 depth_offset; + +void setRenderTarget(u32 index); +void init_screen(void *host_addr,u32 size); +void waitflip(); +void flip(); + +#endif diff --git a/samples/graphics/blitting/source/bitmap.c b/samples/graphics/blitting/source/bitmap.cpp similarity index 85% rename from samples/graphics/blitting/source/bitmap.c rename to samples/graphics/blitting/source/bitmap.cpp index eaefff37..d288935b 100644 --- a/samples/graphics/blitting/source/bitmap.c +++ b/samples/graphics/blitting/source/bitmap.cpp @@ -1,19 +1,18 @@ - -#include -#include -#include -#include - #include -#include #include +#include +#include +#include #include +#include + +#include #include "bitmap.h" void bitmapInit(Bitmap *bitmap, u32 width, u32 height) { s32 status; - bitmap->pixels = rsxMemalign(64, width * height * 4); + bitmap->pixels = (u32*)rsxMemalign(64, width * height * 4); status = rsxAddressToOffset(bitmap->pixels, &bitmap->offset); assert(status==0); bitmap->width = width; @@ -25,11 +24,11 @@ void bitmapDestroy(Bitmap *bitmap) { bitmap->pixels = NULL; } -void bitmapSetXpm(Bitmap *bitmap, char * xpm[]) { +void bitmapSetXpm(Bitmap *bitmap, const char* xpm[]) { u32 palette[256]; u32 width, height, ncolors, depth; char *p; - int ln; + u32 ln; u32 x, y, *pix; width = atoi(xpm[0]); diff --git a/samples/graphics/blitting/source/main.c b/samples/graphics/blitting/source/main.c deleted file mode 100644 index 34a1f934..00000000 --- a/samples/graphics/blitting/source/main.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Usage of the blit functions. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "bitmap.h" -#include "psl1ght.xpm" - -typedef struct { - gcmContextData *context; - u32 curr_fb; - u32 framecnt; - u32 pitch; - u32 *buffer[2]; - u32 offset[2]; - u32 depth_pitch; - u16 *depth_buffer; - u32 depth_offset; - videoResolution res; -} displayData; - -void setRenderTarget(displayData *vdat) -{ - gcmSurface sf; - - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; - sf.colorLocation[0] = GCM_LOCATION_RSX; - sf.colorOffset[0] = vdat->offset[vdat->curr_fb]; - sf.colorPitch[0] = vdat->pitch; - - sf.colorLocation[1] = GCM_LOCATION_RSX; - sf.colorLocation[2] = GCM_LOCATION_RSX; - sf.colorLocation[3] = GCM_LOCATION_RSX; - sf.colorOffset[1] = 0; - sf.colorOffset[2] = 0; - sf.colorOffset[3] = 0; - sf.colorPitch[1] = 64; - sf.colorPitch[2] = 64; - sf.colorPitch[3] = 64; - - sf.depthFormat = GCM_TF_ZETA_Z16; - sf.depthLocation = GCM_LOCATION_RSX; - sf.depthOffset = vdat->depth_offset; - sf.depthPitch = vdat->depth_pitch; - - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; - - sf.width = vdat->res.width; - sf.height = vdat->res.height; - sf.x = 0; - sf.y = 0; - - rsxSetSurface(vdat->context, &sf); -} - -static void eventHandle(u64 status, u64 param, void * userdata) { - (void)param; - (void)userdata; - if(status == SYSUTIL_EXIT_GAME){ - printf("Quit game requested\n"); - exit(0); - }else if(status == SYSUTIL_MENU_OPEN){ - //xmb opened, should prob pause game or something :P - printf("XMB opened\n"); - }else if(status == SYSUTIL_MENU_CLOSE){ - //xmb closed, and then resume - printf("XMB closed\n"); - }else if(status == SYSUTIL_DRAW_BEGIN){ - }else if(status == SYSUTIL_DRAW_END){ - }else{ - printf("Unhandled event: %08llX\n", (unsigned long long int)status); - } -} - -void appCleanup(){ - sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); - printf("Exiting for real.\n"); -} - -/* Block the PPU thread untill the previous flip operation has finished. */ -void waitFlip() { - while(gcmGetFlipStatus() != 0) - usleep(200); - gcmResetFlipStatus(); -} - -/* Enqueue a flip command in RSX command buffer. - Setup next screen to be drawn to. */ -void flip(displayData *vdat) { - s32 status = gcmSetFlip(vdat->context, vdat->curr_fb); - assert(status == 0); - rsxFlushBuffer(vdat->context); - gcmSetWaitFlip(vdat->context); - vdat->curr_fb = !vdat->curr_fb; - ++vdat->framecnt; - setRenderTarget(vdat); -} - -/* Initilize everything. */ -void init_screen(displayData *vdat) { - int i; - - /* Allocate a 1Mb buffer, alligned to a 1Mb boundary to be our shared IO memory with the RSX. */ - void *host_addr = memalign(1024*1024, 1024*1024); - assert(host_addr != NULL); - - /* Initilise libRSX, which sets up the command buffer and shared IO memory */ - vdat->context = rsxInit(0x10000, 1024*1024, host_addr); - assert(vdat->context != NULL); - - videoState state; - s32 status = videoGetState(0, 0, &state); // Get the state of the display - assert(status == 0); - assert(state.state == 0); // Make sure display is enabled - - /* Get the current resolution */ - status = videoGetResolution(state.displayMode.resolution, &vdat->res); - assert(status == 0); - - /* Configure the buffer format to xRGB */ - videoConfiguration vconfig; - memset(&vconfig, 0, sizeof(videoConfiguration)); - vconfig.resolution = state.displayMode.resolution; - vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; - vconfig.pitch = vdat->res.width * 4; - vconfig.aspect=state.displayMode.aspect; - - status = videoConfigure(0, &vconfig, NULL, 0); - assert(status == 0); - status = videoGetState(0, 0, &state); - assert(status == 0); - - gcmSetFlipMode(GCM_FLIP_VSYNC); /* Wait for VSYNC to flip */ - - /* Allocate and setup two buffers for the RSX to draw to the screen (double buffering) */ - vdat->pitch = vdat->res.width*sizeof(u32); - for (i=0; i<2; ++i) { - vdat->buffer[i] = (u32*)rsxMemalign(64, vdat->pitch * vdat->res.height); - assert(vdat->buffer[i] != NULL); - status = rsxAddressToOffset(vdat->buffer[i], &vdat->offset[i]); - assert(status==0); - status = gcmSetDisplayBuffer(i, vdat->offset[i], vdat->pitch, vdat->res.width, vdat->res.height); - assert(status==0); - } - - /* Allocate the depth buffer */ - vdat->depth_pitch = vdat->res.width * sizeof(u16); - vdat->depth_buffer = (u16*)rsxMemalign(64, vdat->depth_pitch * vdat->res.height); - assert(vdat->depth_buffer != NULL); - status = rsxAddressToOffset(vdat->depth_buffer, &vdat->depth_offset); - assert(status==0); - - gcmResetFlipStatus(); - vdat->curr_fb = 0; - vdat->framecnt = 0; - flip(vdat); -} - -void blit_simple(displayData *vdat, Bitmap *bitmap, - u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h) -{ - rsxSetTransferImage(vdat->context, GCM_TRANSFER_LOCAL_TO_LOCAL, - vdat->offset[vdat->curr_fb], vdat->pitch, dstX-w/2, dstY-h/2, - bitmap->offset, bitmap->width*4, rsxGetFixedUint16((float)srcX), - rsxGetFixedUint16((float)srcY), w, h, 4); -} - -void blit_data(displayData *vdat, Bitmap *bitmap, - u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h) -{ - rsxSetTransferData(vdat->context, GCM_TRANSFER_LOCAL_TO_LOCAL, - vdat->offset[vdat->curr_fb], vdat->pitch, bitmap->offset, bitmap->width*4, - w*4, h); -} - -void blit_scale(displayData *vdat, Bitmap *bitmap, - u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h, float zoom) -{ - gcmTransferScale scale; - gcmTransferSurface surface; - - scale.conversion = GCM_TRANSFER_CONVERSION_TRUNCATE; - scale.format = GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8; - scale.origin = GCM_TRANSFER_ORIGIN_CORNER; - scale.operation = GCM_TRANSFER_OPERATION_SRCCOPY_AND; - scale.interp = GCM_TRANSFER_INTERPOLATOR_NEAREST; - scale.clipX = 0; - scale.clipY = 0; - scale.clipW = vdat->res.width; - scale.clipH = vdat->res.height; - scale.outX = dstX - w*zoom*.5f; - scale.outY = dstY - h*zoom*.5f; - scale.outW = w * zoom; - scale.outH = h * zoom; - scale.ratioX = rsxGetFixedSint32(1.f / zoom); - scale.ratioY = rsxGetFixedSint32(1.f / zoom); - scale.inX = rsxGetFixedUint16(srcX); - scale.inY = rsxGetFixedUint16(srcY); - scale.inW = bitmap->width; - scale.inH = bitmap->height; - scale.offset = bitmap->offset; - scale.pitch = sizeof(u32) * bitmap->width; - - surface.format = GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8; - surface.pitch = vdat->pitch; - surface.offset = vdat->offset[vdat->curr_fb]; - - rsxSetTransferScaleMode(vdat->context, GCM_TRANSFER_LOCAL_TO_LOCAL, - GCM_TRANSFER_SURFACE); - - rsxSetTransferScaleSurface(vdat->context, &scale, &surface); -} - -int main(int argc, const char* argv[]) -{ - padInfo padinfo; - padData paddata; - Bitmap bitmap; - - displayData vdat; - int quit = 0; - int i; - int k = 0; - - atexit(appCleanup); - sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, eventHandle, NULL); - - init_screen(&vdat); - printf("screen res: %dx%d buffers: %p %p\n", - vdat.res.width, vdat.res.height, vdat.buffer[0], vdat.buffer[1]); - ioPadInit(7); - - bitmapSetXpm(&bitmap, psl1ght_xpm); - - while (!quit) { - /* Check the pads. */ - ioPadGetInfo(&padinfo); - for (i=0; i=0; --i) { - int x = vdat.res.width * (0.1f + 0.8f * (0.5f+0.5f*sinf((vdat.framecnt - 10*i) * .01f))); - int y = 150 + 400 * (0.5f+0.5f*sinf((vdat.framecnt - 10*i) * .02f)); - blit_simple(&vdat, &bitmap, x, y, i*32, 0, 32, bitmap.height); - } - - /* Animate all letters, with zoom */ - for (i=6; i>=0; --i) { - int x = vdat.res.width * (0.1f + 0.8f * (0.5f+0.5f*sinf(M_PI + (vdat.framecnt - 10*i) * .01f))); - int y = 150 + 400 * (0.5f+0.5f*sinf((vdat.framecnt - 10*i) * .02f)); - blit_scale(&vdat, &bitmap, x, y, i*32, 0, 32, bitmap.height, 2.f); - } - - /* Flip buffer onto screen */ - flip(&vdat); - - sysUtilCheckCallback(); - } - waitFlip(); - bitmapDestroy(&bitmap); - - return 0; -} diff --git a/samples/graphics/blitting/source/main.cpp b/samples/graphics/blitting/source/main.cpp new file mode 100644 index 00000000..49544f04 --- /dev/null +++ b/samples/graphics/blitting/source/main.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "rsxutil.h" +#include "bitmap.h" +#include "psl1ght.xpm" + +u32 running = 0; +u32 frame_cnt = 0; + +SYS_PROCESS_PARAM(1001, 0x100000); + +extern "C" { +static void program_exit_callback() +{ + sysUtilUnregisterCallback(SYSUTIL_EVENT_SLOT0); + gcmSetWaitFlip(context); + rsxFinish(context,1); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + +void blit_simple(Bitmap *bitmap, u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h) +{ + rsxSetTransferImage(context, GCM_TRANSFER_LOCAL_TO_LOCAL, + color_offset[curr_fb], color_pitch, dstX-w/2, dstY-h/2, + bitmap->offset, bitmap->width*4, rsxGetFixedUint16((float)srcX), + rsxGetFixedUint16((float)srcY), w, h, 4); +} + +void blit_data(Bitmap *bitmap, u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h) +{ + rsxSetTransferData(context, GCM_TRANSFER_LOCAL_TO_LOCAL, + color_offset[curr_fb], color_pitch, bitmap->offset, bitmap->width*4, + w*4, h); +} + +void blit_scale(Bitmap *bitmap, u32 dstX, u32 dstY, u32 srcX, u32 srcY, u32 w, u32 h, float zoom) +{ + gcmTransferScale scale; + gcmTransferSurface surface; + + scale.conversion = GCM_TRANSFER_CONVERSION_TRUNCATE; + scale.format = GCM_TRANSFER_SCALE_FORMAT_A8R8G8B8; + scale.origin = GCM_TRANSFER_ORIGIN_CORNER; + scale.operation = GCM_TRANSFER_OPERATION_SRCCOPY_AND; + scale.interp = GCM_TRANSFER_INTERPOLATOR_NEAREST; + scale.clipX = 0; + scale.clipY = 0; + scale.clipW = display_width; + scale.clipH = display_height; + scale.outX = dstX - w*zoom*.5f; + scale.outY = dstY - h*zoom*.5f; + scale.outW = w * zoom; + scale.outH = h * zoom; + scale.ratioX = rsxGetFixedSint32(1.f / zoom); + scale.ratioY = rsxGetFixedSint32(1.f / zoom); + scale.inX = rsxGetFixedUint16(srcX); + scale.inY = rsxGetFixedUint16(srcY); + scale.inW = bitmap->width; + scale.inH = bitmap->height; + scale.offset = bitmap->offset; + scale.pitch = sizeof(u32) * bitmap->width; + + surface.format = GCM_TRANSFER_SURFACE_FORMAT_A8R8G8B8; + surface.pitch = color_pitch; + surface.offset = color_offset[curr_fb]; + + rsxSetTransferScaleMode(context, GCM_TRANSFER_LOCAL_TO_LOCAL, GCM_TRANSFER_SURFACE); + rsxSetTransferScaleSurface(context, &scale, &surface); +} + +int main(int argc,const char *argv[]) +{ + int k = 0; + padInfo padinfo; + padData paddata; + Bitmap bitmap; + void *host_addr = memalign(1024*1024,HOST_SIZE); + + printf("blitting started...\n"); + + init_screen(host_addr,HOST_SIZE); + ioPadInit(7); + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + bitmapSetXpm(&bitmap, psl1ght_xpm); + setRenderTarget(curr_fb); + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if(paddata.BTN_CROSS) + goto done; + } + + } + + /* Display some stuff on the screen */ + rsxSetClearColor(context, 0x200030); + rsxSetClearDepthStencil(context, 0xffff); + rsxClearSurface(context,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + /* Enable blending (for rsxSetTransferScaleSurface) */ + rsxSetBlendFunc(context, GCM_SRC_ALPHA, GCM_ONE_MINUS_SRC_ALPHA, GCM_SRC_ALPHA, GCM_ONE_MINUS_SRC_ALPHA); + rsxSetBlendEquation(context, GCM_FUNC_ADD, GCM_FUNC_ADD); + rsxSetBlendEnable(context, GCM_TRUE); + + /* Display the whole PSL1GHT image */ + blit_simple(&bitmap, display_width/4, 100, 0, 0, bitmap.width, bitmap.height); + + /* Distort the PSL1GHT image by displaying lines with different X coords */ + for (u32 i=0; i=0; --i) { + int x = display_width * (0.1f + 0.8f * (0.5f+0.5f*sinf((frame_cnt - 10*i) * .01f))); + int y = 150 + 400 * (0.5f+0.5f*sinf((frame_cnt - 10*i) * .02f)); + blit_simple(&bitmap, x, y, i*32, 0, 32, bitmap.height); + } + + /* Animate all letters, with zoom */ + for (int i=6; i>=0; --i) { + int x = display_width * (0.1f + 0.8f * (0.5f+0.5f*sinf(M_PI + (frame_cnt - 10*i) * .01f))); + int y = 150 + 400 * (0.5f+0.5f*sinf((frame_cnt - 10*i) * .02f)); + blit_scale(&bitmap, x, y, i*32, 0, 32, bitmap.height, 2.f); + } + + flip(); + frame_cnt++; + } + +done: + printf("blitting finished...\n"); + + bitmapDestroy(&bitmap); + return 0; +} diff --git a/samples/sys/osk/source/rsxutil.c b/samples/graphics/blitting/source/rsxutil.cpp similarity index 86% rename from samples/sys/osk/source/rsxutil.c rename to samples/graphics/blitting/source/rsxutil.cpp index b7803e6f..e61327a7 100644 --- a/samples/sys/osk/source/rsxutil.c +++ b/samples/graphics/blitting/source/rsxutil.cpp @@ -3,6 +3,9 @@ #include #include #include +#include + +#include #include "rsxutil.h" @@ -27,7 +30,7 @@ u32 *color_buffer[2]; static u32 sLabelVal = 1; -static void wait_finish() +static void waitFinish() { rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); @@ -39,22 +42,22 @@ static void wait_finish() ++sLabelVal; } -static void wait_rsx_idle() +static void waitRSXIdle() { rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); ++sLabelVal; - wait_finish(); + waitFinish(); } -void set_render_target(u32 index) +void setRenderTarget(u32 index) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = color_offset[index]; sf.colorPitch[0] = color_pitch; @@ -69,13 +72,13 @@ void set_render_target(u32 index) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = display_width; sf.height = display_height; @@ -87,7 +90,7 @@ void set_render_target(u32 index) void init_screen(void *host_addr,u32 size) { - context = rsxInit(CB_SIZE,size,host_addr); + rsxInit(&context,CB_SIZE,size,host_addr); videoState state; videoGetState(0,0,&state); @@ -101,7 +104,7 @@ void init_screen(void *host_addr,u32 size) vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; vconfig.pitch = res.width*sizeof(u32); - wait_rsx_idle(); + waitRSXIdle(); videoConfigure(0,&vconfig,NULL,0); videoGetState(0,0,&state); @@ -144,7 +147,7 @@ void flip() gcmSetWaitFlip(context); curr_fb ^= 1; - set_render_target(curr_fb); + setRenderTarget(curr_fb); first_fb = 0; } diff --git a/samples/graphics/cairo/source/rsxutil.c b/samples/graphics/cairo/source/rsxutil.c index bce58746..ec417867 100644 --- a/samples/graphics/cairo/source/rsxutil.c +++ b/samples/graphics/cairo/source/rsxutil.c @@ -108,7 +108,7 @@ initScreen (void *host_addr, u32 size) videoResolution res; /* Screen Resolution */ /* Initilise Reality, which sets up the command buffer and shared IO memory */ - context = rsxInit (CB_SIZE, size, host_addr); + rsxInit (&context, CB_SIZE, size, host_addr); if (context == NULL) goto error; @@ -191,8 +191,8 @@ setRenderTarget(gcmContextData *context, rsxBuffer *buffer) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = buffer->offset; sf.colorPitch[0] = depth_pitch; @@ -207,13 +207,13 @@ setRenderTarget(gcmContextData *context, rsxBuffer *buffer) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_TEXTURE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = buffer->width; sf.height = buffer->height; diff --git a/samples/graphics/cairo_clock/Makefile b/samples/graphics/cairo_clock/Makefile new file mode 100644 index 00000000..5e2d7756 --- /dev/null +++ b/samples/graphics/cairo_clock/Makefile @@ -0,0 +1,145 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +TITLE := Cairo clock sample - PSL1GHT +APPID := CAIRO0002 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lgcm_sys -lrsx -lsysutil -lio -lcairo -lfreetype -lz -lpixman-1 -lm -lrt -llv2 + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(OUTPUT).fake.self $(OUTPUT).gnpdrm.pkg $(OUTPUT).pkg + + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/cairo_clock/Readme.md b/samples/graphics/cairo_clock/Readme.md new file mode 100644 index 00000000..df42ce88 --- /dev/null +++ b/samples/graphics/cairo_clock/Readme.md @@ -0,0 +1,3 @@ +A nice cairo example. + +![Cairo Clock](https://github.com/crystalct/PS3LibrariesUpdate/blob/master/samples/cairo_clock/cairo_clock.png) diff --git a/samples/graphics/cairo_clock/cairo_clock.png b/samples/graphics/cairo_clock/cairo_clock.png new file mode 100644 index 00000000..62d5d45d Binary files /dev/null and b/samples/graphics/cairo_clock/cairo_clock.png differ diff --git a/samples/graphics/cairo_clock/include/rsxutil.h b/samples/graphics/cairo_clock/include/rsxutil.h new file mode 100644 index 00000000..e4e75ae2 --- /dev/null +++ b/samples/graphics/cairo_clock/include/rsxutil.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) Youness Alaoui (KaKaRoTo) + * + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 3, as published by the Free Software Foundation. + */ + +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include +#include + +#define CB_SIZE 0x100000 +#define HOST_SIZE (32*1024*1024) + +typedef struct +{ + + int height; + int width; + int id; + uint32_t *ptr; + // Internal stuff + uint32_t offset; +} rsxBuffer; + + +/* Block the PPU thread untill the previous flip operation has finished. */ +void waitFlip (void); +/* Flip a buffer onto the screen. Returns TRUE on success */ +int flip (gcmContextData *context, s32 buffer); +/* Create a buffer to draw into and assign it to @id. Returns NULL on error */ +int makeBuffer (rsxBuffer * buffer, u16 width, u16 height, int id); +/* Get current screen resolution. returns TRUE on success */ +int getResolution (u16 *width, u16 *height); +/* Initilize the RSX properly. Returns NULL on error */ +gcmContextData *initScreen (void *host_addr, u32 size); +/* Sets the target buffer to render to */ +void setRenderTarget(gcmContextData *context, rsxBuffer *buffer); + +#endif /* __RSXUTIL_H__ */ diff --git a/samples/graphics/cairo_clock/source/main.c b/samples/graphics/cairo_clock/source/main.c new file mode 100644 index 00000000..a5d96d54 --- /dev/null +++ b/samples/graphics/cairo_clock/source/main.c @@ -0,0 +1,203 @@ +// Cairo clock sample by CrystalCT (crystal@unict.it) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rsxutil.h" + +#define MAX_BUFFERS 2 + +#define DEBUG(...) + +u16 width; +u16 height; + +// Draw a single frame, do all your drawing/animation from in here. +void +drawFrame (rsxBuffer *buffer, int frame) +{ + cairo_t *cr; + cairo_surface_t *surface = NULL; + + + + + + + surface = cairo_image_surface_create_for_data ((u8 *) buffer->ptr, + CAIRO_FORMAT_RGB24, buffer->width, buffer->height, buffer->width * 4); + + if (surface != NULL) { + cr = cairo_create (surface); + if (cr != NULL) { + // Lets start by clearing everything + cairo_scale(cr, height, height); + cairo_translate(cr, 0.5 * width/height, 0.5); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + /* Draw what needs tobe drawn */ + { + // ARC + double xc = 0.0; + double yc = 0.0; + double m_radius = 0.42; + double m_line_width = 0.05; + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); // Black + + cairo_set_line_width (cr, m_line_width); + + cairo_arc (cr, xc, yc, m_radius, 0, 2 * M_PI); + cairo_stroke(cr); + + //clock ticks + int i; + for (i = 0; i < 12; i++) + { + double inset = 0.05; + + cairo_save(cr); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + + if(i % 3 != 0) + { + inset *= 0.8; + cairo_set_line_width(cr, 0.03); + } + + cairo_move_to(cr, + (m_radius - inset) * cos (i * M_PI / 6), + (m_radius - inset) * sin (i * M_PI / 6)); + cairo_line_to (cr, + m_radius * cos (i * M_PI / 6), + m_radius * sin (i * M_PI / 6)); + cairo_stroke(cr); + cairo_restore(cr); /* stack-pen-size */ + } + + // store the current time + time_t rawtime; + time(&rawtime); + struct tm * timeinfo = localtime (&rawtime); + + // compute the angles of the indicators of our clock + double minutes = timeinfo->tm_min * M_PI / 30; + double hours = timeinfo->tm_hour * M_PI / 6; + double seconds= timeinfo->tm_sec * M_PI / 30; + + cairo_save(cr); + cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); + + // draw the seconds hand + cairo_save(cr); + cairo_set_line_width(cr, m_line_width / 3); + cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); // gray + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, sin(seconds) * (m_radius * 0.9), + -cos(seconds) * (m_radius * 0.9)); + cairo_stroke(cr); + cairo_restore(cr); + + // draw the minutes hand + cairo_set_source_rgb(cr, 0.117, 0.337, 0.612); // blue + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, sin(minutes + seconds / 60) * (m_radius * 0.8), + -cos(minutes + seconds / 60) * (m_radius * 0.8)); + cairo_stroke(cr); + + // draw the hours hand + cairo_set_source_rgb(cr, 0.337, 0.612, 0.117); // green + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, sin(hours + minutes / 12.0) * (m_radius * 0.5), + -cos(hours + minutes / 12.0) * (m_radius * 0.5)); + cairo_stroke(cr); + cairo_restore(cr); + + // draw a little dot in the middle + cairo_arc(cr, 0, 0, m_line_width / 3.0, 0, 2 * M_PI); + cairo_fill(cr); + + } + + cairo_destroy (cr); // Realease Surface + } + + cairo_surface_finish (surface); + cairo_surface_destroy (surface); // Flush and destroy the cairo surface + } + +} + + + +int +main (s32 argc, const char* argv[]) +{ + gcmContextData *context; + void *host_addr = NULL; + rsxBuffer buffers[MAX_BUFFERS]; + int currentBuffer = 0; + padInfo padinfo; + padData paddata; + + int frame = 0; + int i; + + /* Allocate a 1Mb buffer, alligned to a 1Mb boundary + * to be our shared IO memory with the RSX. */ + host_addr = memalign (1024*1024, HOST_SIZE); + context = initScreen (host_addr, HOST_SIZE); + ioPadInit (7); + + getResolution(&width, &height); + for (i = 0; i < MAX_BUFFERS; i++) + makeBuffer (&buffers[i], width, height, i); + + flip(context, MAX_BUFFERS - 1); + + DEBUG ("Starting Cairo test\n"); + + while (1) { + ioPadGetInfo (&padinfo); + for(i = 0; i < MAX_PADS; i++) { + if(padinfo.status[i]) { + ioPadGetData (i, &paddata); + if(paddata.BTN_START) { + goto end; + } + } + } + + setRenderTarget(context, &buffers[currentBuffer]); + + DEBUG ("Drawing frame %d\n", frame); + waitFlip (); + drawFrame (&buffers[currentBuffer], frame++); // Draw into the unused buffer + flip (context, buffers[currentBuffer].id); // Flip buffer onto screen + + currentBuffer++; + if (currentBuffer >= MAX_BUFFERS) + currentBuffer = 0; + } + + end: + + gcmSetWaitFlip(context); + for (i = 0; i < MAX_BUFFERS; i++) + rsxFree (buffers[i].ptr); + + rsxFinish (context, 1); + free (host_addr); + ioPadEnd(); + + return 0; +} + diff --git a/samples/graphics/cairo_clock/source/rsxutil.c b/samples/graphics/cairo_clock/source/rsxutil.c new file mode 100644 index 00000000..ec417867 --- /dev/null +++ b/samples/graphics/cairo_clock/source/rsxutil.c @@ -0,0 +1,224 @@ +/* + * This software is distributed under the terms of the GNU General Public + * License ("GPL") version 3, as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rsxutil.h" + +#define GCM_LABEL_INDEX 255 + +static void waitRSXIdle(gcmContextData *context); + +static u32 depth_pitch; +static u32 depth_offset; +static u32 *depth_buffer; + +void +waitFlip () +{ + while (gcmGetFlipStatus () != 0) + usleep (200); /* Sleep, to not stress the cpu. */ + gcmResetFlipStatus (); +} + +int +flip (gcmContextData *context, s32 buffer) +{ + if (gcmSetFlip (context, buffer) == 0) { + rsxFlushBuffer (context); + // Prevent the RSX from continuing until the flip has finished. + gcmSetWaitFlip (context); + + return TRUE; + } + return FALSE; +} + + +int +makeBuffer (rsxBuffer * buffer, u16 width, u16 height, int id) +{ + int depth = sizeof(u32); + int pitch = depth * width; + int size = depth * width * height; + + buffer->ptr = (uint32_t*) rsxMemalign (64, size); + + if (buffer->ptr == NULL) + goto error; + + if (rsxAddressToOffset (buffer->ptr, &buffer->offset) != 0) + goto error; + + /* Register the display buffer with the RSX */ + if (gcmSetDisplayBuffer (id, buffer->offset, pitch, width, height) != 0) + goto error; + + buffer->width = width; + buffer->height = height; + buffer->id = id; + + return TRUE; + + error: + if (buffer->ptr != NULL) + rsxFree (buffer->ptr); + + return FALSE; +} + +int +getResolution (u16 *width, u16 *height) +{ + videoState state; + videoResolution resolution; + + /* Get the state of the display */ + if (videoGetState (0, 0, &state) == 0 && + videoGetResolution (state.displayMode.resolution, &resolution) == 0) { + if (width) + *width = resolution.width; + if (height) + *height = resolution.height; + + return TRUE; + } + return FALSE; +} + +gcmContextData * +initScreen (void *host_addr, u32 size) +{ + gcmContextData *context = NULL; /* Context to keep track of the RSX buffer. */ + videoState state; + videoConfiguration vconfig; + videoResolution res; /* Screen Resolution */ + + /* Initilise Reality, which sets up the command buffer and shared IO memory */ + rsxInit (&context, CB_SIZE, size, host_addr); + if (context == NULL) + goto error; + + /* Get the state of the display */ + if (videoGetState (0, 0, &state) != 0) + goto error; + + /* Make sure display is enabled */ + if (state.state != 0) + goto error; + + /* Get the current resolution */ + if (videoGetResolution (state.displayMode.resolution, &res) != 0) + goto error; + + /* Configure the buffer format to xRGB */ + memset (&vconfig, 0, sizeof(videoConfiguration)); + vconfig.resolution = state.displayMode.resolution; + vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; + vconfig.pitch = res.width * sizeof(u32); + vconfig.aspect = state.displayMode.aspect; + + waitRSXIdle(context); + + if (videoConfigure (0, &vconfig, NULL, 0) != 0) + goto error; + + if (videoGetState (0, 0, &state) != 0) + goto error; + + gcmSetFlipMode (GCM_FLIP_VSYNC); // Wait for VSYNC to flip + + depth_pitch = res.width * sizeof(u32); + depth_buffer = (u32 *) rsxMemalign (64, (res.height * depth_pitch)* 2); + rsxAddressToOffset (depth_buffer, &depth_offset); + + gcmResetFlipStatus(); + + return context; + + error: + if (context) + rsxFinish (context, 0); + + if (host_addr) + free (host_addr); + + return NULL; +} + + +static void +waitFinish(gcmContextData *context, u32 sLabelVal) +{ + rsxSetWriteBackendLabel (context, GCM_LABEL_INDEX, sLabelVal); + + rsxFlushBuffer (context); + + while(*(vu32 *) gcmGetLabelAddress (GCM_LABEL_INDEX) != sLabelVal) + usleep(30); + + sLabelVal++; +} + +static void +waitRSXIdle(gcmContextData *context) +{ + u32 sLabelVal = 1; + + rsxSetWriteBackendLabel (context, GCM_LABEL_INDEX, sLabelVal); + rsxSetWaitLabel (context, GCM_LABEL_INDEX, sLabelVal); + + sLabelVal++; + + waitFinish(context, sLabelVal); +} + +void +setRenderTarget(gcmContextData *context, rsxBuffer *buffer) +{ + gcmSurface sf; + + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; + sf.colorLocation[0] = GCM_LOCATION_RSX; + sf.colorOffset[0] = buffer->offset; + sf.colorPitch[0] = depth_pitch; + + sf.colorLocation[1] = GCM_LOCATION_RSX; + sf.colorLocation[2] = GCM_LOCATION_RSX; + sf.colorLocation[3] = GCM_LOCATION_RSX; + sf.colorOffset[1] = 0; + sf.colorOffset[2] = 0; + sf.colorOffset[3] = 0; + sf.colorPitch[1] = 64; + sf.colorPitch[2] = 64; + sf.colorPitch[3] = 64; + + sf.depthFormat = GCM_SURFACE_ZETA_Z16; + sf.depthLocation = GCM_LOCATION_RSX; + sf.depthOffset = depth_offset; + sf.depthPitch = depth_pitch; + + sf.type = GCM_TEXTURE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; + + sf.width = buffer->width; + sf.height = buffer->height; + sf.x = 0; + sf.y = 0; + + rsxSetSurface (context, &sf); +} diff --git a/samples/graphics/rsx_Basic/Makefile b/samples/graphics/rsx_Basic/Makefile new file mode 100644 index 00000000..f5b861d3 --- /dev/null +++ b/samples/graphics/rsx_Basic/Makefile @@ -0,0 +1,164 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +SHADERS := shaders +INCLUDES := include + +TITLE := RSX Test - PSL1GHT +APPID := RSX00003 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lsimdmath -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(SHADERS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +VCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.vcg))) +FCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.fcg))) + +VPOFILES := $(VCGFILES:.vcg=.vpo) +FPOFILES := $(FCGFILES:.fcg=.fpo) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(addsuffix .o,$(VPOFILES)) \ + $(addsuffix .o,$(FPOFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(OUTPUT).fake.self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.vpo.o : %.vpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.fpo.o : %.fpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/rsx_Basic/Readme.md b/samples/graphics/rsx_Basic/Readme.md new file mode 100644 index 00000000..c5ae4d7d --- /dev/null +++ b/samples/graphics/rsx_Basic/Readme.md @@ -0,0 +1,4 @@ +A basic example to use RSX and Vertex/Fragment without camera position, eyes position, lights, 3D objects, textures, etc etc. +Just draw a tringle..... + +![RSX basic example](rsx_basic.png?raw=true) diff --git a/samples/graphics/rsx_Basic/include/acid.h b/samples/graphics/rsx_Basic/include/acid.h new file mode 100644 index 00000000..d1643518 --- /dev/null +++ b/samples/graphics/rsx_Basic/include/acid.h @@ -0,0 +1,2939 @@ +/* GIMP RGBA C-Source image dump (acid.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +} acid = { + 128, 128, 4, + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\335\335\335\0\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31" + "\31\0\15\15\15\0\5\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0))" + ")\0===\0UUU\0qqq\0\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\345\345\345\0\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\15\15\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0qqq\0---\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\15\0\0\0" + "\23\0\0\0\30\0\0\0\35\0\0\0!\0\0\0$\0\0\0&\0\0\0(\0\0\0(\0\0\0'\0\0\0$\0" + "\0\0!\0\0\0\35\0\0\0\31\0\0\0\23\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0---\0qqq\0\271\271\271\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\17\0\0\0\30\0\0\0\40\0\0\0+\0\0\0B\0" + "\0\0\\\0\0\0t\0\0\0\211\0\0\0\234\0\0\0\254\0\0\0\271\0\0\0\304\0\0\0\313" + "\0\0\0\313\0\0\0\304\0\0\0\271\0\0\0\254\0\0\0\234\0\0\0\211\0\0\0t\0\0\0" + "\\\0\0\0B\0\0\0+\0\0\0!\0\0\0\30\0\0\0\17\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\21\21\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\2\0\0\0\14\0\0\0\30\0\0\0&\0\0\0?\0\0\0d\0\0\0\211\0\0\0\254\0\0\0\311" + "\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\354\0\0\0\361\0\0\0\365\0\0\0\370\0" + "\0\0\373\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\371\0\0\0\365\0\0\0\361\0\0" + "\0\355\0\0\0\347\0\0\0\341\0\0\0\331\0\0\0\312\0\0\0\254\0\0\0\211\0\0\0" + "d\0\0\0?\0\0\0&\0\0\0\30\0\0\0\15\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0QQQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0\33\0\0" + "\0.\0\0\0Y\0\0\0\211\0\0\0\265\0\0\0\325\0\0\0\343\0\0\0\354\0\0\0\365\0" + "\0\0\374\40!\0\377FH\0\377hk\0\377\206\213\0\377\240\246\0\377\267\275\0" + "\377\311\321\0\377\330\341\0\377\344\354\0\377\344\354\0\377\330\341\0\377" + "\311\321\0\377\267\275\0\377\240\246\0\377\206\213\0\377hk\0\377FH\0\377" + "\40!\0\377\0\0\0\375\0\0\0\365\0\0\0\355\0\0\0\343\0\0\0\326\0\0\0\266\0" + "\0\0\211\0\0\0Z\0\0\0/\0\0\0\33\0\0\0\16\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0" + "\0\0\0\0QQQ\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\255\255\255\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0" + "\27\0\0\0-\0\0\0]\0\0\0\224\0\0\0\304\0\0\0\336\0\0\0\354\0\0\0\367\30\31" + "\0\376QT\0\377\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0" + "\376\0\0\0\367\0\0\0\354\0\0\0\337\0\0\0\305\0\0\0\224\0\0\0]\0\0\0-\0\0" + "\0\30\0\0\0\11\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0===\0\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265" + "\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\15\0\0\0!\0\0\0H\0\0\0\204" + "\0\0\0\274\0\0\0\336\0\0\0\357\0\0\0\373BD\0\377\206\213\0\377\306\315\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\306\315\0\377\206\213\0\377BD\0\377\0\0\0\373" + "\0\0\0\357\0\0\0\337\0\0\0\275\0\0\0\204\0\0\0I\0\0\0!\0\0\0\15\0\0\0\3\0" + "\0\0\1\0\0\0\0\0\0\0\0===\0\265\265\265\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0QQ" + "Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0'\0\0\0[\0\0\0\236\0\0" + "\0\324\0\0\0\353\0\0\0\371FH\0\377\225\232\0\377\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\340\350\0\377\225\232\0\377FH\0\377\0\0\0\371\0" + "\0\0\353\0\0\0\324\0\0\0\236\0\0\0\\\0\0\0'\0\0\0\17\0\0\0\3\0\0\0\1\0\0" + "\0\0\0\0\0\0QQQ\0\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0(\0\0\0c\0\0\0\250" + "\0\0\0\332\0\0\0\361$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\361\0\0\0" + "\333\0\0\0\251\0\0\0c\0\0\0(\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0yyy" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0)))\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\0\0\0$\0\0\0_" + "\0\0\0\250\0\0\0\334\0\0\0\364BD\0\376\244\252\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0" + "\335\0\0\0\250\0\0\0`\0\0\0%\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\0)))\0\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\4\0\0\0\34\0\0\0O\0\0\0\234\0\0\0\332\0\0\0\364FH\0\376\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH\0\376\0\0\0\364\0" + "\0\0\332\0\0\0\234\0\0\0P\0\0\0\34\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0qqq\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315" + "\0""555\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0""0\0\0\0\203\0\0\0\321\0" + "\0\0\360+-\0\375\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377+-\0\375" + "\0\0\0\360\0\0\0\322\0\0\0\203\0\0\0""1\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0" + """555\0\315\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\4\0\0\0\40\0\0\0`\0\0\0\262\0\0\0\346\0\0\0\374~\203\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\374\0\0\0\347\0\0\0\263\0\0\0a\0\0\0\40\0\0\0\5\0\0" + "\0\1\0\0\0\0\1\1\1\0\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0" + "\0/\0\0\0\207\0\0\0\326\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\311\321\0\377FH\0\376\0\0\0\366\0\0\0\327\0\0\0\207\0\0\0" + """0\0\0\0\14\0\0\0\2\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375" + "\375\375\0UUU\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\30\0\0\0S\0\0\0\252\0\0\0\345" + "\0\0\0\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\374\0\0\0\346" + "\0\0\0\253\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\0UUU\0\375\375\375\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0==" + "=\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\"\0\0\0q\0\0\0\316\0\0\0\363/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\364\0\0\0\316\0\0\0q\0\0\0\"\0\0\0\5\0\0\0\1\0\0\0\0===\0\351\351" + "\351\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\0\0\0\0\1" + "\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\\`\0\377\0\0\0\373\0\0\0\332\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1\0\0" + "\0\1---\0\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\331\331\331\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0""2\0\0\0\225\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\342\0\0\0" + "\226\0\0\0""2\0\0\0\11\0\0\0\1\0\0\0\1%%%\0\331\331\331\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\335\335\335\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0?\0\0\0\243\0\0\0\350\2\2\0\375\240\246\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377" + "\2\2\0\375\0\0\0\350\0\0\0\244\0\0\0@\0\0\0\15\0\0\0\2\0\0\0\1%%%\0\335\335" + "\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\0\0\0\0\1\0\0\0\16" + "\0\0\0H\0\0\0\257\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\355\0\0\0\257\0\0\0H\0\0\0" + "\17\0\0\0\2\0\0\0\1---\0\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\375\375\375\0===\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0H\0\0\0\264\0\0\0\360\40!\0\376\306\315\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\40!\0\376\0\0\0" + "\360\0\0\0\265\0\0\0I\0\0\0\15\0\0\0\1\0\0\0\1===\0\375\375\375\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0?\0\0\0\257\0\0\0\360$%\0\376\315\325\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\315\325" + "\0\377$%\0\377\0\0\0\360\0\0\0\257\0\0\0@\0\0\0\11\0\0\0\1\0\0\0\1UUU\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0""2" + "\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\355\0\0\0\244\0\0\0""2\0" + "\0\0\6\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\0\0\0\0\0\0\0\0\0\0" + "\0\4\0\0\0*\0\0\0\225\0\0\0\350\25\25\0\376\306\315\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\25" + "\25\0\376\0\0\0\350\0\0\0\226\0\0\0*\0\0\0\5\0\0\0\1\0\0\0\0\235\235\235" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315\0" + "\1\1\1\0\0\0\0\0\0\0\0\3\0\0\0\"\0\0\0\205\0\0\0\342\2\2\0\375\267\275\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\2\2\0\375\0\0\0\342\0\0\0" + "\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\0\315\315\315\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374" + "\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377\13\14\0\377UX\0\377" + "\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0S\0\0\0\316\0\0\0\373\202\207" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\310\317\0\3779<\0\377\0\0\0\3779<\0\377\310\317\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\306\315\0\377!\"\0\377\0\0\0\377\0\0\0\377\4\4\0\377PT\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\316\0\0\0S\0\0\0\14\0\0\0\1\0\0\0\0qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\0\0\0\0\4\0\0\0/\0\0\0\253\0\0\0\364\\`\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377/2\0\377\0\0\0\377\0\0\0\377\0\0\0\377/2\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0" + "\253\0\0\0""0\0\0\0\5\0\0\0\1\0\0\0\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0)))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0" + "\0\207\0\0\0\345/1\0\376\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\207\215\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\357\370\0\377/1\0\376\0\0\0\346" + "\0\0\0\207\0\0\0\40\0\0\0\3\0\0\0\1)))\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0`\0\0\0\326\0\0\0\374\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\5\5\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\374\0\0\0" + "\327\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\0yyy\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0" + "\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0" + "\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\0\321\321\321\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0" + "\0\0\0\0\0\0\2\0\0\0\34\0\0\0\203\0\0\0\346FH\0\376\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\376" + "\0\0\0\347\0\0\0\204\0\0\0\34\0\0\0\2\0\0\0\1QQQ\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0\0\0\0" + "\0\0\0\12\0\0\0O\0\0\0\321\0\0\0\374\311\321\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321" + "\0\377\0\0\0\374\0\0\0\322\0\0\0P\0\0\0\13\0\0\0\1\0\0\0\0\265\265\265\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0" + "\0%\0\0\0\234\0\0\0\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\361\0\0\0\234\0\0\0%\0\0\0\3\0\0\0\1===\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0_\0" + "\0\0\332+-\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377+-\0\375\0\0\0\332\0\0\0`\0\0\0\17\0\0\0\1\0\0\0\0\255\255" + "\255\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0(\0\0\0\250\0\0\0" + "\363\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\244\252\0\377\0\0\0\364\0\0\0\250\0\0\0)\0\0\0\3\0\0\0\1=" + "==\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0c\0\0\0\334FH" + "\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\17\0\0\0" + "\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'\0\0\0\251\0\0\0\363\267\275" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0" + "(\0\0\0\3\0\0\0\1QQQ\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377BD\0\376\0\0\0\333\0\0\0\\" + "\0\0\0\16\0\0\0\1\0\0\0\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\2\0\0\0!\0\0\0\235\0\0\0\361\244\252\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\361\0" + "\0\0\236\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\35\35\35\0\0\0\0\0\0\0\0\10\0\0\0H\0\0\0\324$%\0\375\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377$%\0\375\0" + "\0\0\325\0\0\0I\0\0\0\11\0\0\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0\203\0\0\0\353~\203\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203" + "\0\377\0\0\0\353\0\0\0\204\0\0\0\27\0\0\0\1\0\0\0\0\265\265\265\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\325\335\0\377\0\0\0\371\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\336FH\0\376\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0]\0\0\0\16\0\0\0\1\21\21\21\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0\0\0\0\0\0\0\0\0\0\0\0\32\0\0\0\223\0\0\0\357\225\232\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\357\0\0\0\224\0\0\0\33\0" + "\0\0\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\340\350\0\377\0\0\0\373\0\0\0\305\0\0\0" + "/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0---\0\0\0\0\0\0\0\0\14\0\0\0Y\0\0\0\336BD\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\337\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0" + "\0\0\211\0\0\0\30\0\0\0\1\0\0\0\0\345\345\345\0\377\377\377\0\377\377\377" + "\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\265\0\0\0\367\306\315\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377" + "\0\0\0\367\0\0\0\266\0\0\0&\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377\377\377\0\377\377" + "\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343QT\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT" + "\0\377\0\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0" + "\15\15\15\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15\15\15\0\377\377\377" + "\0\335\335\335\0\0\0\0\0\0\0\0\0\0\0\0\40\0\0\0\254\0\0\0\365\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0\0!\0\0\0\1\0\0\0\0\335" + "\335\335\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0+\0\0\0\311\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\210\215\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\7\7\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\344\354\0\377\0\0\0\374\0\0\0\312\0\0\0,\0\0\0\2" + "\0\0\0\1\265\265\265\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0B\0\0\0\331\40" + "!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\20\21\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\40!\0\377\0\0\0" + "\332\0\0\0B\0\0\0\7\0\0\0\1\221\221\221\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0" + "\0\0\341FH\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\37702\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\37702\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377!\"\0\377\0\0" + "\0\377\0\0\0\377\4\4\0\377PS\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0\0\0\342\0" + "\0\0]\0\0\0\15\0\0\0\1qqq\0UUU\0\0\0\0\0\0\0\0\23\0\0\0t\0\0\0\347hk\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\3779<\0\377\0" + "\0\0\3779<\0\377\310\317\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377" + "\13\14\0\377UX\0\377\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0" + "\0\0u\0\0\0\23\0\0\0\1UUU\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206" + "\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===" + "\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0\361\240\246\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246" + "\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0\1)))\0\31\31\31\0\0\0\0\0\0\0\0" + "\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0\15\15\15\0\0\0\0\0\0\0\0$\0\0\0\271\0" + "\0\0\370\311\321\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\311\321\0\377\0\0\0\371\0\0\0\272\0\0\0" + "$\0\0\0\1\15\15\15\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\1\1\1" + "\0\0\0\0\0\0\0\0(\0\0\0\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\313\0\0\0)\0\0\0\1\1\1\1\0\1\1\1\0\0\0\0\0\0\0\0(\0\0\0" + "\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\344\354\0\377\0\0\0\375\0\0\0\313\0\0" + "\0)\0\0\0\1\1\1\1\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\15\15" + "\15\0\0\0\0\0\0\0\0$\0\0\0\271\0\0\0\370\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321\0" + "\377\0\0\0\371\0\0\0\272\0\0\0$\0\0\0\1\15\15\15\0\31\31\31\0\0\0\0\0\0\0" + "\0\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0" + "\361\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\240\246\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0" + "\1)))\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206" + "\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===\0UUU\0\0\0\0\0\0\0\0\23" + "\0\0\0t\0\0\0\347hk\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0\0\0u\0\0\0\23\0\0\0" + "\1UUU\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\341FH\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0" + "\0\0\342\0\0\0]\0\0\0\15\0\0\0\1qqq\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0" + "B\0\0\0\331\40!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\40!\0\377\0\0\0\332\0\0\0C\0\0\0\7\0\0\0\1\221" + "\221\221\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0,\0\0\0\312\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\312\0\0\0,\0\0\0\2\0\0\0\1\265\265\265\0\335\335\335\0\0" + "\0\0\0\0\0\0\1\0\0\0!\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0" + "\0\"\0\0\0\1\0\0\0\1\335\335\335\0\377\377\377\0\15\15\15\0\0\0\0\0\0\0\0" + "\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15" + "\15\15\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343" + "QT\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT\0\377\0" + "\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0qqq\0\0" + "\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377" + "\377\377\0\377\377\377\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\266\0" + "\0\0\367\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\335\345\0\377\261\270\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\0\0\0\370" + "\0\0\0\266\0\0\0'\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377\377\377" + "\0\345\345\345\0\0\0\0\0\0\0\0\1\0\0\0\31\0\0\0\212\0\0\0\354\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\322\332\0\377\36" + "\37\0\377\10\10\0\377\265\273\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\316\326\0\377\230\235\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\0" + "\0\0\1\345\345\345\0\377\377\377\0\377\377\377\0\377\377\377\0---\0\0\0\0" + "\0\0\0\0\14\0\0\0Z\0\0\0\337BD\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\1\1\0\377\201\206\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0\377\17" + "\20\0\377\2\2\0\377\224\231\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\340\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377SV\0\377\353\364\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377w{\0\377\1\1\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377;>\0\377<>\0\377<>\0\377\303\312\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\0\0\0\373\0\0\0\305\0\0\0/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\1" + "\0\0\0\33\0\0\0\224\0\0\0\357\225\232\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\26\26\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377.0\0\377" + "\330\340\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\345\355\0\377?A" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\1\1\0\377\310\320\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\360\0\0\0" + "\225\0\0\0\34\0\0\0\1\0\0\0\1\271\271\271\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0" + "]\0\0\0\337FH\0\376\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\257\266\0\377\4\4\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\16\17\0\377\265\273" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\277\306\0\377\23\24\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\0\377\226\233\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0^\0\0\0\16\0\0\0\1\21\21" + "\21\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\300\307\0\377\30\31\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377z\177\0\377\355\366" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377pt\0\377\2\2\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2" + "\0\377\235\243\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\325\335\0\377\0\0\0\371" + "\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\1\0\0\0\27\0\0\0\204\0\0\0\353~\203\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\330\341\0\377&'\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\25\25\0\377\277\306\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\377" + "-/\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\25\25\0\377\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377~\203\0\377\0\0\0\354\0\0\0\205\0\0\0\30\0\0\0\1\0\0\0\1\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\35\35\35\0\0\0\0\0\0\0\0\11\0\0\0I\0\0\0\324" + "$%\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\350\360\0\377EG\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\2\2\0\377mq\0\377\352\363\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\342\352\0" + "\377fi\0\377\2\2\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377*,\0\377\333\344\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377$%\0\375\0\0\0\325\0\0\0J\0\0\0\11\0\0" + "\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\2" + "\0\0\0!\0\0\0\236\0\0\0\361\244\252\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377tx\0\377\1\1\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\36\0\377\235\243\0" + "\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\220" + "\225\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377gj\0\377\353\364\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\362\0" + "\0\0\237\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\1\0\0\0\16\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0" + "\377\13\14\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377-/\0\377\273\302\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355\366\0\377\177\204" + "\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\11\12\0\377\246\254\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "BD\0\376\0\0\0\333\0\0\0]\0\0\0\17\0\0\0\1\0\0\0\1\331\331\331\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'" + "\0\0\0\251\0\0\0\363\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\346\356\0\377HK\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377=?\0\377\247\255\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377\206\213\0\377" + "\34\35\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377/1\0\377\325\335\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0(\0\0\0\3\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0" + "\0\0\0\0\0\0\1\0\0\0\20\0\0\0d\0\0\0\335FH\0\375\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\211\217\0\377\10\11\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\14\15\0\377qu\0\377" + "\343\353\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\356\367\0\377\254\263\0\377hl\0\377\5\5\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\16\17\0\377\231\237\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\20\0\0\0\1\0\0\0\1\271\271\271" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0)\0\0\0\251\0\0\0\363\244\252\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\346\356\0\377fi\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\4\4\0\377BD\0\377\206\213\0\377\301\310\0\377\354\365\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340\350\0\377\230\235\0" + "\377^b\0\377\25\25\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377Z^" + "\0\377\335\345\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377" + "\0\0\0\364\0\0\0\251\0\0\0*\0\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255" + "\255\255\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0`\0\0\0\332+-\0\375\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\254\263\0\377\25\25\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\13\0\377;>\0\377UX\0" + "\377lp\0\377x|\0\377x|\0\377x|\0\377bf\0\377HK\0\377\6\6\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37713\0\377\275\304" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "+-\0\375\0\0\0\332\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\1\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0%\0\0\0\234\0\0\0" + "\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\216\223\0\377\16\17\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + ",.\0\377\247\255\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0\361\0\0\0\235\0\0\0%\0" + "\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265" + "\265\265\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0P\0\0\0\322\0\0\0\374\311\321\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355" + "\366\0\377\213\221\0\377\17\20\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\37724\0\377\246\254\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\311\321\0\377\0\0\0\374\0\0\0\323\0\0\0Q\0\0\0\14\0\0\0\1\0\0\0\1" + "\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0\34\0\0\0\204\0\0\0\347FH\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\356\367\0\377\235\243\0\377(*\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\5\5\0" + "\377hl\0\377\270\276\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377FH\0\377\0\0\0\347\0\0\0\204\0\0\0\35\0\0\0\2\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321" + "\321\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\320\330\0\377\\`\0\377\7" + "\7\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\3778:\0\377\226\233\0" + "\377\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\206\213\0\377\0\0\0\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\1" + "\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0a\0\0\0" + "\327\0\0\0\374\276\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\357\370\0\377\245\253\0\377w{\0\377:=\0\377\3\3\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377*,\0\377dh\0\377\217\224\0\377\350" + "\361\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\375\0\0\0\330\0\0\0b\0\0" + "\0\20\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + ")))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0\0\207\0\0\0\346/1\0\376\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\357\370\0\377\305\314\0\377\247\255\0\377" + "\212\220\0\377x}\0\377x}\0\377x}\0\377x}\0\377{\200\0\377\240\246\0\377\270" + "\276\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377/1\0\376\0\0\0\347\0\0\0\210\0\0\0!\0\0\0\3\0\0\0" + "\1)))\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""0\0\0\0\253\0\0\0\364\\`\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0\254\0\0\0""1" + "\0\0\0\6\0\0\0\1\0\0\0\1\265\265\265\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\1\0\0\0\14\0\0" + "\0T\0\0\0\317\0\0\0\373\202\207\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\317\0\0\0T\0\0\0\15\0\0\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374\240\246\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\315\315\315\0\1\1\1\0\0\0\0\1\0\0\0\4\0\0\0\"\0" + "\0\0\205\0\0\0\342\2\2\0\375\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267" + "\275\0\377\2\2\0\375\0\0\0\342\0\0\0\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\1\315" + "\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235" + "\235\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0+\0\0\0\226\0\0\0\350\25\25\0\376\306" + "\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\306\315\0\377\25\25\0\376\0\0\0\351\0\0\0\226\0\0\0+\0\0\0\6\0" + "\0\0\1\0\0\0\1\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0" + """2\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\356\0\0\0\245\0\0\0""3\0" + "\0\0\7\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0" + "\0\0\0\0\0\0\1\0\0\0\11\0\0\0@\0\0\0\260\0\0\0\360$%\0\376\315\325\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377$%\0\377\0\0\0\361\0\0\0\260\0\0\0A\0\0\0" + "\12\0\0\0\1\0\0\0\1UUU\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\375\375\375\0===\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0H\0\0\0\264\0\0\0\360" + "\40!\0\376\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\306\315\0\377\40!\0\376\0\0\0\361\0\0\0\265\0\0\0I\0\0\0\16" + "\0\0\0\2\0\0\0\1===\1\375\375\375\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\1\0\0\0\2\0\0\0\17" + "\0\0\0I\0\0\0\260\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\356\0\0\0\260\0\0\0I\0\0\0" + "\20\0\0\0\2\0\0\0\1---\1\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "%%%\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0@\0\0\0\244\0\0\0\350\2\2\0\375\240\246" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\240\246\0\377\2\2\0\375\0\0\0\351\0\0\0\245\0\0\0@\0\0\0\16" + "\0\0\0\2\0\0\0\1%%%\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\331\331\331\0%%%\0\0\0\0\1\0\0\0\2\0\0\0\12\0\0\0""2\0\0\0\226" + "\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\343\0\0\0\226\0\0\0""3\0\0\0" + "\12\0\0\0\2\0\0\0\1%%%\1\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\1\0\0" + "\0\1\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357" + "\370\0\377\\`\0\377\0\0\0\373\0\0\0\333\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1" + "\0\0\0\1---\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0" + "===\0\0\0\0\1\0\0\0\1\0\0\0\5\0\0\0#\0\0\0r\0\0\0\317\0\0\0\364/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\365\0\0\0\317\0\0\0r\0\0\0#\0\0\0\6\0\0\0\1\0\0\0\1===\1\351\351\351" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375\375\375" + "\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0S\0\0\0\253\0\0\0\346\0\0\0" + "\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\375\0\0\0\347\0\0\0" + "\254\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\1UUU\0\375\375\375\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0/\0\0\0\210\0" + "\0\0\327\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\311\321\0\377FH\0\377\0\0\0\367\0\0\0\330\0\0\0\210\0\0\0""0\0\0\0\15\0" + "\0\0\3\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\5\0" + "\0\0!\0\0\0a\0\0\0\263\0\0\0\347\0\0\0\374~\203\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0" + "\374\0\0\0\347\0\0\0\264\0\0\0b\0\0\0!\0\0\0\6\0\0\0\1\0\0\0\1\1\1\1\1\235" + "\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\315\315\315\0""555\0\0\0\0\0\0\0\0\1\0" + "\0\0\3\0\0\0\17\0\0\0""1\0\0\0\204\0\0\0\322\0\0\0\361+-\0\375\244\252\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\244\252\0\377+-\0\375\0\0\0\361\0\0\0\323\0\0\0" + "\204\0\0\0""1\0\0\0\20\0\0\0\3\0\0\0\1\0\0\0\1""555\0\315\315\315\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0" + "\0\0\1\0\0\0\1\0\0\0\5\0\0\0\34\0\0\0P\0\0\0\234\0\0\0\332\0\0\0\364FH\0" + "\376\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH" + "\0\376\0\0\0\364\0\0\0\333\0\0\0\235\0\0\0Q\0\0\0\35\0\0\0\5\0\0\0\1\0\0" + "\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0)))\0\0" + "\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0%\0\0\0`\0\0\0\251\0\0\0\335\0\0\0\364" + "BD\0\376\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0\336\0\0\0\251\0\0\0a\0\0\0&" + "\0\0\0\14\0\0\0\3\0\0\0\1\0\0\0\1)))\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0" + "\0\1\0\0\0\1\0\0\0\3\0\0\0\17\0\0\0)\0\0\0d\0\0\0\251\0\0\0\333\0\0\0\362" + "$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\362\0\0\0\334\0\0\0\252\0\0\0" + "d\0\0\0)\0\0\0\17\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\321\321\321\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1\0" + "\0\0\4\0\0\0\20\0\0\0(\0\0\0\\\0\0\0\236\0\0\0\325\0\0\0\354\0\0\0\372FH" + "\0\377\225\232\0\377\340\350\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\225\232\0\377FH\0\377\0\0\0\372\0\0\0\354\0\0\0\325\0\0\0\236" + "\0\0\0]\0\0\0(\0\0\0\20\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\321\321\321" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\265\265\265\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0" + "\16\0\0\0\"\0\0\0I\0\0\0\205\0\0\0\275\0\0\0\337\0\0\0\360\0\0\0\374BD\0" + "\377\206\213\0\377\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\206" + "\213\0\377BD\0\377\0\0\0\374\0\0\0\360\0\0\0\340\0\0\0\276\0\0\0\205\0\0" + "\0J\0\0\0\"\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1===\0\265\265\265\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255\255" + "\255\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\11\0\0\0\27\0\0\0-\0\0" + "\0]\0\0\0\225\0\0\0\305\0\0\0\337\0\0\0\355\0\0\0\370\30\31\0\376QT\0\377" + "\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0\376\0\0\0\370" + "\0\0\0\355\0\0\0\340\0\0\0\306\0\0\0\225\0\0\0^\0\0\0-\0\0\0\30\0\0\0\11" + "\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1===\0\255\255\255\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\271\271\271\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0\33\0\0\0/\0\0\0Z\0\0\0\212\0\0\0\266\0\0" + "\0\326\0\0\0\344\0\0\0\355\0\0\0\365\0\0\0\374\40!\0\377FH\0\377hk\0\377" + "\206\213\0\377\240\246\0\377\267\275\0\377\311\321\0\377\330\341\0\377\344" + "\354\0\377\344\354\0\377\330\341\0\377\311\321\0\377\267\275\0\377\240\246" + "\0\377\206\213\0\377hk\0\377FH\0\377\40!\0\377\0\0\0\375\0\0\0\366\0\0\0" + "\355\0\0\0\344\0\0\0\326\0\0\0\266\0\0\0\212\0\0\0Z\0\0\0/\0\0\0\33\0\0\0" + "\16\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\271\271\271\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\3\0\0\0\15\0\0\0\31\0\0\0'\0\0\0@\0\0\0e\0\0\0\212\0" + "\0\0\255\0\0\0\312\0\0\0\332\0\0\0\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0" + "\0\365\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0" + "\366\0\0\0\362\0\0\0\355\0\0\0\350\0\0\0\342\0\0\0\332\0\0\0\313\0\0\0\255" + "\0\0\0\212\0\0\0e\0\0\0@\0\0\0'\0\0\0\31\0\0\0\16\0\0\0\4\0\0\0\2\0\0\0\1" + "\0\0\0\1\0\0\0\1\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\2\0\0\0\6\0\0\0\17\0\0\0\31\0\0\0!\0\0\0,\0\0\0C\0\0\0]\0\0\0u\0\0\0\212" + "\0\0\0\235\0\0\0\255\0\0\0\272\0\0\0\305\0\0\0\314\0\0\0\314\0\0\0\305\0" + "\0\0\272\0\0\0\255\0\0\0\235\0\0\0\212\0\0\0u\0\0\0]\0\0\0C\0\0\0,\0\0\0" + "\"\0\0\0\31\0\0\0\20\0\0\0\7\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\21\21" + "\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0qqq\0---\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\7\0\0\0\15\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!\0\0\0$\0\0\0'\0\0\0)" + "\0\0\0)\0\0\0'\0\0\0%\0\0\0!\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\16\0\0\0\10" + "\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1---\0qqq\0\271\271" + "\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\15\15" + "\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31\31\0\15\15\15\0\5" + "\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0)))\0===\0UUU\0qqq\0" + "\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0", +}; + diff --git a/samples/graphics/rsx_Basic/include/mesh.h b/samples/graphics/rsx_Basic/include/mesh.h new file mode 100644 index 00000000..63665494 --- /dev/null +++ b/samples/graphics/rsx_Basic/include/mesh.h @@ -0,0 +1,62 @@ +#ifndef __MESH_H__ +#define __MESH_H__ + +#include + +using namespace Vectormath::Aos; + +template< class T > +inline const T& min_(const T& a,const T& b) +{ + return a +inline const T& max_(const T& a,const T& b) +{ + return a +inline const T clamp(const T& val,const T& low,const T& high) +{ + return min_(max_(val,low),high); +} + +struct S3DVertex +{ + S3DVertex() {}; + S3DVertex(f32 x,f32 y,f32 z,f32 nx,f32 ny,f32 nz,f32 tu,f32 tv) + : pos(x,y,z),nrm(nx,ny,nz),u(tu),v(tv) {}; + + inline S3DVertex& operator=(const S3DVertex& other) + { + pos = other.pos; + nrm = other.nrm; + u = other.u; + v = other.v; + return *this; + } + + Vector3 pos; + Vector3 nrm; + + f32 u,v; +}; + +template< class T > +class CMeshBuffer +{ +public: + CMeshBuffer() : indices(NULL),cnt_indices(0),vertices(NULL),cnt_vertices(0) {}; + + u16 *indices; + u32 cnt_indices; + + S3DVertex *vertices; + u32 cnt_vertices; +}; + +typedef CMeshBuffer SMeshBuffer; + +#endif diff --git a/samples/graphics/rsx_Basic/include/rsxutil.h b/samples/graphics/rsx_Basic/include/rsxutil.h new file mode 100644 index 00000000..009bbb98 --- /dev/null +++ b/samples/graphics/rsx_Basic/include/rsxutil.h @@ -0,0 +1,36 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include +#include + +#define DEFUALT_CB_SIZE 0x80000 // 512Kb default command buffer size +#define HOST_STATE_CB_SIZE 0x10000 // 64Kb state command buffer size (used for resetting certain default states) +#define HOST_ADDR_ALIGNMENT (1024*1024) +#define HOSTBUFFER_SIZE (128*1024*1024) + +#define FRAME_BUFFER_COUNT 2 + +extern gcmContextData *context; + +extern u32 curr_fb; + +extern u32 display_width; +extern u32 display_height; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern u32 *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern u32 *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; + +void setRenderTarget(u32 index); +void init_screen(void *host_addr,u32 size); +void waitflip(); +void flip(); + +#endif diff --git a/samples/graphics/rsx_Basic/rsx_basic.png b/samples/graphics/rsx_Basic/rsx_basic.png new file mode 100644 index 00000000..680f4afa Binary files /dev/null and b/samples/graphics/rsx_Basic/rsx_basic.png differ diff --git a/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.fcg b/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.fcg new file mode 100644 index 00000000..c378a720 --- /dev/null +++ b/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.fcg @@ -0,0 +1,9 @@ + +void main +( + float4 color_in : COLOR, + out float4 color_out : COLOR +) +{ + color_out = color_in; +} \ No newline at end of file diff --git a/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.vcg b/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.vcg new file mode 100644 index 00000000..0e2e3570 --- /dev/null +++ b/samples/graphics/rsx_Basic/shaders/diffuse_specular_shader.vcg @@ -0,0 +1,16 @@ +void main(float4 position : POSITION, + float4 color : COLOR0, + float2 texcoord : TEXCOORD0, + + uniform float4x4 modelViewProj, + + out float4 oPosition : POSITION, + out float4 oColor : COLOR0, + out float2 oTexCoord : TEXCOORD0 + ) + { + oPosition = mul(modelViewProj, position); + oColor = color; + oTexCoord = texcoord; + } + \ No newline at end of file diff --git a/samples/graphics/rsx_Basic/source/main.cpp b/samples/graphics/rsx_Basic/source/main.cpp new file mode 100644 index 00000000..42d7a73c --- /dev/null +++ b/samples/graphics/rsx_Basic/source/main.cpp @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "acid.h" +#include "mesh.h" +#include "rsxutil.h" + +#include "diffuse_specular_shader_vpo.h" +#include "diffuse_specular_shader_fpo.h" + +typedef struct +{ + float x, y, z; + u32 rgba; +} Vertex_t; + +Vertex_t* vertex_buffer; +u32 VertexBufferOffset; + +u32 running = 0; + +u32 fp_offset; +u32 *fp_buffer; + + + +// vertex shader +rsxProgramConst *projMatrix; + +rsxProgramAttrib* mPosIndex = NULL; + +rsxProgramAttrib* mColIndex = NULL; + +u32 color_index; +u32 position_index; + + +void *vp_ucode = NULL; +rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; + +void *fp_ucode = NULL; +rsxFragmentProgram *fpo = (rsxFragmentProgram*)diffuse_specular_shader_fpo; + + +SYS_PROCESS_PARAM(1001, 0x100000); + +extern "C" { +static void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context,1); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + + +static void setDrawEnv() +{ + rsxSetColorMask(context,GCM_COLOR_MASK_B | + GCM_COLOR_MASK_G | + GCM_COLOR_MASK_R | + GCM_COLOR_MASK_A); + + rsxSetColorMaskMrt(context,0); + + u16 x,y,w,h; + f32 min, max; + f32 scale[4],offset[4]; + + x = 0; + y = 0; + w = display_width; + h = display_height; + min = 0.0f; + max = 1.0f; + scale[0] = w*0.5f; + scale[1] = h*-0.5f; + scale[2] = (max - min)*0.5f; + scale[3] = 0.0f; + offset[0] = x + w*0.5f; + offset[1] = y + h*0.5f; + offset[2] = (max + min)*0.5f; + offset[3] = 0.0f; + + rsxSetViewport(context,x, y, w, h, min, max, scale, offset); + rsxSetScissor(context,x,y,w,h); + + rsxSetDepthTestEnable(context,GCM_TRUE); + rsxSetDepthFunc(context,GCM_LESS); + rsxSetShadeModel(context,GCM_SHADE_MODEL_SMOOTH); + rsxSetDepthWriteEnable(context,1); + rsxSetFrontFace(context,GCM_FRONTFACE_CCW); +} + +void init_shader() +{ + u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + + projMatrix = rsxVertexProgramGetConst(vpo, "modelViewProj"); + + mPosIndex = rsxVertexProgramGetAttrib(vpo, "position"); + + mColIndex = rsxVertexProgramGetAttrib(vpo, "color"); + + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + + fp_buffer = (u32*)rsxMemalign(64,fpsize); + memcpy(fp_buffer,fp_ucode,fpsize); + + position_index = mPosIndex->index; + color_index = mColIndex->index; + + rsxAddressToOffset(fp_buffer,&fp_offset); + +} + +void drawFrame() +{ + u32 i, color; + + setDrawEnv(); + + // Screen clear color between red and blue + static float count = 0; + count += 0.1f; + unsigned char red = ((int)count) % 255; + unsigned char green = 32; + unsigned char blue = (255 - (int)count) % 255; + color = (blue << 0) | (green << 8) | (red << 16) | (255 << 24); + // Otherwise + //color = 0; // -> Black; + + rsxSetClearColor(context,color); + rsxSetClearDepthStencil(context,0xffffff00); + rsxClearSurface(context,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + rsxSetZControl(context,0,1,1); + + for(i=0;i<8;i++) + rsxSetViewportClip(context,i,display_width,display_height); + + Matrix4 tempMatrix = transpose(Matrix4::identity()); + + rsxAddressToOffset((void*)vertex_buffer, &VertexBufferOffset); + + rsxBindVertexArrayAttrib(context, position_index, 0, VertexBufferOffset, sizeof(Vertex_t), 3, GCM_VERTEX_DATA_TYPE_F32, GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context, color_index, 0, VertexBufferOffset + sizeof(float) * 3, sizeof(Vertex_t), 3, GCM_VERTEX_DATA_TYPE_U8, GCM_LOCATION_RSX); + + rsxLoadVertexProgram(context, vpo, vp_ucode); + rsxSetVertexProgramParameter(context, vpo, projMatrix, (float*)&tempMatrix); + rsxLoadFragmentProgramLocation(context, fpo, fp_offset, GCM_LOCATION_RSX); + rsxDrawVertexArray(context, GCM_TYPE_TRIANGLES, 0, 3); + +} + +int main(int argc,const char *argv[]) +{ + padInfo padinfo; + padData paddata; + void *host_addr = memalign(HOST_ADDR_ALIGNMENT,HOSTBUFFER_SIZE); + + printf("rsxtest started...\n"); + + init_screen(host_addr,HOSTBUFFER_SIZE); + ioPadInit(7); + + //Create Triangle + void* ret = rsxMemalign(128, sizeof(Vertex_t) * 3); + vertex_buffer = (Vertex_t*)ret; + vertex_buffer[0].x = -1.0f; + vertex_buffer[0].y = -1.0f; + vertex_buffer[0].z = -1.0f; + vertex_buffer[0].rgba = 0x00ff0000; + + vertex_buffer[1].x = 1.0f; + vertex_buffer[1].y = -1.0f; + vertex_buffer[1].z = -1.0f; + vertex_buffer[1].rgba = 0x0000ff00; + + vertex_buffer[2].x = 0.0f; + vertex_buffer[2].y = 1.0f; + vertex_buffer[2].z = -1.0f; + vertex_buffer[2].rgba = 0xff000000; + + init_shader(); + + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + setDrawEnv(); + setRenderTarget(curr_fb); + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if(paddata.BTN_CROSS) + goto done; + } + + } + + drawFrame(); + + + flip(); + } + +done: + printf("rsxtest done...\n"); + program_exit_callback(); + return 0; +} diff --git a/samples/graphics/rsx_Basic/source/rsxutil.cpp b/samples/graphics/rsx_Basic/source/rsxutil.cpp new file mode 100644 index 00000000..b86f41af --- /dev/null +++ b/samples/graphics/rsx_Basic/source/rsxutil.cpp @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include + +#include + + +#include "rsxutil.h" + +#define GCM_LABEL_INDEX 255 + +videoResolution vResolution; +gcmContextData *context = NULL; + +u32 curr_fb = 0; +u32 first_fb = 1; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +u32 *depth_buffer; + +u32 color_pitch; +u32 color_offset[FRAME_BUFFER_COUNT]; +u32 *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); + +static u32 sLabelVal = 1; + + +static void waitFinish() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(context); + + while(*(vu32*)gcmGetLabelAddress(GCM_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitFinish(); +} + +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + (u32)vResolution.width*4 + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + +void setRenderTarget(u32 index) +{ + gcmSurface sf; + + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; + sf.colorLocation[0] = GCM_LOCATION_RSX; + sf.colorOffset[0] = color_offset[index]; + sf.colorPitch[0] = color_pitch; + + sf.colorLocation[1] = GCM_LOCATION_RSX; + sf.colorLocation[2] = GCM_LOCATION_RSX; + sf.colorLocation[3] = GCM_LOCATION_RSX; + sf.colorOffset[1] = 0; + sf.colorOffset[2] = 0; + sf.colorOffset[3] = 0; + sf.colorPitch[1] = 64; + sf.colorPitch[2] = 64; + sf.colorPitch[3] = 64; + + sf.depthFormat = GCM_SURFACE_ZETA_Z24S8; + sf.depthLocation = GCM_LOCATION_RSX; + sf.depthOffset = depth_offset; + sf.depthPitch = depth_pitch; + + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; + + sf.width = display_width; + sf.height = display_height; + sf.x = 0; + sf.y = 0; + + rsxSetSurface(context,&sf); +} + +void init_screen(void *host_addr,u32 size) +{ + u32 zs_depth = 4; + u32 color_depth = 4; + + rsxInit(&context,DEFUALT_CB_SIZE,size,host_addr); + + initVideoConfiguration(); + + waitRSXIdle(); + + gcmSetFlipMode(GCM_FLIP_VSYNC); + + color_pitch = display_width*color_depth; + depth_pitch = display_width*zs_depth; + + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + color_buffer[i] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + rsxAddressToOffset(color_buffer[i],&color_offset[i]); + gcmSetDisplayBuffer(i,color_offset[i],color_pitch,display_width,display_height); + } + + depth_buffer = (u32*)rsxMemalign(64, display_height*depth_pitch); + rsxAddressToOffset(depth_buffer,&depth_offset); + +} + +void waitflip() +{ + while(gcmGetFlipStatus()!=0) + usleep(200); + gcmResetFlipStatus(); +} + +void flip() +{ + if(!first_fb) waitflip(); + else gcmResetFlipStatus(); + + gcmSetFlip(context,curr_fb); + rsxFlushBuffer(context); + + gcmSetWaitFlip(context); + + curr_fb ^= 1; + setRenderTarget(curr_fb); + + first_fb = 0; +} diff --git a/samples/graphics/rsx_Basic_Cube/Makefile b/samples/graphics/rsx_Basic_Cube/Makefile new file mode 100644 index 00000000..c76ea9e9 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/Makefile @@ -0,0 +1,164 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source ../debugfont_renderer/source +DATA := data +SHADERS := shaders ../debugfont_renderer/shaders +INCLUDES := include ../debugfont_renderer/include + +TITLE := RSX Test - PSL1GHT +APPID := RSX00003 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lsimdmath -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm -lsysmodule -lpngdec + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(SHADERS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +VCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.vcg))) +FCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.fcg))) + +VPOFILES := $(VCGFILES:.vcg=.vpo) +FPOFILES := $(FCGFILES:.fcg=.fpo) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(addsuffix .o,$(VPOFILES)) \ + $(addsuffix .o,$(FPOFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(OUTPUT).fake.self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.vpo.o : %.vpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.fpo.o : %.fpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/rsx_Basic_Cube/Readme.md b/samples/graphics/rsx_Basic_Cube/Readme.md new file mode 100644 index 00000000..588a40dd --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/Readme.md @@ -0,0 +1,3 @@ +A basic cube example to use a texture on a cube and to rotate it. + +![RSX basic cube example](rsx_basic_cube.png?raw=true) diff --git a/samples/graphics/rsx_Basic_Cube/data/Stone_Texture_png.bin b/samples/graphics/rsx_Basic_Cube/data/Stone_Texture_png.bin new file mode 100644 index 00000000..26777bb1 Binary files /dev/null and b/samples/graphics/rsx_Basic_Cube/data/Stone_Texture_png.bin differ diff --git a/samples/graphics/rsx_Basic_Cube/include/acid.h b/samples/graphics/rsx_Basic_Cube/include/acid.h new file mode 100644 index 00000000..d1643518 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/include/acid.h @@ -0,0 +1,2939 @@ +/* GIMP RGBA C-Source image dump (acid.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +} acid = { + 128, 128, 4, + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\335\335\335\0\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31" + "\31\0\15\15\15\0\5\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0))" + ")\0===\0UUU\0qqq\0\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\345\345\345\0\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\15\15\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0qqq\0---\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\15\0\0\0" + "\23\0\0\0\30\0\0\0\35\0\0\0!\0\0\0$\0\0\0&\0\0\0(\0\0\0(\0\0\0'\0\0\0$\0" + "\0\0!\0\0\0\35\0\0\0\31\0\0\0\23\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0---\0qqq\0\271\271\271\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\17\0\0\0\30\0\0\0\40\0\0\0+\0\0\0B\0" + "\0\0\\\0\0\0t\0\0\0\211\0\0\0\234\0\0\0\254\0\0\0\271\0\0\0\304\0\0\0\313" + "\0\0\0\313\0\0\0\304\0\0\0\271\0\0\0\254\0\0\0\234\0\0\0\211\0\0\0t\0\0\0" + "\\\0\0\0B\0\0\0+\0\0\0!\0\0\0\30\0\0\0\17\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\21\21\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\2\0\0\0\14\0\0\0\30\0\0\0&\0\0\0?\0\0\0d\0\0\0\211\0\0\0\254\0\0\0\311" + "\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\354\0\0\0\361\0\0\0\365\0\0\0\370\0" + "\0\0\373\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\371\0\0\0\365\0\0\0\361\0\0" + "\0\355\0\0\0\347\0\0\0\341\0\0\0\331\0\0\0\312\0\0\0\254\0\0\0\211\0\0\0" + "d\0\0\0?\0\0\0&\0\0\0\30\0\0\0\15\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0QQQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0\33\0\0" + "\0.\0\0\0Y\0\0\0\211\0\0\0\265\0\0\0\325\0\0\0\343\0\0\0\354\0\0\0\365\0" + "\0\0\374\40!\0\377FH\0\377hk\0\377\206\213\0\377\240\246\0\377\267\275\0" + "\377\311\321\0\377\330\341\0\377\344\354\0\377\344\354\0\377\330\341\0\377" + "\311\321\0\377\267\275\0\377\240\246\0\377\206\213\0\377hk\0\377FH\0\377" + "\40!\0\377\0\0\0\375\0\0\0\365\0\0\0\355\0\0\0\343\0\0\0\326\0\0\0\266\0" + "\0\0\211\0\0\0Z\0\0\0/\0\0\0\33\0\0\0\16\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0" + "\0\0\0\0QQQ\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\255\255\255\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0" + "\27\0\0\0-\0\0\0]\0\0\0\224\0\0\0\304\0\0\0\336\0\0\0\354\0\0\0\367\30\31" + "\0\376QT\0\377\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0" + "\376\0\0\0\367\0\0\0\354\0\0\0\337\0\0\0\305\0\0\0\224\0\0\0]\0\0\0-\0\0" + "\0\30\0\0\0\11\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0===\0\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265" + "\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\15\0\0\0!\0\0\0H\0\0\0\204" + "\0\0\0\274\0\0\0\336\0\0\0\357\0\0\0\373BD\0\377\206\213\0\377\306\315\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\306\315\0\377\206\213\0\377BD\0\377\0\0\0\373" + "\0\0\0\357\0\0\0\337\0\0\0\275\0\0\0\204\0\0\0I\0\0\0!\0\0\0\15\0\0\0\3\0" + "\0\0\1\0\0\0\0\0\0\0\0===\0\265\265\265\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0QQ" + "Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0'\0\0\0[\0\0\0\236\0\0" + "\0\324\0\0\0\353\0\0\0\371FH\0\377\225\232\0\377\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\340\350\0\377\225\232\0\377FH\0\377\0\0\0\371\0" + "\0\0\353\0\0\0\324\0\0\0\236\0\0\0\\\0\0\0'\0\0\0\17\0\0\0\3\0\0\0\1\0\0" + "\0\0\0\0\0\0QQQ\0\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0(\0\0\0c\0\0\0\250" + "\0\0\0\332\0\0\0\361$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\361\0\0\0" + "\333\0\0\0\251\0\0\0c\0\0\0(\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0yyy" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0)))\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\0\0\0$\0\0\0_" + "\0\0\0\250\0\0\0\334\0\0\0\364BD\0\376\244\252\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0" + "\335\0\0\0\250\0\0\0`\0\0\0%\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\0)))\0\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\4\0\0\0\34\0\0\0O\0\0\0\234\0\0\0\332\0\0\0\364FH\0\376\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH\0\376\0\0\0\364\0" + "\0\0\332\0\0\0\234\0\0\0P\0\0\0\34\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0qqq\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315" + "\0""555\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0""0\0\0\0\203\0\0\0\321\0" + "\0\0\360+-\0\375\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377+-\0\375" + "\0\0\0\360\0\0\0\322\0\0\0\203\0\0\0""1\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0" + """555\0\315\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\4\0\0\0\40\0\0\0`\0\0\0\262\0\0\0\346\0\0\0\374~\203\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\374\0\0\0\347\0\0\0\263\0\0\0a\0\0\0\40\0\0\0\5\0\0" + "\0\1\0\0\0\0\1\1\1\0\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0" + "\0/\0\0\0\207\0\0\0\326\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\311\321\0\377FH\0\376\0\0\0\366\0\0\0\327\0\0\0\207\0\0\0" + """0\0\0\0\14\0\0\0\2\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375" + "\375\375\0UUU\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\30\0\0\0S\0\0\0\252\0\0\0\345" + "\0\0\0\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\374\0\0\0\346" + "\0\0\0\253\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\0UUU\0\375\375\375\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0==" + "=\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\"\0\0\0q\0\0\0\316\0\0\0\363/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\364\0\0\0\316\0\0\0q\0\0\0\"\0\0\0\5\0\0\0\1\0\0\0\0===\0\351\351" + "\351\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\0\0\0\0\1" + "\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\\`\0\377\0\0\0\373\0\0\0\332\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1\0\0" + "\0\1---\0\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\331\331\331\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0""2\0\0\0\225\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\342\0\0\0" + "\226\0\0\0""2\0\0\0\11\0\0\0\1\0\0\0\1%%%\0\331\331\331\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\335\335\335\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0?\0\0\0\243\0\0\0\350\2\2\0\375\240\246\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377" + "\2\2\0\375\0\0\0\350\0\0\0\244\0\0\0@\0\0\0\15\0\0\0\2\0\0\0\1%%%\0\335\335" + "\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\0\0\0\0\1\0\0\0\16" + "\0\0\0H\0\0\0\257\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\355\0\0\0\257\0\0\0H\0\0\0" + "\17\0\0\0\2\0\0\0\1---\0\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\375\375\375\0===\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0H\0\0\0\264\0\0\0\360\40!\0\376\306\315\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\40!\0\376\0\0\0" + "\360\0\0\0\265\0\0\0I\0\0\0\15\0\0\0\1\0\0\0\1===\0\375\375\375\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0?\0\0\0\257\0\0\0\360$%\0\376\315\325\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\315\325" + "\0\377$%\0\377\0\0\0\360\0\0\0\257\0\0\0@\0\0\0\11\0\0\0\1\0\0\0\1UUU\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0""2" + "\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\355\0\0\0\244\0\0\0""2\0" + "\0\0\6\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\0\0\0\0\0\0\0\0\0\0" + "\0\4\0\0\0*\0\0\0\225\0\0\0\350\25\25\0\376\306\315\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\25" + "\25\0\376\0\0\0\350\0\0\0\226\0\0\0*\0\0\0\5\0\0\0\1\0\0\0\0\235\235\235" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315\0" + "\1\1\1\0\0\0\0\0\0\0\0\3\0\0\0\"\0\0\0\205\0\0\0\342\2\2\0\375\267\275\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\2\2\0\375\0\0\0\342\0\0\0" + "\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\0\315\315\315\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374" + "\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377\13\14\0\377UX\0\377" + "\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0S\0\0\0\316\0\0\0\373\202\207" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\310\317\0\3779<\0\377\0\0\0\3779<\0\377\310\317\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\306\315\0\377!\"\0\377\0\0\0\377\0\0\0\377\4\4\0\377PT\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\316\0\0\0S\0\0\0\14\0\0\0\1\0\0\0\0qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\0\0\0\0\4\0\0\0/\0\0\0\253\0\0\0\364\\`\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377/2\0\377\0\0\0\377\0\0\0\377\0\0\0\377/2\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0" + "\253\0\0\0""0\0\0\0\5\0\0\0\1\0\0\0\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0)))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0" + "\0\207\0\0\0\345/1\0\376\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\207\215\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\357\370\0\377/1\0\376\0\0\0\346" + "\0\0\0\207\0\0\0\40\0\0\0\3\0\0\0\1)))\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0`\0\0\0\326\0\0\0\374\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\5\5\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\374\0\0\0" + "\327\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\0yyy\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0" + "\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0" + "\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\0\321\321\321\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0" + "\0\0\0\0\0\0\2\0\0\0\34\0\0\0\203\0\0\0\346FH\0\376\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\376" + "\0\0\0\347\0\0\0\204\0\0\0\34\0\0\0\2\0\0\0\1QQQ\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0\0\0\0" + "\0\0\0\12\0\0\0O\0\0\0\321\0\0\0\374\311\321\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321" + "\0\377\0\0\0\374\0\0\0\322\0\0\0P\0\0\0\13\0\0\0\1\0\0\0\0\265\265\265\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0" + "\0%\0\0\0\234\0\0\0\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\361\0\0\0\234\0\0\0%\0\0\0\3\0\0\0\1===\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0_\0" + "\0\0\332+-\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377+-\0\375\0\0\0\332\0\0\0`\0\0\0\17\0\0\0\1\0\0\0\0\255\255" + "\255\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0(\0\0\0\250\0\0\0" + "\363\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\244\252\0\377\0\0\0\364\0\0\0\250\0\0\0)\0\0\0\3\0\0\0\1=" + "==\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0c\0\0\0\334FH" + "\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\17\0\0\0" + "\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'\0\0\0\251\0\0\0\363\267\275" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0" + "(\0\0\0\3\0\0\0\1QQQ\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377BD\0\376\0\0\0\333\0\0\0\\" + "\0\0\0\16\0\0\0\1\0\0\0\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\2\0\0\0!\0\0\0\235\0\0\0\361\244\252\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\361\0" + "\0\0\236\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\35\35\35\0\0\0\0\0\0\0\0\10\0\0\0H\0\0\0\324$%\0\375\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377$%\0\375\0" + "\0\0\325\0\0\0I\0\0\0\11\0\0\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0\203\0\0\0\353~\203\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203" + "\0\377\0\0\0\353\0\0\0\204\0\0\0\27\0\0\0\1\0\0\0\0\265\265\265\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\325\335\0\377\0\0\0\371\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\336FH\0\376\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0]\0\0\0\16\0\0\0\1\21\21\21\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0\0\0\0\0\0\0\0\0\0\0\0\32\0\0\0\223\0\0\0\357\225\232\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\357\0\0\0\224\0\0\0\33\0" + "\0\0\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\340\350\0\377\0\0\0\373\0\0\0\305\0\0\0" + "/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0---\0\0\0\0\0\0\0\0\14\0\0\0Y\0\0\0\336BD\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\337\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0" + "\0\0\211\0\0\0\30\0\0\0\1\0\0\0\0\345\345\345\0\377\377\377\0\377\377\377" + "\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\265\0\0\0\367\306\315\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377" + "\0\0\0\367\0\0\0\266\0\0\0&\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377\377\377\0\377\377" + "\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343QT\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT" + "\0\377\0\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0" + "\15\15\15\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15\15\15\0\377\377\377" + "\0\335\335\335\0\0\0\0\0\0\0\0\0\0\0\0\40\0\0\0\254\0\0\0\365\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0\0!\0\0\0\1\0\0\0\0\335" + "\335\335\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0+\0\0\0\311\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\210\215\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\7\7\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\344\354\0\377\0\0\0\374\0\0\0\312\0\0\0,\0\0\0\2" + "\0\0\0\1\265\265\265\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0B\0\0\0\331\40" + "!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\20\21\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\40!\0\377\0\0\0" + "\332\0\0\0B\0\0\0\7\0\0\0\1\221\221\221\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0" + "\0\0\341FH\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\37702\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\37702\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377!\"\0\377\0\0" + "\0\377\0\0\0\377\4\4\0\377PS\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0\0\0\342\0" + "\0\0]\0\0\0\15\0\0\0\1qqq\0UUU\0\0\0\0\0\0\0\0\23\0\0\0t\0\0\0\347hk\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\3779<\0\377\0" + "\0\0\3779<\0\377\310\317\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377" + "\13\14\0\377UX\0\377\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0" + "\0\0u\0\0\0\23\0\0\0\1UUU\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206" + "\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===" + "\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0\361\240\246\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246" + "\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0\1)))\0\31\31\31\0\0\0\0\0\0\0\0" + "\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0\15\15\15\0\0\0\0\0\0\0\0$\0\0\0\271\0" + "\0\0\370\311\321\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\311\321\0\377\0\0\0\371\0\0\0\272\0\0\0" + "$\0\0\0\1\15\15\15\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\1\1\1" + "\0\0\0\0\0\0\0\0(\0\0\0\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\313\0\0\0)\0\0\0\1\1\1\1\0\1\1\1\0\0\0\0\0\0\0\0(\0\0\0" + "\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\344\354\0\377\0\0\0\375\0\0\0\313\0\0" + "\0)\0\0\0\1\1\1\1\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\15\15" + "\15\0\0\0\0\0\0\0\0$\0\0\0\271\0\0\0\370\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321\0" + "\377\0\0\0\371\0\0\0\272\0\0\0$\0\0\0\1\15\15\15\0\31\31\31\0\0\0\0\0\0\0" + "\0\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0" + "\361\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\240\246\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0" + "\1)))\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206" + "\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===\0UUU\0\0\0\0\0\0\0\0\23" + "\0\0\0t\0\0\0\347hk\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0\0\0u\0\0\0\23\0\0\0" + "\1UUU\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\341FH\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0" + "\0\0\342\0\0\0]\0\0\0\15\0\0\0\1qqq\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0" + "B\0\0\0\331\40!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\40!\0\377\0\0\0\332\0\0\0C\0\0\0\7\0\0\0\1\221" + "\221\221\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0,\0\0\0\312\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\312\0\0\0,\0\0\0\2\0\0\0\1\265\265\265\0\335\335\335\0\0" + "\0\0\0\0\0\0\1\0\0\0!\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0" + "\0\"\0\0\0\1\0\0\0\1\335\335\335\0\377\377\377\0\15\15\15\0\0\0\0\0\0\0\0" + "\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15" + "\15\15\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343" + "QT\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT\0\377\0" + "\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0qqq\0\0" + "\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377" + "\377\377\0\377\377\377\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\266\0" + "\0\0\367\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\335\345\0\377\261\270\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\0\0\0\370" + "\0\0\0\266\0\0\0'\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377\377\377" + "\0\345\345\345\0\0\0\0\0\0\0\0\1\0\0\0\31\0\0\0\212\0\0\0\354\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\322\332\0\377\36" + "\37\0\377\10\10\0\377\265\273\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\316\326\0\377\230\235\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\0" + "\0\0\1\345\345\345\0\377\377\377\0\377\377\377\0\377\377\377\0---\0\0\0\0" + "\0\0\0\0\14\0\0\0Z\0\0\0\337BD\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\1\1\0\377\201\206\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0\377\17" + "\20\0\377\2\2\0\377\224\231\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\340\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377SV\0\377\353\364\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377w{\0\377\1\1\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377;>\0\377<>\0\377<>\0\377\303\312\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\0\0\0\373\0\0\0\305\0\0\0/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\1" + "\0\0\0\33\0\0\0\224\0\0\0\357\225\232\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\26\26\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377.0\0\377" + "\330\340\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\345\355\0\377?A" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\1\1\0\377\310\320\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\360\0\0\0" + "\225\0\0\0\34\0\0\0\1\0\0\0\1\271\271\271\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0" + "]\0\0\0\337FH\0\376\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\257\266\0\377\4\4\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\16\17\0\377\265\273" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\277\306\0\377\23\24\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\0\377\226\233\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0^\0\0\0\16\0\0\0\1\21\21" + "\21\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\300\307\0\377\30\31\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377z\177\0\377\355\366" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377pt\0\377\2\2\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2" + "\0\377\235\243\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\325\335\0\377\0\0\0\371" + "\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\1\0\0\0\27\0\0\0\204\0\0\0\353~\203\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\330\341\0\377&'\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\25\25\0\377\277\306\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\377" + "-/\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\25\25\0\377\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377~\203\0\377\0\0\0\354\0\0\0\205\0\0\0\30\0\0\0\1\0\0\0\1\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\35\35\35\0\0\0\0\0\0\0\0\11\0\0\0I\0\0\0\324" + "$%\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\350\360\0\377EG\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\2\2\0\377mq\0\377\352\363\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\342\352\0" + "\377fi\0\377\2\2\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377*,\0\377\333\344\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377$%\0\375\0\0\0\325\0\0\0J\0\0\0\11\0\0" + "\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\2" + "\0\0\0!\0\0\0\236\0\0\0\361\244\252\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377tx\0\377\1\1\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\36\0\377\235\243\0" + "\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\220" + "\225\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377gj\0\377\353\364\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\362\0" + "\0\0\237\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\1\0\0\0\16\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0" + "\377\13\14\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377-/\0\377\273\302\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355\366\0\377\177\204" + "\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\11\12\0\377\246\254\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "BD\0\376\0\0\0\333\0\0\0]\0\0\0\17\0\0\0\1\0\0\0\1\331\331\331\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'" + "\0\0\0\251\0\0\0\363\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\346\356\0\377HK\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377=?\0\377\247\255\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377\206\213\0\377" + "\34\35\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377/1\0\377\325\335\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0(\0\0\0\3\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0" + "\0\0\0\0\0\0\1\0\0\0\20\0\0\0d\0\0\0\335FH\0\375\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\211\217\0\377\10\11\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\14\15\0\377qu\0\377" + "\343\353\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\356\367\0\377\254\263\0\377hl\0\377\5\5\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\16\17\0\377\231\237\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\20\0\0\0\1\0\0\0\1\271\271\271" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0)\0\0\0\251\0\0\0\363\244\252\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\346\356\0\377fi\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\4\4\0\377BD\0\377\206\213\0\377\301\310\0\377\354\365\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340\350\0\377\230\235\0" + "\377^b\0\377\25\25\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377Z^" + "\0\377\335\345\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377" + "\0\0\0\364\0\0\0\251\0\0\0*\0\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255" + "\255\255\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0`\0\0\0\332+-\0\375\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\254\263\0\377\25\25\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\13\0\377;>\0\377UX\0" + "\377lp\0\377x|\0\377x|\0\377x|\0\377bf\0\377HK\0\377\6\6\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37713\0\377\275\304" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "+-\0\375\0\0\0\332\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\1\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0%\0\0\0\234\0\0\0" + "\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\216\223\0\377\16\17\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + ",.\0\377\247\255\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0\361\0\0\0\235\0\0\0%\0" + "\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265" + "\265\265\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0P\0\0\0\322\0\0\0\374\311\321\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355" + "\366\0\377\213\221\0\377\17\20\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\37724\0\377\246\254\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\311\321\0\377\0\0\0\374\0\0\0\323\0\0\0Q\0\0\0\14\0\0\0\1\0\0\0\1" + "\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0\34\0\0\0\204\0\0\0\347FH\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\356\367\0\377\235\243\0\377(*\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\5\5\0" + "\377hl\0\377\270\276\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377FH\0\377\0\0\0\347\0\0\0\204\0\0\0\35\0\0\0\2\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321" + "\321\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\320\330\0\377\\`\0\377\7" + "\7\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\3778:\0\377\226\233\0" + "\377\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\206\213\0\377\0\0\0\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\1" + "\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0a\0\0\0" + "\327\0\0\0\374\276\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\357\370\0\377\245\253\0\377w{\0\377:=\0\377\3\3\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377*,\0\377dh\0\377\217\224\0\377\350" + "\361\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\375\0\0\0\330\0\0\0b\0\0" + "\0\20\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + ")))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0\0\207\0\0\0\346/1\0\376\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\357\370\0\377\305\314\0\377\247\255\0\377" + "\212\220\0\377x}\0\377x}\0\377x}\0\377x}\0\377{\200\0\377\240\246\0\377\270" + "\276\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377/1\0\376\0\0\0\347\0\0\0\210\0\0\0!\0\0\0\3\0\0\0" + "\1)))\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""0\0\0\0\253\0\0\0\364\\`\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0\254\0\0\0""1" + "\0\0\0\6\0\0\0\1\0\0\0\1\265\265\265\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\1\0\0\0\14\0\0" + "\0T\0\0\0\317\0\0\0\373\202\207\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\317\0\0\0T\0\0\0\15\0\0\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374\240\246\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\315\315\315\0\1\1\1\0\0\0\0\1\0\0\0\4\0\0\0\"\0" + "\0\0\205\0\0\0\342\2\2\0\375\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267" + "\275\0\377\2\2\0\375\0\0\0\342\0\0\0\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\1\315" + "\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235" + "\235\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0+\0\0\0\226\0\0\0\350\25\25\0\376\306" + "\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\306\315\0\377\25\25\0\376\0\0\0\351\0\0\0\226\0\0\0+\0\0\0\6\0" + "\0\0\1\0\0\0\1\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0" + """2\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\356\0\0\0\245\0\0\0""3\0" + "\0\0\7\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0" + "\0\0\0\0\0\0\1\0\0\0\11\0\0\0@\0\0\0\260\0\0\0\360$%\0\376\315\325\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377$%\0\377\0\0\0\361\0\0\0\260\0\0\0A\0\0\0" + "\12\0\0\0\1\0\0\0\1UUU\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\375\375\375\0===\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0H\0\0\0\264\0\0\0\360" + "\40!\0\376\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\306\315\0\377\40!\0\376\0\0\0\361\0\0\0\265\0\0\0I\0\0\0\16" + "\0\0\0\2\0\0\0\1===\1\375\375\375\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\1\0\0\0\2\0\0\0\17" + "\0\0\0I\0\0\0\260\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\356\0\0\0\260\0\0\0I\0\0\0" + "\20\0\0\0\2\0\0\0\1---\1\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "%%%\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0@\0\0\0\244\0\0\0\350\2\2\0\375\240\246" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\240\246\0\377\2\2\0\375\0\0\0\351\0\0\0\245\0\0\0@\0\0\0\16" + "\0\0\0\2\0\0\0\1%%%\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\331\331\331\0%%%\0\0\0\0\1\0\0\0\2\0\0\0\12\0\0\0""2\0\0\0\226" + "\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\343\0\0\0\226\0\0\0""3\0\0\0" + "\12\0\0\0\2\0\0\0\1%%%\1\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\1\0\0" + "\0\1\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357" + "\370\0\377\\`\0\377\0\0\0\373\0\0\0\333\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1" + "\0\0\0\1---\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0" + "===\0\0\0\0\1\0\0\0\1\0\0\0\5\0\0\0#\0\0\0r\0\0\0\317\0\0\0\364/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\365\0\0\0\317\0\0\0r\0\0\0#\0\0\0\6\0\0\0\1\0\0\0\1===\1\351\351\351" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375\375\375" + "\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0S\0\0\0\253\0\0\0\346\0\0\0" + "\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\375\0\0\0\347\0\0\0" + "\254\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\1UUU\0\375\375\375\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0/\0\0\0\210\0" + "\0\0\327\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\311\321\0\377FH\0\377\0\0\0\367\0\0\0\330\0\0\0\210\0\0\0""0\0\0\0\15\0" + "\0\0\3\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\5\0" + "\0\0!\0\0\0a\0\0\0\263\0\0\0\347\0\0\0\374~\203\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0" + "\374\0\0\0\347\0\0\0\264\0\0\0b\0\0\0!\0\0\0\6\0\0\0\1\0\0\0\1\1\1\1\1\235" + "\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\315\315\315\0""555\0\0\0\0\0\0\0\0\1\0" + "\0\0\3\0\0\0\17\0\0\0""1\0\0\0\204\0\0\0\322\0\0\0\361+-\0\375\244\252\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\244\252\0\377+-\0\375\0\0\0\361\0\0\0\323\0\0\0" + "\204\0\0\0""1\0\0\0\20\0\0\0\3\0\0\0\1\0\0\0\1""555\0\315\315\315\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0" + "\0\0\1\0\0\0\1\0\0\0\5\0\0\0\34\0\0\0P\0\0\0\234\0\0\0\332\0\0\0\364FH\0" + "\376\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH" + "\0\376\0\0\0\364\0\0\0\333\0\0\0\235\0\0\0Q\0\0\0\35\0\0\0\5\0\0\0\1\0\0" + "\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0)))\0\0" + "\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0%\0\0\0`\0\0\0\251\0\0\0\335\0\0\0\364" + "BD\0\376\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0\336\0\0\0\251\0\0\0a\0\0\0&" + "\0\0\0\14\0\0\0\3\0\0\0\1\0\0\0\1)))\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0" + "\0\1\0\0\0\1\0\0\0\3\0\0\0\17\0\0\0)\0\0\0d\0\0\0\251\0\0\0\333\0\0\0\362" + "$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\362\0\0\0\334\0\0\0\252\0\0\0" + "d\0\0\0)\0\0\0\17\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\321\321\321\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1\0" + "\0\0\4\0\0\0\20\0\0\0(\0\0\0\\\0\0\0\236\0\0\0\325\0\0\0\354\0\0\0\372FH" + "\0\377\225\232\0\377\340\350\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\225\232\0\377FH\0\377\0\0\0\372\0\0\0\354\0\0\0\325\0\0\0\236" + "\0\0\0]\0\0\0(\0\0\0\20\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\321\321\321" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\265\265\265\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0" + "\16\0\0\0\"\0\0\0I\0\0\0\205\0\0\0\275\0\0\0\337\0\0\0\360\0\0\0\374BD\0" + "\377\206\213\0\377\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\206" + "\213\0\377BD\0\377\0\0\0\374\0\0\0\360\0\0\0\340\0\0\0\276\0\0\0\205\0\0" + "\0J\0\0\0\"\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1===\0\265\265\265\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255\255" + "\255\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\11\0\0\0\27\0\0\0-\0\0" + "\0]\0\0\0\225\0\0\0\305\0\0\0\337\0\0\0\355\0\0\0\370\30\31\0\376QT\0\377" + "\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0\376\0\0\0\370" + "\0\0\0\355\0\0\0\340\0\0\0\306\0\0\0\225\0\0\0^\0\0\0-\0\0\0\30\0\0\0\11" + "\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1===\0\255\255\255\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\271\271\271\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0\33\0\0\0/\0\0\0Z\0\0\0\212\0\0\0\266\0\0" + "\0\326\0\0\0\344\0\0\0\355\0\0\0\365\0\0\0\374\40!\0\377FH\0\377hk\0\377" + "\206\213\0\377\240\246\0\377\267\275\0\377\311\321\0\377\330\341\0\377\344" + "\354\0\377\344\354\0\377\330\341\0\377\311\321\0\377\267\275\0\377\240\246" + "\0\377\206\213\0\377hk\0\377FH\0\377\40!\0\377\0\0\0\375\0\0\0\366\0\0\0" + "\355\0\0\0\344\0\0\0\326\0\0\0\266\0\0\0\212\0\0\0Z\0\0\0/\0\0\0\33\0\0\0" + "\16\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\271\271\271\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\3\0\0\0\15\0\0\0\31\0\0\0'\0\0\0@\0\0\0e\0\0\0\212\0" + "\0\0\255\0\0\0\312\0\0\0\332\0\0\0\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0" + "\0\365\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0" + "\366\0\0\0\362\0\0\0\355\0\0\0\350\0\0\0\342\0\0\0\332\0\0\0\313\0\0\0\255" + "\0\0\0\212\0\0\0e\0\0\0@\0\0\0'\0\0\0\31\0\0\0\16\0\0\0\4\0\0\0\2\0\0\0\1" + "\0\0\0\1\0\0\0\1\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\2\0\0\0\6\0\0\0\17\0\0\0\31\0\0\0!\0\0\0,\0\0\0C\0\0\0]\0\0\0u\0\0\0\212" + "\0\0\0\235\0\0\0\255\0\0\0\272\0\0\0\305\0\0\0\314\0\0\0\314\0\0\0\305\0" + "\0\0\272\0\0\0\255\0\0\0\235\0\0\0\212\0\0\0u\0\0\0]\0\0\0C\0\0\0,\0\0\0" + "\"\0\0\0\31\0\0\0\20\0\0\0\7\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\21\21" + "\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0qqq\0---\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\7\0\0\0\15\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!\0\0\0$\0\0\0'\0\0\0)" + "\0\0\0)\0\0\0'\0\0\0%\0\0\0!\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\16\0\0\0\10" + "\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1---\0qqq\0\271\271" + "\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\15\15" + "\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31\31\0\15\15\15\0\5" + "\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0)))\0===\0UUU\0qqq\0" + "\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0", +}; + diff --git a/samples/graphics/rsx_Basic_Cube/include/mesh.h b/samples/graphics/rsx_Basic_Cube/include/mesh.h new file mode 100644 index 00000000..63665494 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/include/mesh.h @@ -0,0 +1,62 @@ +#ifndef __MESH_H__ +#define __MESH_H__ + +#include + +using namespace Vectormath::Aos; + +template< class T > +inline const T& min_(const T& a,const T& b) +{ + return a +inline const T& max_(const T& a,const T& b) +{ + return a +inline const T clamp(const T& val,const T& low,const T& high) +{ + return min_(max_(val,low),high); +} + +struct S3DVertex +{ + S3DVertex() {}; + S3DVertex(f32 x,f32 y,f32 z,f32 nx,f32 ny,f32 nz,f32 tu,f32 tv) + : pos(x,y,z),nrm(nx,ny,nz),u(tu),v(tv) {}; + + inline S3DVertex& operator=(const S3DVertex& other) + { + pos = other.pos; + nrm = other.nrm; + u = other.u; + v = other.v; + return *this; + } + + Vector3 pos; + Vector3 nrm; + + f32 u,v; +}; + +template< class T > +class CMeshBuffer +{ +public: + CMeshBuffer() : indices(NULL),cnt_indices(0),vertices(NULL),cnt_vertices(0) {}; + + u16 *indices; + u32 cnt_indices; + + S3DVertex *vertices; + u32 cnt_vertices; +}; + +typedef CMeshBuffer SMeshBuffer; + +#endif diff --git a/samples/graphics/rsx_Basic_Cube/include/rsxutil.h b/samples/graphics/rsx_Basic_Cube/include/rsxutil.h new file mode 100644 index 00000000..4a87ea9b --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/include/rsxutil.h @@ -0,0 +1,38 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include +#include + +#include + +#define DEFUALT_CB_SIZE 0x80000 // 512Kb default command buffer size +#define HOST_STATE_CB_SIZE 0x10000 // 64Kb state command buffer size (used for resetting certain default states) +#define HOST_ADDR_ALIGNMENT (1024*1024) +#define HOSTBUFFER_SIZE (128*1024*1024) + +#define FRAME_BUFFER_COUNT 2 + +extern gcmContextData *context; + +extern u32 curr_fb; + +extern u32 display_width; +extern u32 display_height; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern u32 *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern u32 *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; + +void setRenderTarget(u32 index); +void init_screen(void *host_addr,u32 size); +void waitflip(); +void flip(); + +#endif diff --git a/samples/graphics/rsx_Basic_Cube/rsx_basic_cube.png b/samples/graphics/rsx_Basic_Cube/rsx_basic_cube.png new file mode 100644 index 00000000..75b48136 Binary files /dev/null and b/samples/graphics/rsx_Basic_Cube/rsx_basic_cube.png differ diff --git a/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.fcg b/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.fcg new file mode 100644 index 00000000..7a9f6b40 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.fcg @@ -0,0 +1,13 @@ +void main +( + float2 texcoord : TEXCOORD2, + + + uniform sampler2D texture, + + out float4 oColor +) +{ + + oColor = tex2D(texture, texcoord); +} diff --git a/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.vcg b/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.vcg new file mode 100644 index 00000000..c11e6228 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/shaders/diffuse_specular_shader.vcg @@ -0,0 +1,21 @@ +void main +( + float3 vertexPosition : POSITION, + float3 vertexNormal : NORMAL, + float2 vertexTexcoord : TEXCOORD0, + + uniform float4x4 projMatrix, + uniform float4x4 modelViewMatrix, + + out float4 ePosition : POSITION, + out float4 oPosition : TEXCOORD0, + out float3 oNormal : TEXCOORD1, + out float2 oTexcoord : TEXCOORD2 +) +{ + ePosition = mul(mul(projMatrix,modelViewMatrix),float4(vertexPosition,1.0f)); + + oPosition = float4(vertexPosition,1.0f); + oNormal = vertexNormal; + oTexcoord = vertexTexcoord; +} diff --git a/samples/graphics/rsx_Basic_Cube/source/main.cpp b/samples/graphics/rsx_Basic_Cube/source/main.cpp new file mode 100644 index 00000000..ed0f2e1a --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/source/main.cpp @@ -0,0 +1,425 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "Stone_Texture_png_bin.h" +#include + +#include +#include +#include + +#include "acid.h" +#include "mesh.h" +#include "rsxutil.h" + +#include "diffuse_specular_shader_vpo.h" +#include "diffuse_specular_shader_fpo.h" + +#define DEGTORAD(a) ( (a) * 0.01745329252f ) +#define RADTODEG(a) ( (a) * 57.29577951f ) +#define TEXTURE_SIZE 128 +float perlin2d(float x, float y, float freq, int depth); + +u32 running = 0; + +u32 fp_offset; +u32 *fp_buffer; + +u32 *texture_buffer[3]; +u32 texture_buffer_idx = 0; +u32 texture_offset[3]; +pngData *png; +f32 rotx = 0.0f; +f32 roty = 0.0f; + +// vertex shader +rsxProgramConst *projMatrix; +rsxProgramConst *mvMatrix; + +// fragment shader +rsxProgramAttrib *textureUnit; + +Point3 eye_pos = Point3(0.0f,0.0f,20.0f); +Point3 eye_dir = Point3(0.0f,0.0f,0.0f); +Vector3 up_vec = Vector3(0.0f,1.0f,0.0f); + +void *vp_ucode = NULL; +rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; + +void *fp_ucode = NULL; +rsxFragmentProgram *fpo = (rsxFragmentProgram*)diffuse_specular_shader_fpo; + +static Matrix4 P; +static SMeshBuffer *cube = NULL; + +SYS_PROCESS_PARAM(1001, 0x100000); + +extern "C" { +static void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context,1); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + + +static void init_texture() +{ + u32 i; + u8 *buffer; + + //Init png texture + const u8* data = (u8*)png->bmp_out; + texture_buffer[0] = (u32*)rsxMemalign(128, (png->height * png->pitch)); + + if(!texture_buffer[0]) return; + + rsxAddressToOffset(texture_buffer[0],&texture_offset[0]); + + buffer = (u8*)texture_buffer[0]; + for (i = 0; i < png->height * png->pitch; i += 4) { + buffer[i + 0] = *data++; + buffer[i + 1] = *data++; + buffer[i + 2] = *data++; + buffer[i + 3] = *data++; + } + + //Init acid pixel texture + data = acid.pixel_data; + texture_buffer[1] = (u32*)rsxMemalign(128,(acid.width*acid.height*4)); + + if (!texture_buffer[1]) return; + + rsxAddressToOffset(texture_buffer[1], &texture_offset[1]); + + buffer = (u8*)texture_buffer[1]; + for(i=0;icnt_indices = 36; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + for(i=0;i<36;i++) buffer->indices[i] = u[i]; + + buffer->cnt_vertices = 12; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->vertices[0] = S3DVertex(0,0,0, -1,-1,-1, 1, 0); + buffer->vertices[1] = S3DVertex(1,0,0, 1,-1,-1, 1, 1); + buffer->vertices[2] = S3DVertex(1,1,0, 1, 1,-1, 0, 1); + buffer->vertices[3] = S3DVertex(0,1,0, -1, 1,-1, 0, 0); + buffer->vertices[4] = S3DVertex(1,0,1, 1,-1, 1, 1, 0); + buffer->vertices[5] = S3DVertex(1,1,1, 1, 1, 1, 0, 0); + buffer->vertices[6] = S3DVertex(0,1,1, -1, 1, 1, 0, 1); + buffer->vertices[7] = S3DVertex(0,0,1, -1,-1, 1, 1, 1); + buffer->vertices[8] = S3DVertex(0,1,1, -1, 1, 1, 1, 0); + buffer->vertices[9] = S3DVertex(0,1,0, -1, 1,-1, 1, 1); + buffer->vertices[10] = S3DVertex(1,0,1, 1,-1, 1, 0, 1); + buffer->vertices[11] = S3DVertex(1,0,0, 1,-1,-1, 0, 0); + + for(i=0;i<12;i++) { + buffer->vertices[i].pos -= Vector3(0.5f,0.5f,0.5f); + buffer->vertices[i].pos *= size; + } + + return buffer; +} + +static void setTexture(u8 textureUnit, u32 numTex) +{ + u32 width = 128; + u32 height = 128; + u32 pitch = (width*4); + gcmTexture texture; + + if(!texture_buffer[0]) return; + + rsxInvalidateTextureCache(context,GCM_INVALIDATE_TEXTURE); + + //texture.format = (GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN); + texture.format = (GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN | GCM_TEXTURE_FORMAT_NRM); + + texture.mipmap = 1; + texture.dimension = GCM_TEXTURE_DIMS_2D; + texture.cubemap = GCM_FALSE; + texture.remap = ((GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_B_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_G_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_R_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_A_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_B << GCM_TEXTURE_REMAP_COLOR_B_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_G << GCM_TEXTURE_REMAP_COLOR_G_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_R << GCM_TEXTURE_REMAP_COLOR_R_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_A << GCM_TEXTURE_REMAP_COLOR_A_SHIFT)); + texture.width = width; + texture.height = height; + texture.depth = 1; + texture.location = GCM_LOCATION_RSX; + texture.pitch = pitch; + texture.offset = texture_offset[numTex]; + rsxLoadTexture(context,textureUnit,&texture); + rsxTextureControl(context,textureUnit,GCM_TRUE,0<<8,12<<8,GCM_TEXTURE_MAX_ANISO_1); + rsxTextureFilter(context,textureUnit,0,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureWrapMode(context,textureUnit,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,0,GCM_TEXTURE_ZFUNC_LESS,0); +} + +static void setDrawEnv() +{ + rsxSetColorMask(context,GCM_COLOR_MASK_B | + GCM_COLOR_MASK_G | + GCM_COLOR_MASK_R | + GCM_COLOR_MASK_A); + + rsxSetColorMaskMrt(context,0); + + u16 x,y,w,h; + f32 min, max; + f32 scale[4],offset[4]; + + x = 0; + y = 0; + w = display_width; + h = display_height; + min = 0.0f; + max = 1.0f; + scale[0] = w*0.5f; + scale[1] = h*-0.5f; + scale[2] = (max - min)*0.5f; + scale[3] = 0.0f; + offset[0] = x + w*0.5f; + offset[1] = y + h*0.5f; + offset[2] = (max + min)*0.5f; + offset[3] = 0.0f; + + rsxSetViewport(context,x, y, w, h, min, max, scale, offset); + rsxSetScissor(context,x,y,w,h); + + rsxSetDepthTestEnable(context,GCM_TRUE); + rsxSetDepthFunc(context,GCM_LESS); + rsxSetShadeModel(context,GCM_SHADE_MODEL_SMOOTH); + rsxSetDepthWriteEnable(context,1); + rsxSetFrontFace(context,GCM_FRONTFACE_CCW); +} + +void init_shader() +{ + u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + printf("vpsize: %d\n", vpsize); + + projMatrix = rsxVertexProgramGetConst(vpo,"projMatrix"); + if (projMatrix) + printf("projMatrix OK\n"); + mvMatrix = rsxVertexProgramGetConst(vpo,"modelViewMatrix"); + if (mvMatrix) + printf("mvMatrix OK\n"); + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + printf("fpsize: %d\n", fpsize); + + fp_buffer = (u32*)rsxMemalign(64,fpsize); + memcpy(fp_buffer,fp_ucode,fpsize); + rsxAddressToOffset(fp_buffer,&fp_offset); + + textureUnit = rsxFragmentProgramGetAttrib(fpo,"texture"); + if (textureUnit) + printf("textureUnit OK\n"); +} + +void drawFrame() +{ + u32 i,offset,color = 0; + Matrix4 rotX,rotY; + Matrix4 viewMatrix,modelMatrix,modelMatrixIT,modelViewMatrix; + + SMeshBuffer *mesh = NULL; + + setDrawEnv(); + setTexture(textureUnit->index, texture_buffer_idx); + + rsxSetClearColor(context,color); + rsxSetClearDepthStencil(context,0xffffff00); + rsxClearSurface(context,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + rsxSetZControl(context,0,1,1); + + for(i=0;i<8;i++) + rsxSetViewportClip(context,i,display_width,display_height); + + viewMatrix = Matrix4::lookAt(eye_pos,eye_dir,up_vec); + + mesh = cube; + rotX = Matrix4::rotationX(DEGTORAD(rotx)); + rotY = Matrix4::rotationY(DEGTORAD(roty)); + modelMatrix = rotX*rotY; + modelMatrixIT = Matrix4::identity();// inverse(modelMatrix); + modelViewMatrix = transpose(viewMatrix*modelMatrix); + + rsxAddressToOffset(&mesh->vertices[0].pos,&offset); + rsxBindVertexArrayAttrib(context,GCM_VERTEX_ATTRIB_POS,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); + rsxBindVertexArrayAttrib(context,GCM_VERTEX_ATTRIB_NORMAL,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].u,&offset); + rsxBindVertexArrayAttrib(context,GCM_VERTEX_ATTRIB_TEX0,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxLoadVertexProgram(context,vpo,vp_ucode); + rsxSetVertexProgramParameter(context,vpo,projMatrix,(float*)&P); + rsxSetVertexProgramParameter(context,vpo,mvMatrix,(float*)&modelViewMatrix); + rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); + + rsxSetUserClipPlaneControl(context,GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0],&offset); + rsxDrawIndexArray(context,GCM_TYPE_TRIANGLES,offset,mesh->cnt_indices,GCM_INDEX_TYPE_16B,GCM_LOCATION_RSX); + +} + +int main(int argc,const char *argv[]) +{ + padInfo padinfo; + padData paddata; + + if (sysModuleLoad(SYSMODULE_PNGDEC) != 0) exit(0); + + png = new pngData; + pngLoadFromBuffer(Stone_Texture_png_bin, Stone_Texture_png_bin_size, png); + + void *host_addr = memalign(HOST_ADDR_ALIGNMENT,HOSTBUFFER_SIZE); + + printf("rsxtest started...\n"); + + init_screen(host_addr,HOSTBUFFER_SIZE); + ioPadInit(7); + init_shader(); + init_texture(); + + DebugFont::init(); + DebugFont::setScreenRes(display_width, display_height); + + cube = createCube(5.0f); + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + P = transpose(Matrix4::perspective(DEGTORAD(45.0f),aspect_ratio,1.0f,3000.0f)); + + setDrawEnv(); + setRenderTarget(curr_fb); + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if (paddata.BTN_DOWN) { + rotx += 0.5f; + } + if (paddata.BTN_UP) { + rotx -= 0.5f; + } + if (rotx >= 360.0f || rotx <= 0.0f) rotx = fmodf(rotx, 360.0f); + if (paddata.BTN_RIGHT) { + roty += 0.5f; + } + if (paddata.BTN_LEFT) { + roty -= 0.5f; + } + if (roty >= 360.0f || roty <= 0.0f) roty = fmodf(roty, 360.0f); + if (paddata.BTN_CROSS) + texture_buffer_idx++; + if (texture_buffer_idx == 3) + texture_buffer_idx = 0; + if(paddata.BTN_CIRCLE) + goto done; + } + + } + + drawFrame(); + int ypos = 10; + int xpos = 10; + DebugFont::setPosition(xpos, ypos); + DebugFont::setColor(1.0f, 1.0f, 1.0f, 1.0f); + + DebugFont::print("Left/Right Pad to Left/Right rotation"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("Up/Down Pad to Up/Down rotation"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("CROSS Button to change texture"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("CIRCLE Button to exit"); + + flip(); + } + +done: + printf("rsxtest done...\n"); + DebugFont::shutdown(); + program_exit_callback(); + return 0; +} diff --git a/samples/graphics/rsx_Basic_Cube/source/perlin.cpp b/samples/graphics/rsx_Basic_Cube/source/perlin.cpp new file mode 100644 index 00000000..14ec05ad --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/source/perlin.cpp @@ -0,0 +1,68 @@ +#include + +static int SEED = 0; + +static int hash[] = { 208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40, + 185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204, + 9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81, + 70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13, + 203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41, + 164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105, + 228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89, + 232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174, + 193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145, + 101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167, + 135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255, + 114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219 }; + +int noise2(int x, int y) +{ + int tmp = hash[(y + SEED) % 256]; + return hash[(tmp + x) % 256]; +} + +float lin_inter(float x, float y, float s) +{ + return x + s * (y - x); +} + +float smooth_inter(float x, float y, float s) +{ + return lin_inter(x, y, s * s * (3 - 2 * s)); +} + +float noise2d(float x, float y) +{ + int x_int = x; + int y_int = y; + float x_frac = x - x_int; + float y_frac = y - y_int; + int s = noise2(x_int, y_int); + int t = noise2(x_int + 1, y_int); + int u = noise2(x_int, y_int + 1); + int v = noise2(x_int + 1, y_int + 1); + float low = smooth_inter(s, t, x_frac); + float high = smooth_inter(u, v, x_frac); + return smooth_inter(low, high, y_frac); +} + +float perlin2d(float x, float y, float freq, int depth) +{ + float xa = x * freq; + float ya = y * freq; + float amp = 1.0; + float fin = 0; + float div = 0.0; + + int i; + for (i = 0; i < depth; i++) + { + div += 256 * amp; + fin += noise2d(xa, ya) * amp; + amp /= 2; + xa *= 2; + ya *= 2; + } + + return fin / div; +} \ No newline at end of file diff --git a/samples/graphics/rsx_Basic_Cube/source/rsxutil.cpp b/samples/graphics/rsx_Basic_Cube/source/rsxutil.cpp new file mode 100644 index 00000000..4319d8e6 --- /dev/null +++ b/samples/graphics/rsx_Basic_Cube/source/rsxutil.cpp @@ -0,0 +1,207 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "rsxutil.h" + +#define GCM_LABEL_INDEX 255 + +videoResolution vResolution; +gcmContextData *context = NULL; + +u32 curr_fb = 0; +u32 first_fb = 1; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +u32 *depth_buffer; + +u32 color_pitch; +u32 color_offset[FRAME_BUFFER_COUNT]; +u32 *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); + +static u32 sLabelVal = 1; + +static RSXDebugFontRenderer *debugFontRenderer; + +static void waitFinish() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(context); + + while(*(vu32*)gcmGetLabelAddress(GCM_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitFinish(); +} + +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + (u32)vResolution.width*4 + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + +void setRenderTarget(u32 index) +{ + gcmSurface sf; + + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; + sf.colorLocation[0] = GCM_LOCATION_RSX; + sf.colorOffset[0] = color_offset[index]; + sf.colorPitch[0] = color_pitch; + + sf.colorLocation[1] = GCM_LOCATION_RSX; + sf.colorLocation[2] = GCM_LOCATION_RSX; + sf.colorLocation[3] = GCM_LOCATION_RSX; + sf.colorOffset[1] = 0; + sf.colorOffset[2] = 0; + sf.colorOffset[3] = 0; + sf.colorPitch[1] = 64; + sf.colorPitch[2] = 64; + sf.colorPitch[3] = 64; + + sf.depthFormat = GCM_SURFACE_ZETA_Z24S8; + sf.depthLocation = GCM_LOCATION_RSX; + sf.depthOffset = depth_offset; + sf.depthPitch = depth_pitch; + + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; + + sf.width = display_width; + sf.height = display_height; + sf.x = 0; + sf.y = 0; + + rsxSetSurface(context,&sf); +} + +void init_screen(void *host_addr,u32 size) +{ + u32 zs_depth = 4; + u32 color_depth = 4; + + rsxInit(&context,DEFUALT_CB_SIZE,size,host_addr); + + initVideoConfiguration(); + + waitRSXIdle(); + + gcmSetFlipMode(GCM_FLIP_VSYNC); + + color_pitch = display_width*color_depth; + depth_pitch = display_width*zs_depth; + + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + color_buffer[i] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + rsxAddressToOffset(color_buffer[i],&color_offset[i]); + gcmSetDisplayBuffer(i,color_offset[i],color_pitch,display_width,display_height); + } + + depth_buffer = (u32*)rsxMemalign(64, display_height*depth_pitch); + rsxAddressToOffset(depth_buffer,&depth_offset); + + debugFontRenderer = new RSXDebugFontRenderer(context); +} + +void waitflip() +{ + while(gcmGetFlipStatus()!=0) + usleep(200); + gcmResetFlipStatus(); +} + +void flip() +{ + if(!first_fb) waitflip(); + else gcmResetFlipStatus(); + + gcmSetFlip(context,curr_fb); + rsxFlushBuffer(context); + + gcmSetWaitFlip(context); + + curr_fb ^= 1; + setRenderTarget(curr_fb); + + first_fb = 0; +} diff --git a/samples/graphics/rsx_Basic_Wallpaper/Makefile b/samples/graphics/rsx_Basic_Wallpaper/Makefile new file mode 100644 index 00000000..c76ea9e9 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/Makefile @@ -0,0 +1,164 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source ../debugfont_renderer/source +DATA := data +SHADERS := shaders ../debugfont_renderer/shaders +INCLUDES := include ../debugfont_renderer/include + +TITLE := RSX Test - PSL1GHT +APPID := RSX00003 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lsimdmath -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm -lsysmodule -lpngdec + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(SHADERS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +VCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.vcg))) +FCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.fcg))) + +VPOFILES := $(VCGFILES:.vcg=.vpo) +FPOFILES := $(FCGFILES:.fcg=.fpo) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(addsuffix .o,$(VPOFILES)) \ + $(addsuffix .o,$(FPOFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(OUTPUT).fake.self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.vpo.o : %.vpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.fpo.o : %.fpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/rsx_Basic_Wallpaper/Readme.md b/samples/graphics/rsx_Basic_Wallpaper/Readme.md new file mode 100644 index 00000000..45745d77 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/Readme.md @@ -0,0 +1,3 @@ +A basic background wallpaper using vertex, fragment and texture with a scanline shader. + +![RSX basic cube example](rsx_basic_wallpaper.png?raw=true) diff --git a/samples/graphics/rsx_Basic_Wallpaper/include/acid.h b/samples/graphics/rsx_Basic_Wallpaper/include/acid.h new file mode 100644 index 00000000..d1643518 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/include/acid.h @@ -0,0 +1,2939 @@ +/* GIMP RGBA C-Source image dump (acid.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +} acid = { + 128, 128, 4, + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\335\335\335\0\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31" + "\31\0\15\15\15\0\5\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0))" + ")\0===\0UUU\0qqq\0\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\345\345\345\0\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\15\15\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0qqq\0---\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\15\0\0\0" + "\23\0\0\0\30\0\0\0\35\0\0\0!\0\0\0$\0\0\0&\0\0\0(\0\0\0(\0\0\0'\0\0\0$\0" + "\0\0!\0\0\0\35\0\0\0\31\0\0\0\23\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0---\0qqq\0\271\271\271\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\17\0\0\0\30\0\0\0\40\0\0\0+\0\0\0B\0" + "\0\0\\\0\0\0t\0\0\0\211\0\0\0\234\0\0\0\254\0\0\0\271\0\0\0\304\0\0\0\313" + "\0\0\0\313\0\0\0\304\0\0\0\271\0\0\0\254\0\0\0\234\0\0\0\211\0\0\0t\0\0\0" + "\\\0\0\0B\0\0\0+\0\0\0!\0\0\0\30\0\0\0\17\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\21\21\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\2\0\0\0\14\0\0\0\30\0\0\0&\0\0\0?\0\0\0d\0\0\0\211\0\0\0\254\0\0\0\311" + "\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\354\0\0\0\361\0\0\0\365\0\0\0\370\0" + "\0\0\373\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\371\0\0\0\365\0\0\0\361\0\0" + "\0\355\0\0\0\347\0\0\0\341\0\0\0\331\0\0\0\312\0\0\0\254\0\0\0\211\0\0\0" + "d\0\0\0?\0\0\0&\0\0\0\30\0\0\0\15\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0QQQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0\33\0\0" + "\0.\0\0\0Y\0\0\0\211\0\0\0\265\0\0\0\325\0\0\0\343\0\0\0\354\0\0\0\365\0" + "\0\0\374\40!\0\377FH\0\377hk\0\377\206\213\0\377\240\246\0\377\267\275\0" + "\377\311\321\0\377\330\341\0\377\344\354\0\377\344\354\0\377\330\341\0\377" + "\311\321\0\377\267\275\0\377\240\246\0\377\206\213\0\377hk\0\377FH\0\377" + "\40!\0\377\0\0\0\375\0\0\0\365\0\0\0\355\0\0\0\343\0\0\0\326\0\0\0\266\0" + "\0\0\211\0\0\0Z\0\0\0/\0\0\0\33\0\0\0\16\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0" + "\0\0\0\0QQQ\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\255\255\255\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0" + "\27\0\0\0-\0\0\0]\0\0\0\224\0\0\0\304\0\0\0\336\0\0\0\354\0\0\0\367\30\31" + "\0\376QT\0\377\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0" + "\376\0\0\0\367\0\0\0\354\0\0\0\337\0\0\0\305\0\0\0\224\0\0\0]\0\0\0-\0\0" + "\0\30\0\0\0\11\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0===\0\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265" + "\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\15\0\0\0!\0\0\0H\0\0\0\204" + "\0\0\0\274\0\0\0\336\0\0\0\357\0\0\0\373BD\0\377\206\213\0\377\306\315\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\306\315\0\377\206\213\0\377BD\0\377\0\0\0\373" + "\0\0\0\357\0\0\0\337\0\0\0\275\0\0\0\204\0\0\0I\0\0\0!\0\0\0\15\0\0\0\3\0" + "\0\0\1\0\0\0\0\0\0\0\0===\0\265\265\265\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0QQ" + "Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0'\0\0\0[\0\0\0\236\0\0" + "\0\324\0\0\0\353\0\0\0\371FH\0\377\225\232\0\377\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\340\350\0\377\225\232\0\377FH\0\377\0\0\0\371\0" + "\0\0\353\0\0\0\324\0\0\0\236\0\0\0\\\0\0\0'\0\0\0\17\0\0\0\3\0\0\0\1\0\0" + "\0\0\0\0\0\0QQQ\0\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0(\0\0\0c\0\0\0\250" + "\0\0\0\332\0\0\0\361$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\361\0\0\0" + "\333\0\0\0\251\0\0\0c\0\0\0(\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0yyy" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0)))\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\0\0\0$\0\0\0_" + "\0\0\0\250\0\0\0\334\0\0\0\364BD\0\376\244\252\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0" + "\335\0\0\0\250\0\0\0`\0\0\0%\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\0)))\0\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\4\0\0\0\34\0\0\0O\0\0\0\234\0\0\0\332\0\0\0\364FH\0\376\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH\0\376\0\0\0\364\0" + "\0\0\332\0\0\0\234\0\0\0P\0\0\0\34\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0qqq\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315" + "\0""555\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0""0\0\0\0\203\0\0\0\321\0" + "\0\0\360+-\0\375\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377+-\0\375" + "\0\0\0\360\0\0\0\322\0\0\0\203\0\0\0""1\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0" + """555\0\315\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\4\0\0\0\40\0\0\0`\0\0\0\262\0\0\0\346\0\0\0\374~\203\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\374\0\0\0\347\0\0\0\263\0\0\0a\0\0\0\40\0\0\0\5\0\0" + "\0\1\0\0\0\0\1\1\1\0\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0" + "\0/\0\0\0\207\0\0\0\326\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\311\321\0\377FH\0\376\0\0\0\366\0\0\0\327\0\0\0\207\0\0\0" + """0\0\0\0\14\0\0\0\2\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375" + "\375\375\0UUU\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\30\0\0\0S\0\0\0\252\0\0\0\345" + "\0\0\0\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\374\0\0\0\346" + "\0\0\0\253\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\0UUU\0\375\375\375\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0==" + "=\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\"\0\0\0q\0\0\0\316\0\0\0\363/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\364\0\0\0\316\0\0\0q\0\0\0\"\0\0\0\5\0\0\0\1\0\0\0\0===\0\351\351" + "\351\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\0\0\0\0\1" + "\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\\`\0\377\0\0\0\373\0\0\0\332\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1\0\0" + "\0\1---\0\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\331\331\331\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0""2\0\0\0\225\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\342\0\0\0" + "\226\0\0\0""2\0\0\0\11\0\0\0\1\0\0\0\1%%%\0\331\331\331\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\335\335\335\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0?\0\0\0\243\0\0\0\350\2\2\0\375\240\246\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377" + "\2\2\0\375\0\0\0\350\0\0\0\244\0\0\0@\0\0\0\15\0\0\0\2\0\0\0\1%%%\0\335\335" + "\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\0\0\0\0\1\0\0\0\16" + "\0\0\0H\0\0\0\257\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\355\0\0\0\257\0\0\0H\0\0\0" + "\17\0\0\0\2\0\0\0\1---\0\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\375\375\375\0===\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0H\0\0\0\264\0\0\0\360\40!\0\376\306\315\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\40!\0\376\0\0\0" + "\360\0\0\0\265\0\0\0I\0\0\0\15\0\0\0\1\0\0\0\1===\0\375\375\375\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0?\0\0\0\257\0\0\0\360$%\0\376\315\325\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\315\325" + "\0\377$%\0\377\0\0\0\360\0\0\0\257\0\0\0@\0\0\0\11\0\0\0\1\0\0\0\1UUU\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0""2" + "\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\355\0\0\0\244\0\0\0""2\0" + "\0\0\6\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\0\0\0\0\0\0\0\0\0\0" + "\0\4\0\0\0*\0\0\0\225\0\0\0\350\25\25\0\376\306\315\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\25" + "\25\0\376\0\0\0\350\0\0\0\226\0\0\0*\0\0\0\5\0\0\0\1\0\0\0\0\235\235\235" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315\0" + "\1\1\1\0\0\0\0\0\0\0\0\3\0\0\0\"\0\0\0\205\0\0\0\342\2\2\0\375\267\275\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\2\2\0\375\0\0\0\342\0\0\0" + "\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\0\315\315\315\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374" + "\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377\13\14\0\377UX\0\377" + "\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0S\0\0\0\316\0\0\0\373\202\207" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\310\317\0\3779<\0\377\0\0\0\3779<\0\377\310\317\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\306\315\0\377!\"\0\377\0\0\0\377\0\0\0\377\4\4\0\377PT\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\316\0\0\0S\0\0\0\14\0\0\0\1\0\0\0\0qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\0\0\0\0\4\0\0\0/\0\0\0\253\0\0\0\364\\`\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377/2\0\377\0\0\0\377\0\0\0\377\0\0\0\377/2\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0" + "\253\0\0\0""0\0\0\0\5\0\0\0\1\0\0\0\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0)))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0" + "\0\207\0\0\0\345/1\0\376\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\207\215\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\357\370\0\377/1\0\376\0\0\0\346" + "\0\0\0\207\0\0\0\40\0\0\0\3\0\0\0\1)))\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0`\0\0\0\326\0\0\0\374\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\5\5\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\374\0\0\0" + "\327\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\0yyy\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0" + "\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0" + "\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\0\321\321\321\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0" + "\0\0\0\0\0\0\2\0\0\0\34\0\0\0\203\0\0\0\346FH\0\376\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\376" + "\0\0\0\347\0\0\0\204\0\0\0\34\0\0\0\2\0\0\0\1QQQ\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0\0\0\0" + "\0\0\0\12\0\0\0O\0\0\0\321\0\0\0\374\311\321\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321" + "\0\377\0\0\0\374\0\0\0\322\0\0\0P\0\0\0\13\0\0\0\1\0\0\0\0\265\265\265\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0" + "\0%\0\0\0\234\0\0\0\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\361\0\0\0\234\0\0\0%\0\0\0\3\0\0\0\1===\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0_\0" + "\0\0\332+-\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377+-\0\375\0\0\0\332\0\0\0`\0\0\0\17\0\0\0\1\0\0\0\0\255\255" + "\255\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0(\0\0\0\250\0\0\0" + "\363\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\244\252\0\377\0\0\0\364\0\0\0\250\0\0\0)\0\0\0\3\0\0\0\1=" + "==\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0c\0\0\0\334FH" + "\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\17\0\0\0" + "\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'\0\0\0\251\0\0\0\363\267\275" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0" + "(\0\0\0\3\0\0\0\1QQQ\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377BD\0\376\0\0\0\333\0\0\0\\" + "\0\0\0\16\0\0\0\1\0\0\0\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\2\0\0\0!\0\0\0\235\0\0\0\361\244\252\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\361\0" + "\0\0\236\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\35\35\35\0\0\0\0\0\0\0\0\10\0\0\0H\0\0\0\324$%\0\375\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377$%\0\375\0" + "\0\0\325\0\0\0I\0\0\0\11\0\0\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0\203\0\0\0\353~\203\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203" + "\0\377\0\0\0\353\0\0\0\204\0\0\0\27\0\0\0\1\0\0\0\0\265\265\265\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\325\335\0\377\0\0\0\371\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\336FH\0\376\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0]\0\0\0\16\0\0\0\1\21\21\21\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0\0\0\0\0\0\0\0\0\0\0\0\32\0\0\0\223\0\0\0\357\225\232\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\357\0\0\0\224\0\0\0\33\0" + "\0\0\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\340\350\0\377\0\0\0\373\0\0\0\305\0\0\0" + "/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0---\0\0\0\0\0\0\0\0\14\0\0\0Y\0\0\0\336BD\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\337\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0" + "\0\0\211\0\0\0\30\0\0\0\1\0\0\0\0\345\345\345\0\377\377\377\0\377\377\377" + "\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\265\0\0\0\367\306\315\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377" + "\0\0\0\367\0\0\0\266\0\0\0&\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377\377\377\0\377\377" + "\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343QT\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT" + "\0\377\0\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0" + "\15\15\15\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15\15\15\0\377\377\377" + "\0\335\335\335\0\0\0\0\0\0\0\0\0\0\0\0\40\0\0\0\254\0\0\0\365\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0\0!\0\0\0\1\0\0\0\0\335" + "\335\335\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0+\0\0\0\311\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\210\215\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\7\7\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\344\354\0\377\0\0\0\374\0\0\0\312\0\0\0,\0\0\0\2" + "\0\0\0\1\265\265\265\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0B\0\0\0\331\40" + "!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\20\21\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\40!\0\377\0\0\0" + "\332\0\0\0B\0\0\0\7\0\0\0\1\221\221\221\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0" + "\0\0\341FH\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\37702\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\37702\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377!\"\0\377\0\0" + "\0\377\0\0\0\377\4\4\0\377PS\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0\0\0\342\0" + "\0\0]\0\0\0\15\0\0\0\1qqq\0UUU\0\0\0\0\0\0\0\0\23\0\0\0t\0\0\0\347hk\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\3779<\0\377\0" + "\0\0\3779<\0\377\310\317\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377" + "\13\14\0\377UX\0\377\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0" + "\0\0u\0\0\0\23\0\0\0\1UUU\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206" + "\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===" + "\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0\361\240\246\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246" + "\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0\1)))\0\31\31\31\0\0\0\0\0\0\0\0" + "\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0\15\15\15\0\0\0\0\0\0\0\0$\0\0\0\271\0" + "\0\0\370\311\321\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\311\321\0\377\0\0\0\371\0\0\0\272\0\0\0" + "$\0\0\0\1\15\15\15\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\1\1\1" + "\0\0\0\0\0\0\0\0(\0\0\0\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\313\0\0\0)\0\0\0\1\1\1\1\0\1\1\1\0\0\0\0\0\0\0\0(\0\0\0" + "\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\344\354\0\377\0\0\0\375\0\0\0\313\0\0" + "\0)\0\0\0\1\1\1\1\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\15\15" + "\15\0\0\0\0\0\0\0\0$\0\0\0\271\0\0\0\370\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321\0" + "\377\0\0\0\371\0\0\0\272\0\0\0$\0\0\0\1\15\15\15\0\31\31\31\0\0\0\0\0\0\0" + "\0\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0" + "\361\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\240\246\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0" + "\1)))\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206" + "\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===\0UUU\0\0\0\0\0\0\0\0\23" + "\0\0\0t\0\0\0\347hk\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0\0\0u\0\0\0\23\0\0\0" + "\1UUU\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\341FH\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0" + "\0\0\342\0\0\0]\0\0\0\15\0\0\0\1qqq\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0" + "B\0\0\0\331\40!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\40!\0\377\0\0\0\332\0\0\0C\0\0\0\7\0\0\0\1\221" + "\221\221\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0,\0\0\0\312\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\312\0\0\0,\0\0\0\2\0\0\0\1\265\265\265\0\335\335\335\0\0" + "\0\0\0\0\0\0\1\0\0\0!\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0" + "\0\"\0\0\0\1\0\0\0\1\335\335\335\0\377\377\377\0\15\15\15\0\0\0\0\0\0\0\0" + "\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15" + "\15\15\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343" + "QT\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT\0\377\0" + "\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0qqq\0\0" + "\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377" + "\377\377\0\377\377\377\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\266\0" + "\0\0\367\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\335\345\0\377\261\270\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\0\0\0\370" + "\0\0\0\266\0\0\0'\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377\377\377" + "\0\345\345\345\0\0\0\0\0\0\0\0\1\0\0\0\31\0\0\0\212\0\0\0\354\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\322\332\0\377\36" + "\37\0\377\10\10\0\377\265\273\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\316\326\0\377\230\235\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\0" + "\0\0\1\345\345\345\0\377\377\377\0\377\377\377\0\377\377\377\0---\0\0\0\0" + "\0\0\0\0\14\0\0\0Z\0\0\0\337BD\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\1\1\0\377\201\206\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0\377\17" + "\20\0\377\2\2\0\377\224\231\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\340\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377SV\0\377\353\364\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377w{\0\377\1\1\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377;>\0\377<>\0\377<>\0\377\303\312\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\0\0\0\373\0\0\0\305\0\0\0/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\1" + "\0\0\0\33\0\0\0\224\0\0\0\357\225\232\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\26\26\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377.0\0\377" + "\330\340\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\345\355\0\377?A" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\1\1\0\377\310\320\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\360\0\0\0" + "\225\0\0\0\34\0\0\0\1\0\0\0\1\271\271\271\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0" + "]\0\0\0\337FH\0\376\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\257\266\0\377\4\4\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\16\17\0\377\265\273" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\277\306\0\377\23\24\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\0\377\226\233\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0^\0\0\0\16\0\0\0\1\21\21" + "\21\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\300\307\0\377\30\31\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377z\177\0\377\355\366" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377pt\0\377\2\2\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2" + "\0\377\235\243\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\325\335\0\377\0\0\0\371" + "\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\1\0\0\0\27\0\0\0\204\0\0\0\353~\203\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\330\341\0\377&'\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\25\25\0\377\277\306\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\377" + "-/\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\25\25\0\377\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377~\203\0\377\0\0\0\354\0\0\0\205\0\0\0\30\0\0\0\1\0\0\0\1\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\35\35\35\0\0\0\0\0\0\0\0\11\0\0\0I\0\0\0\324" + "$%\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\350\360\0\377EG\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\2\2\0\377mq\0\377\352\363\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\342\352\0" + "\377fi\0\377\2\2\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377*,\0\377\333\344\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377$%\0\375\0\0\0\325\0\0\0J\0\0\0\11\0\0" + "\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\2" + "\0\0\0!\0\0\0\236\0\0\0\361\244\252\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377tx\0\377\1\1\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\36\0\377\235\243\0" + "\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\220" + "\225\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377gj\0\377\353\364\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\362\0" + "\0\0\237\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\1\0\0\0\16\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0" + "\377\13\14\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377-/\0\377\273\302\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355\366\0\377\177\204" + "\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\11\12\0\377\246\254\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "BD\0\376\0\0\0\333\0\0\0]\0\0\0\17\0\0\0\1\0\0\0\1\331\331\331\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'" + "\0\0\0\251\0\0\0\363\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\346\356\0\377HK\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377=?\0\377\247\255\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377\206\213\0\377" + "\34\35\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377/1\0\377\325\335\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0(\0\0\0\3\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0" + "\0\0\0\0\0\0\1\0\0\0\20\0\0\0d\0\0\0\335FH\0\375\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\211\217\0\377\10\11\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\14\15\0\377qu\0\377" + "\343\353\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\356\367\0\377\254\263\0\377hl\0\377\5\5\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\16\17\0\377\231\237\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\20\0\0\0\1\0\0\0\1\271\271\271" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0)\0\0\0\251\0\0\0\363\244\252\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\346\356\0\377fi\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\4\4\0\377BD\0\377\206\213\0\377\301\310\0\377\354\365\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340\350\0\377\230\235\0" + "\377^b\0\377\25\25\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377Z^" + "\0\377\335\345\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377" + "\0\0\0\364\0\0\0\251\0\0\0*\0\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255" + "\255\255\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0`\0\0\0\332+-\0\375\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\254\263\0\377\25\25\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\13\0\377;>\0\377UX\0" + "\377lp\0\377x|\0\377x|\0\377x|\0\377bf\0\377HK\0\377\6\6\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37713\0\377\275\304" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "+-\0\375\0\0\0\332\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\1\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0%\0\0\0\234\0\0\0" + "\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\216\223\0\377\16\17\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + ",.\0\377\247\255\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0\361\0\0\0\235\0\0\0%\0" + "\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265" + "\265\265\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0P\0\0\0\322\0\0\0\374\311\321\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355" + "\366\0\377\213\221\0\377\17\20\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\37724\0\377\246\254\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\311\321\0\377\0\0\0\374\0\0\0\323\0\0\0Q\0\0\0\14\0\0\0\1\0\0\0\1" + "\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0\34\0\0\0\204\0\0\0\347FH\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\356\367\0\377\235\243\0\377(*\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\5\5\0" + "\377hl\0\377\270\276\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377FH\0\377\0\0\0\347\0\0\0\204\0\0\0\35\0\0\0\2\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321" + "\321\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\320\330\0\377\\`\0\377\7" + "\7\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\3778:\0\377\226\233\0" + "\377\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\206\213\0\377\0\0\0\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\1" + "\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0a\0\0\0" + "\327\0\0\0\374\276\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\357\370\0\377\245\253\0\377w{\0\377:=\0\377\3\3\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377*,\0\377dh\0\377\217\224\0\377\350" + "\361\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\375\0\0\0\330\0\0\0b\0\0" + "\0\20\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + ")))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0\0\207\0\0\0\346/1\0\376\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\357\370\0\377\305\314\0\377\247\255\0\377" + "\212\220\0\377x}\0\377x}\0\377x}\0\377x}\0\377{\200\0\377\240\246\0\377\270" + "\276\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377/1\0\376\0\0\0\347\0\0\0\210\0\0\0!\0\0\0\3\0\0\0" + "\1)))\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""0\0\0\0\253\0\0\0\364\\`\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0\254\0\0\0""1" + "\0\0\0\6\0\0\0\1\0\0\0\1\265\265\265\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\1\0\0\0\14\0\0" + "\0T\0\0\0\317\0\0\0\373\202\207\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\317\0\0\0T\0\0\0\15\0\0\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374\240\246\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\315\315\315\0\1\1\1\0\0\0\0\1\0\0\0\4\0\0\0\"\0" + "\0\0\205\0\0\0\342\2\2\0\375\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267" + "\275\0\377\2\2\0\375\0\0\0\342\0\0\0\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\1\315" + "\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235" + "\235\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0+\0\0\0\226\0\0\0\350\25\25\0\376\306" + "\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\306\315\0\377\25\25\0\376\0\0\0\351\0\0\0\226\0\0\0+\0\0\0\6\0" + "\0\0\1\0\0\0\1\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0" + """2\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\356\0\0\0\245\0\0\0""3\0" + "\0\0\7\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0" + "\0\0\0\0\0\0\1\0\0\0\11\0\0\0@\0\0\0\260\0\0\0\360$%\0\376\315\325\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377$%\0\377\0\0\0\361\0\0\0\260\0\0\0A\0\0\0" + "\12\0\0\0\1\0\0\0\1UUU\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\375\375\375\0===\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0H\0\0\0\264\0\0\0\360" + "\40!\0\376\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\306\315\0\377\40!\0\376\0\0\0\361\0\0\0\265\0\0\0I\0\0\0\16" + "\0\0\0\2\0\0\0\1===\1\375\375\375\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\1\0\0\0\2\0\0\0\17" + "\0\0\0I\0\0\0\260\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\356\0\0\0\260\0\0\0I\0\0\0" + "\20\0\0\0\2\0\0\0\1---\1\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "%%%\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0@\0\0\0\244\0\0\0\350\2\2\0\375\240\246" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\240\246\0\377\2\2\0\375\0\0\0\351\0\0\0\245\0\0\0@\0\0\0\16" + "\0\0\0\2\0\0\0\1%%%\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\331\331\331\0%%%\0\0\0\0\1\0\0\0\2\0\0\0\12\0\0\0""2\0\0\0\226" + "\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\343\0\0\0\226\0\0\0""3\0\0\0" + "\12\0\0\0\2\0\0\0\1%%%\1\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\1\0\0" + "\0\1\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357" + "\370\0\377\\`\0\377\0\0\0\373\0\0\0\333\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1" + "\0\0\0\1---\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0" + "===\0\0\0\0\1\0\0\0\1\0\0\0\5\0\0\0#\0\0\0r\0\0\0\317\0\0\0\364/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\365\0\0\0\317\0\0\0r\0\0\0#\0\0\0\6\0\0\0\1\0\0\0\1===\1\351\351\351" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375\375\375" + "\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0S\0\0\0\253\0\0\0\346\0\0\0" + "\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\375\0\0\0\347\0\0\0" + "\254\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\1UUU\0\375\375\375\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0/\0\0\0\210\0" + "\0\0\327\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\311\321\0\377FH\0\377\0\0\0\367\0\0\0\330\0\0\0\210\0\0\0""0\0\0\0\15\0" + "\0\0\3\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\5\0" + "\0\0!\0\0\0a\0\0\0\263\0\0\0\347\0\0\0\374~\203\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0" + "\374\0\0\0\347\0\0\0\264\0\0\0b\0\0\0!\0\0\0\6\0\0\0\1\0\0\0\1\1\1\1\1\235" + "\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\315\315\315\0""555\0\0\0\0\0\0\0\0\1\0" + "\0\0\3\0\0\0\17\0\0\0""1\0\0\0\204\0\0\0\322\0\0\0\361+-\0\375\244\252\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\244\252\0\377+-\0\375\0\0\0\361\0\0\0\323\0\0\0" + "\204\0\0\0""1\0\0\0\20\0\0\0\3\0\0\0\1\0\0\0\1""555\0\315\315\315\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0" + "\0\0\1\0\0\0\1\0\0\0\5\0\0\0\34\0\0\0P\0\0\0\234\0\0\0\332\0\0\0\364FH\0" + "\376\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH" + "\0\376\0\0\0\364\0\0\0\333\0\0\0\235\0\0\0Q\0\0\0\35\0\0\0\5\0\0\0\1\0\0" + "\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0)))\0\0" + "\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0%\0\0\0`\0\0\0\251\0\0\0\335\0\0\0\364" + "BD\0\376\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0\336\0\0\0\251\0\0\0a\0\0\0&" + "\0\0\0\14\0\0\0\3\0\0\0\1\0\0\0\1)))\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0" + "\0\1\0\0\0\1\0\0\0\3\0\0\0\17\0\0\0)\0\0\0d\0\0\0\251\0\0\0\333\0\0\0\362" + "$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\362\0\0\0\334\0\0\0\252\0\0\0" + "d\0\0\0)\0\0\0\17\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\321\321\321\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1\0" + "\0\0\4\0\0\0\20\0\0\0(\0\0\0\\\0\0\0\236\0\0\0\325\0\0\0\354\0\0\0\372FH" + "\0\377\225\232\0\377\340\350\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\225\232\0\377FH\0\377\0\0\0\372\0\0\0\354\0\0\0\325\0\0\0\236" + "\0\0\0]\0\0\0(\0\0\0\20\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\321\321\321" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\265\265\265\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0" + "\16\0\0\0\"\0\0\0I\0\0\0\205\0\0\0\275\0\0\0\337\0\0\0\360\0\0\0\374BD\0" + "\377\206\213\0\377\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\206" + "\213\0\377BD\0\377\0\0\0\374\0\0\0\360\0\0\0\340\0\0\0\276\0\0\0\205\0\0" + "\0J\0\0\0\"\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1===\0\265\265\265\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255\255" + "\255\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\11\0\0\0\27\0\0\0-\0\0" + "\0]\0\0\0\225\0\0\0\305\0\0\0\337\0\0\0\355\0\0\0\370\30\31\0\376QT\0\377" + "\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0\376\0\0\0\370" + "\0\0\0\355\0\0\0\340\0\0\0\306\0\0\0\225\0\0\0^\0\0\0-\0\0\0\30\0\0\0\11" + "\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1===\0\255\255\255\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\271\271\271\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0\33\0\0\0/\0\0\0Z\0\0\0\212\0\0\0\266\0\0" + "\0\326\0\0\0\344\0\0\0\355\0\0\0\365\0\0\0\374\40!\0\377FH\0\377hk\0\377" + "\206\213\0\377\240\246\0\377\267\275\0\377\311\321\0\377\330\341\0\377\344" + "\354\0\377\344\354\0\377\330\341\0\377\311\321\0\377\267\275\0\377\240\246" + "\0\377\206\213\0\377hk\0\377FH\0\377\40!\0\377\0\0\0\375\0\0\0\366\0\0\0" + "\355\0\0\0\344\0\0\0\326\0\0\0\266\0\0\0\212\0\0\0Z\0\0\0/\0\0\0\33\0\0\0" + "\16\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\271\271\271\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\3\0\0\0\15\0\0\0\31\0\0\0'\0\0\0@\0\0\0e\0\0\0\212\0" + "\0\0\255\0\0\0\312\0\0\0\332\0\0\0\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0" + "\0\365\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0" + "\366\0\0\0\362\0\0\0\355\0\0\0\350\0\0\0\342\0\0\0\332\0\0\0\313\0\0\0\255" + "\0\0\0\212\0\0\0e\0\0\0@\0\0\0'\0\0\0\31\0\0\0\16\0\0\0\4\0\0\0\2\0\0\0\1" + "\0\0\0\1\0\0\0\1\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\2\0\0\0\6\0\0\0\17\0\0\0\31\0\0\0!\0\0\0,\0\0\0C\0\0\0]\0\0\0u\0\0\0\212" + "\0\0\0\235\0\0\0\255\0\0\0\272\0\0\0\305\0\0\0\314\0\0\0\314\0\0\0\305\0" + "\0\0\272\0\0\0\255\0\0\0\235\0\0\0\212\0\0\0u\0\0\0]\0\0\0C\0\0\0,\0\0\0" + "\"\0\0\0\31\0\0\0\20\0\0\0\7\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\21\21" + "\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0qqq\0---\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\7\0\0\0\15\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!\0\0\0$\0\0\0'\0\0\0)" + "\0\0\0)\0\0\0'\0\0\0%\0\0\0!\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\16\0\0\0\10" + "\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1---\0qqq\0\271\271" + "\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\15\15" + "\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31\31\0\15\15\15\0\5" + "\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0)))\0===\0UUU\0qqq\0" + "\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0", +}; + diff --git a/samples/graphics/rsx_Basic_Wallpaper/include/geometry.h b/samples/graphics/rsx_Basic_Wallpaper/include/geometry.h new file mode 100644 index 00000000..8be11b93 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/include/geometry.h @@ -0,0 +1,12 @@ +#ifndef __GEOMETRY_H__ +#define __GEOMETRY_H__ + +#include "mesh.h" + +SMeshBuffer* createCube(f32 size); +SMeshBuffer* createDonut(f32 outerRadius,f32 innerRadius,u32 polyCntX,u32 polyCntY); +SMeshBuffer* createSphere(f32 radius,u32 polyCntX,u32 polyCntY); +SMeshBuffer* createQuad(f32 size, float z); +SMeshBuffer* createQuad(Point3 P1, Point3 P2, Point3 P3, Point3 P4); + +#endif diff --git a/samples/graphics/rsx_Basic_Wallpaper/include/irrallocator.h b/samples/graphics/rsx_Basic_Wallpaper/include/irrallocator.h new file mode 100644 index 00000000..47feeab2 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/include/irrallocator.h @@ -0,0 +1,73 @@ +#ifndef __IRRALLOCATOR_H__ +#define __IRRALLOCATOR_H__ + +#include + +namespace irr +{ + namespace core + { + template< typename T > + class allocator + { + public: + T* allocate(u32 cnt) + { + return (T*)operator new(cnt*sizeof(T)); + } + + void deallocate(T *ptr) + { + operator delete(ptr); + } + + void construct(T *ptr,const T& elem) + { + new ((void*)ptr) T(elem); + } + + void destruct(T *ptr) + { + ptr->~T(); + } + }; + + template< typename T > + class allocatorRSX + { + public: + T* allocate(u32 cnt) + { + return (T*)operator new(cnt*sizeof(T)); + } + + void deallocate(T *ptr) + { + operator delete(ptr); + } + + void construct(T *ptr,const T& elem) + { + new ((void*)ptr) T(elem); + } + + void destruct(T *ptr) + { + ptr->~T(); + } + + protected: + void* operator new(size_t size) + { + return rsxMemalign(64,size); + } + + void operator delete(void *ptr) + { + rsxFree(ptr); + } + }; + } +} + +#endif diff --git a/samples/graphics/rsx_Basic_Wallpaper/include/irrarray.h b/samples/graphics/rsx_Basic_Wallpaper/include/irrarray.h new file mode 100644 index 00000000..e9c98f0d --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/include/irrarray.h @@ -0,0 +1,162 @@ +#ifndef __IRRARRAY_H__ +#define __IRRARRAY_H__ + +#include "irrallocator.h" + +namespace irr +{ + namespace core + { + template< class T, typename TAlloc = allocator > + class array + { + public: + array() : data(NULL),used(0),allocated(0),free_it(true),is_sorted(true) {}; + array(u32 start_cnt) : data(NULL),used(0),allocated(0),free_it(true),is_sorted(true) + { + reallocate(start_cnt); + } + array(const array& other) : data(NULL) + { + *this = other; + } + + ~array() + { + u32 i; + + if(free_it==true) { + for(i=0;iallocated) { + T e(elem); + u32 newAlloc; + + newAlloc = used + 1 + (allocated<500 ? (allocated<5 ? 5 : used) : used>>2); + + reallocate(newAlloc); + allocator.construct(&data[used++],e); + } else + allocator.construct(&data[used++],elem); + + is_sorted = false; + } + + void push_front(const T& elem) + { + insert(elem); + } + + void insert(const T& elem,u32 index = 0) + { + u32 i; + + if(index>used) return; + if((used + 1)>allocated) reallocate(used + 1); + + for(i=used;i>index;i--) { + if(iindex) allocator.destruct(&data[index]); + + allocator.construct(&data[index],elem); + is_sorted = false; + used++; + } + + void erase(u32 index) + { + u32 i; + + for(i=index+1;iused) reallocate(new_cnt); + used = new_cnt; + } + + void clear() + { + u32 i; + + for(i=0;i + +using namespace Vectormath::Aos; + +template< class T > +inline const T& min_(const T& a,const T& b) +{ + return a +inline const T& max_(const T& a,const T& b) +{ + return a +inline const T clamp(const T& val,const T& low,const T& high) +{ + return min_(max_(val,low),high); +} + +struct S3DVertex +{ + S3DVertex() {}; + S3DVertex(f32 x,f32 y,f32 z,f32 nx,f32 ny,f32 nz,f32 tu,f32 tv, u32 c) + : pos(x, y, z), nrm(nx, ny, nz), u(tu), v(tv), col(c) {}; + + inline S3DVertex& operator=(const S3DVertex& other) + { + pos = other.pos; + nrm = other.nrm; + u = other.u; + v = other.v; + col = other.col; + return *this; + } + + Vector3 pos; + Vector3 nrm; + f32 u, v; + u32 col; +}; + +template< class T > +class CMeshBuffer +{ +public: + CMeshBuffer() : indices(NULL),cnt_indices(0),vertices(NULL),cnt_vertices(0) {}; + + u16 *indices; + u32 cnt_indices; + + S3DVertex *vertices; + u32 cnt_vertices; +}; + +typedef CMeshBuffer SMeshBuffer; + +#endif diff --git a/samples/graphics/rsx_Basic_Wallpaper/include/rsxutil.h b/samples/graphics/rsx_Basic_Wallpaper/include/rsxutil.h new file mode 100644 index 00000000..2d2d3a39 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/include/rsxutil.h @@ -0,0 +1,48 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include + +#include + +#define DEFAULT_CB_SIZE 0x80000 // 512Kb default command buffer size +#define HOST_STATE_CB_SIZE 0x10000 // 64Kb state command buffer size (used for resetting certain default states) +#define HOST_ADDR_ALIGNMENT (1024*1024) + +#define GCM_PREPARED_BUFFER_INDEX 65 +#define GCM_BUFFER_STATUS_INDEX 66 +#define GCM_WAIT_LABEL_INDEX 255 + +#define MAX_BUFFER_QUEUE_SIZE 1 + +#define BUFFER_IDLE 0 +#define BUFFER_BUSY 1 + +#define FRAME_BUFFER_COUNT 4 + +extern u32 curr_fb; + +extern u32 display_width; +extern u32 display_height; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern void *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern void *color_buffer[FRAME_BUFFER_COUNT]; + +extern void *state_buffer; +extern u32 state_offset; + + +extern f32 aspect_ratio; + +void initScreen(u32 hostBufferSize); +void flip(); +void finish(); + +void setRenderTarget(u32 index); + +#endif // __RSXUTIL_H__ diff --git a/samples/graphics/rsx_Basic_Wallpaper/rsx_basic_wallpaper.png b/samples/graphics/rsx_Basic_Wallpaper/rsx_basic_wallpaper.png new file mode 100644 index 00000000..0488089d Binary files /dev/null and b/samples/graphics/rsx_Basic_Wallpaper/rsx_basic_wallpaper.png differ diff --git a/samples/graphics/rsx_Basic_Wallpaper/shaders/diffuse_specular_shader.vcg b/samples/graphics/rsx_Basic_Wallpaper/shaders/diffuse_specular_shader.vcg new file mode 100644 index 00000000..0e2e3570 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/shaders/diffuse_specular_shader.vcg @@ -0,0 +1,16 @@ +void main(float4 position : POSITION, + float4 color : COLOR0, + float2 texcoord : TEXCOORD0, + + uniform float4x4 modelViewProj, + + out float4 oPosition : POSITION, + out float4 oColor : COLOR0, + out float2 oTexCoord : TEXCOORD0 + ) + { + oPosition = mul(modelViewProj, position); + oColor = color; + oTexCoord = texcoord; + } + \ No newline at end of file diff --git a/samples/graphics/rsx_Basic_Wallpaper/shaders/scanlines.fcg b/samples/graphics/rsx_Basic_Wallpaper/shaders/scanlines.fcg new file mode 100644 index 00000000..35bcba34 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/shaders/scanlines.fcg @@ -0,0 +1,44 @@ +void main +( + float4 position : TEXCOORD0, + float3 normal : TEXCOORD1, + float2 texcoord : TEXCOORD0, + + uniform float4 scanline, + uniform sampler2D texture, + + out float4 oColor +) +{ + //Scanline parameters + //------------------------------------------------- + //scanline.x => scanline density, values 100 - 200 + //scanline.y => scanline depth / contrast, values 2 - 10 + //scanline.z => scanline brightnes, value 0 - 1 + //scanline.w => scanline type horizontal (value 1.0f), vertical (value 2.0f), none (val 0.0f) + + float dark = scanline.z; + + //pos Absolute from [0,1] to [-1,1] + float posxAbs = position.x * 2.0 - 1.0; + float posyAbs = position.y * 2.0 - 1.0; + + //vertical scanline + if (scanline.w > 0.19) { + dark += (sin(3.1415926f * posxAbs * scanline.x) / scanline.y); + } + else + //horizontal scanline + if (scanline.w > 0.09) { + dark += (sin(3.1415926f * posyAbs * scanline.x) / scanline.y); + + } + //no scanline + else + dark = 1.0f; + + float4 texel = tex2D(texture,texcoord); + float3 color = texel.xyz * dark; + + oColor = float4(color, texel.w); +} diff --git a/samples/graphics/rsx_Basic_Wallpaper/source/geometry.cpp b/samples/graphics/rsx_Basic_Wallpaper/source/geometry.cpp new file mode 100644 index 00000000..081f6ff8 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/source/geometry.cpp @@ -0,0 +1,302 @@ +#include + +#include "geometry.h" + + +SMeshBuffer* createQuad(Point3 P1, Point3 P2, Point3 P3, Point3 P4) +{ + u32 i; + SColor col(255, 255, 255, 255); + SMeshBuffer* buffer = new SMeshBuffer(); + const u16 u[6] = { 0,1,2, 0,3,1 }; + + buffer->indices.set_used(6); + + for (i = 0; i < 6; i++) buffer->indices[i] = u[i]; + + buffer->vertices.set_used(4); + + // position, normal, texture + buffer->vertices[0] = S3DVertex(P1.getX(), P1.getY(), P1.getZ(), -1, -1, -1, col, 0, 1); + buffer->vertices[1] = S3DVertex(P2.getX(), P2.getY(), P2.getZ(), 1, -1, -1, col, 1, 0); + buffer->vertices[2] = S3DVertex(P3.getX(), P3.getY(), P3.getZ(), 1, 1, -1, col, 0, 0); + buffer->vertices[3] = S3DVertex(P4.getX(), P4.getY(), P4.getZ(), -1, 1, -1, col, 1, 1); + + + rsxAddressToOffset(&buffer->vertices[0].pos, &buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm, &buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col, &buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u, &buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0], &buffer->ind_off); + + return buffer; +} + +SMeshBuffer* createQuad(f32 size, float z) +{ + u32 i; + SColor col(255, 255, 255, 255); + SMeshBuffer* buffer = new SMeshBuffer(); + const u16 u[6] = { 0,1,2, 0,3,1 }; + + buffer->indices.set_used(6); + + for (i = 0; i < 6; i++) buffer->indices[i] = u[i]; + + buffer->vertices.set_used(4); + + // position, normal, texture + buffer->vertices[0] = S3DVertex(-1.0, -1.0, z, -1, -1, -1, col, 0, 1); + buffer->vertices[1] = S3DVertex( 1.0, 1.0, z, 1, -1, -1, col, 1, 0); + buffer->vertices[2] = S3DVertex(-1.0, 1.0, z, 1, 1, -1, col, 0, 0); + buffer->vertices[3] = S3DVertex( 1.0, -1.0, z, -1, 1, -1, col, 1, 1); + + //centre and resize + //for (i = 0; i < 4; i++) { + // //center + // buffer->vertices[i].pos += Vector3(-0.5f, 0.5f, 0.0f); + // //resize + // buffer->vertices[i].pos *= size; + //} + + rsxAddressToOffset(&buffer->vertices[0].pos, &buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm, &buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col, &buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u, &buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0], &buffer->ind_off); + + return buffer; +} + +SMeshBuffer* createCube(f32 size) +{ + u32 i; + SColor col(255,255,255,255); + SMeshBuffer *buffer = new SMeshBuffer(); + const u16 u[36] = { 0,1,2, 0,2,3, 1,4,5, 1,5,2, 4,7,6, 4,6,5, + 7,0,3, 7,3,6, 9,2,5, 9,5,8, 0,10,11, 0,7,10}; + + buffer->indices.set_used(36); + for(i=0;i<36;i++) buffer->indices[i] = u[i]; + + buffer->vertices.set_used(12); + + buffer->vertices[0] = S3DVertex(0,0,0, -1,-1,-1, col, 1, 0); + buffer->vertices[1] = S3DVertex(1,0,0, 1,-1,-1, col, 1, 1); + buffer->vertices[2] = S3DVertex(1,1,0, 1, 1,-1, col, 0, 1); + buffer->vertices[3] = S3DVertex(0,1,0, -1, 1,-1, col, 0, 0); + buffer->vertices[4] = S3DVertex(1,0,1, 1,-1, 1, col, 1, 0); + buffer->vertices[5] = S3DVertex(1,1,1, 1, 1, 1, col, 0, 0); + buffer->vertices[6] = S3DVertex(0,1,1, -1, 1, 1, col, 0, 1); + buffer->vertices[7] = S3DVertex(0,0,1, -1,-1, 1, col, 1, 1); + buffer->vertices[8] = S3DVertex(0,1,1, -1, 1, 1, col, 1, 0); + buffer->vertices[9] = S3DVertex(0,1,0, -1, 1,-1, col, 1, 1); + buffer->vertices[10] = S3DVertex(1,0,1, 1,-1, 1, col, 0, 1); + buffer->vertices[11] = S3DVertex(1,0,0, 1,-1,-1, col, 0, 0); + + for(i=0;i<12;i++) { + buffer->vertices[i].pos -= Vector3(0.5f,0.5f,0.5f); + buffer->vertices[i].pos *= size; + } + + rsxAddressToOffset(&buffer->vertices[0].pos,&buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm,&buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col,&buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u,&buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0],&buffer->ind_off); + + return buffer; +} + +SMeshBuffer* createDonut(f32 outerRadius,f32 innerRadius,u32 polyCntX,u32 polyCntY) +{ + u32 i,x,y,level; + SColor col(100,255,255,255); + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + while(polyCntX*polyCntY>32767) { + polyCntX /= 2; + polyCntY /= 2; + } + + f32 ay = 0; + const f32 angleX = 2*M_PI/polyCntX; + const f32 angleY = 2*M_PI/polyCntY; + const u32 polyCntXpitch = polyCntX +1; + const u32 polyCntYpitch = polyCntY + 1; + + buffer->vertices.set_used(polyCntYpitch*polyCntXpitch); + buffer->indices.set_used(polyCntY*polyCntX*6); + + rsxAddressToOffset(&buffer->vertices[0].pos,&buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm,&buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col,&buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u,&buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0],&buffer->ind_off); + + i = 0; + for(y=0;y<=polyCntY;y++) { + f32 axz = 0; + + const f32 sinay = sinf(ay); + const f32 cosay = cosf(ay); + const f32 tu = (f32)y/(f32)polyCntY; + for(x=0;x<=polyCntX;x++) { + const Vector3 pos(static_cast((outerRadius - (innerRadius*cosf(axz)))*cosay), + static_cast((outerRadius - (innerRadius*cosf(axz)))*sinay), + static_cast(innerRadius*sinf(axz))); + + const Vector3 nrm(static_cast(-cosf(axz)*cosay), + static_cast(-cosf(axz)*sinay), + static_cast(sinf(axz))); + + buffer->vertices[i] = S3DVertex(pos,nrm,col,tu,(f32)x/(f32)polyCntX); + + axz += angleX; + i++; + } + ay += angleY; + } + + i = 0; + level = 0; + for(y=0;yindices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + return buffer; +} + +SMeshBuffer* createSphere(f32 radius,u32 polyCntX,u32 polyCntY) +{ + u32 i,p1,p2,level; + u32 x,y,polyCntXpitch; + const f32 RECIPROCAL_PI = 1.0f/M_PI; + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + if(polyCntX*polyCntY>32767) { + if(polyCntX>polyCntY) + polyCntX = 32767/polyCntY-1; + else + polyCntY = 32767/(polyCntX+1); + } + polyCntXpitch = polyCntX+1; + + buffer->vertices.set_used((polyCntXpitch*polyCntY) + 2); + buffer->indices.set_used((polyCntX*polyCntY)*6); + + rsxAddressToOffset(&buffer->vertices[0].pos,&buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm,&buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col,&buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u,&buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0],&buffer->ind_off); + + i = 0; + level = 0; + for(p1=0;p1indices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + const u32 polyCntSq = polyCntXpitch*polyCntY; + const u32 polyCntSq1 = polyCntSq+1; + const u32 polyCntSqM1 = (polyCntY-1)*polyCntXpitch; + + for(p2=0;p2indices[i++] = polyCntSq; + buffer->indices[i++] = p2; + buffer->indices[i++] = p2+1; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1+p2; + buffer->indices[i++] = polyCntSqM1+p2+1; + } + + buffer->indices[i++] = polyCntSq; + buffer->indices[i++] = polyCntX-1; + buffer->indices[i++] = polyCntX; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1; + buffer->indices[i++] = polyCntSqM1+polyCntX-1; + + f32 axz; + f32 ay = 0; + SColor col(100,255,255,255); + const f32 angelX = 2*M_PI/polyCntX; + const f32 angelY = M_PI/polyCntY; + + i = 0; + for(y=0;y(radius*cosf(axz)*sinay), static_cast(radius*cosf(ay)), static_cast(radius*sinf(axz)*sinay)); + + Vector3 normal = normalize(pos); + + f32 tu = 0.5F; + if(y==0) { + if(normal.getY()!=-1.0F && normal.getY()!=1.0F) + tu = static_cast(acosf(clamp(normal.getX()/sinay,-1.0f,1.0f))*0.5F*RECIPROCAL_PI); + if(normal.getZ()<0.0F) + tu = 1-tu; + } else + tu = buffer->vertices[i - polyCntXpitch].u; + + buffer->vertices[i] = S3DVertex(pos,normal,col,tu,static_cast(ay*RECIPROCAL_PI)); + axz += angelX; + i++; + } + buffer->vertices[i] = S3DVertex(buffer->vertices[i-polyCntX]); + buffer->vertices[i].u = 1.0F; + i++; + } + + buffer->vertices[i++] = S3DVertex(0.0F,radius,0.0F,0.0F,1.0F,0.0F,col,0.5F,0.0F); + buffer->vertices[i] = S3DVertex(0.0F,-radius,0.0F,0.0F,-1.0F,0.0F,col,0.5F,1.0F); + + return buffer; +} diff --git a/samples/graphics/rsx_Basic_Wallpaper/source/main.cpp b/samples/graphics/rsx_Basic_Wallpaper/source/main.cpp new file mode 100644 index 00000000..4ed8026c --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/source/main.cpp @@ -0,0 +1,383 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wall1_png_bin.h" + +#include + +#include +#include +#include + +#include "acid.h" +#include "mesh.h" +#include "rsxutil.h" + +#include "diffuse_specular_shader_vpo.h" +#include "scanlines_fpo.h" + +#define GCM_APP_WAIT_LABEL_INDEX 128 +#define HOSTBUFFER_SIZE (128*1024*1024) + +u32 running = 0; + +vu32 *wait_label = NULL; + +u32 fp_offset; +u32 *fp_buffer; + +u32* texture_buffer; +u32 texture_offset; + +pngData* png; + + +SMeshBuffer* quad = NULL; + +// vertex shader +rsxProgramConst *projMatrix; + +rsxProgramAttrib* mPosIndex = NULL; + +rsxProgramAttrib* mColIndex = NULL; + +// fragment shader +rsxProgramConst* scanlines; +rsxProgramAttrib* textureUnit; + +u32 color_index; +u32 position_index; + + +void *vp_ucode = NULL; +rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; + +void *fp_ucode = NULL; +rsxFragmentProgram *fpo = (rsxFragmentProgram*)scanlines_fpo; + +// setting default scanline parameters +Vector4 scanlineParams(200.0f, 2.0f, 0.7f, 0.0f); + +SYS_PROCESS_PARAM(1001, 0x100000); + +static u32 sLabelValue = 0; + +extern "C" { +static void program_exit_callback() +{ + finish(); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + +SMeshBuffer* createQuad(Point3 P1, Point3 P2, Point3 P3, Point3 P4) +{ + u32 i; + u32 col = 0xFFFFFFFF; + + SMeshBuffer* buffer = new SMeshBuffer(); + const u16 u[6] = { 0,1,2, 0,3,1 }; + + buffer->cnt_indices = 6; + buffer->indices = (u16*)rsxMemalign(128, buffer->cnt_indices * sizeof(u16)); + + for (i = 0; i < 6; i++) buffer->indices[i] = u[i]; + + buffer->cnt_vertices = 4; + buffer->vertices = (S3DVertex*)rsxMemalign(128, buffer->cnt_vertices * sizeof(S3DVertex)); + + // position, normal, texture + buffer->vertices[0] = S3DVertex(P1.getX(), P1.getY(), P1.getZ(), -1, -1, -1, 0, 1, col); + buffer->vertices[1] = S3DVertex(P2.getX(), P2.getY(), P2.getZ(), 1, -1, -1, 1, 0, col); + buffer->vertices[2] = S3DVertex(P3.getX(), P3.getY(), P3.getZ(), 1, 1, -1, 0, 0, col); + buffer->vertices[3] = S3DVertex(P4.getX(), P4.getY(), P4.getZ(), -1, 1, -1, 1, 1, col); + + + /*rsxAddressToOffset(&buffer->vertices[0].pos, &buffer->pos_off); + rsxAddressToOffset(&buffer->vertices[0].nrm, &buffer->nrm_off); + rsxAddressToOffset(&buffer->vertices[0].col, &buffer->col_off); + rsxAddressToOffset(&buffer->vertices[0].u, &buffer->uv_off); + rsxAddressToOffset(&buffer->indices[0], &buffer->ind_off);*/ + + return buffer; +} + +static void init_texture() +{ + + u32 i; + u8* buffer; + + //Init png texture + const u8* data = (u8*)png->bmp_out; + texture_buffer = (u32*)rsxMemalign(128, (png->height * png->pitch)); + + if (!texture_buffer) return; + + rsxAddressToOffset(texture_buffer, &texture_offset); + + buffer = (u8*)texture_buffer; + for (i = 0; i < png->height * png->pitch; i += 4) { + buffer[i + 0] = *data++; + buffer[i + 1] = *data++; + buffer[i + 2] = *data++; + buffer[i + 3] = *data++; + } +} + + +static void setTexture(u8 textureUnit) +{ + u32 width = png->width; + u32 height = png->height; + u32 pitch = png->pitch; + gcmTexture texture; + + if (!texture_buffer) return; + + rsxInvalidateTextureCache(gGcmContext, GCM_INVALIDATE_TEXTURE); + + texture.format = (GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN); + texture.mipmap = 1; + texture.dimension = GCM_TEXTURE_DIMS_2D; + texture.cubemap = GCM_FALSE; + texture.remap = ((GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_B_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_G_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_R_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_A_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_B << GCM_TEXTURE_REMAP_COLOR_B_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_G << GCM_TEXTURE_REMAP_COLOR_G_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_R << GCM_TEXTURE_REMAP_COLOR_R_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_A << GCM_TEXTURE_REMAP_COLOR_A_SHIFT)); + texture.width = width; + texture.height = height; + texture.depth = 1; + texture.location = GCM_LOCATION_RSX; + texture.pitch = pitch; + texture.offset = texture_offset; + rsxLoadTexture(gGcmContext, textureUnit, &texture); + rsxTextureControl(gGcmContext, textureUnit, GCM_TRUE, 0 << 8, 12 << 8, GCM_TEXTURE_MAX_ANISO_1); + rsxTextureFilter(gGcmContext, textureUnit, 0, GCM_TEXTURE_LINEAR, GCM_TEXTURE_LINEAR, GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureWrapMode(gGcmContext, textureUnit, GCM_TEXTURE_CLAMP_TO_EDGE, GCM_TEXTURE_CLAMP_TO_EDGE, GCM_TEXTURE_CLAMP_TO_EDGE, 0, GCM_TEXTURE_ZFUNC_LESS, 0); +} + + +static void setDrawEnv() +{ + u16 x,y,w,h; + f32 min, max; + f32 scale[4],offset[4]; + + x = 0; + y = 0; + w = display_width; + h = display_height; + min = 0.0f; + max = 1.0f; + scale[0] = w*0.5f; + scale[1] = h*-0.5f; + scale[2] = (max - min)*0.5f; + scale[3] = 0.0f; + offset[0] = x + w*0.5f; + offset[1] = y + h*0.5f; + offset[2] = (max + min)*0.5f; + offset[3] = 0.0f; + + rsxSetCallCommand(gGcmContext, state_offset); + while(*wait_label != sLabelValue) + usleep(10); + sLabelValue++; + + rsxSetViewport(gGcmContext,x, y, w, h, min, max, scale, offset); + rsxSetScissor(gGcmContext,x,y,w,h); +} + +void init_shader() +{ + u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + + projMatrix = rsxVertexProgramGetConst(vpo, "modelViewProj"); + + mPosIndex = rsxVertexProgramGetAttrib(vpo, "position"); + + mColIndex = rsxVertexProgramGetAttrib(vpo, "color"); + + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + + fp_buffer = (u32*)rsxMemalign(64,fpsize); + memcpy(fp_buffer,fp_ucode,fpsize); + + rsxAddressToOffset(fp_buffer,&fp_offset); + scanlines = rsxFragmentProgramGetConst(fpo, "scanline"); + textureUnit = rsxFragmentProgramGetAttrib(fpo, "texture"); + if (textureUnit) + printf("textureUnit OK\n"); + +} + + +void drawFrame() +{ + u32 i,offset; + SMeshBuffer* mesh = NULL; + + setDrawEnv(); + + + rsxSetClearColor(gGcmContext,0); + rsxSetClearDepthStencil(gGcmContext,0xffffff00); + rsxClearSurface(gGcmContext,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + rsxSetZControl(gGcmContext,0,1,1); + + for(i=0;i<8;i++) + rsxSetViewportClip(gGcmContext,i,display_width,display_height); + + Matrix4 tempMatrix = transpose(Matrix4::identity()); + + mesh = quad; + setTexture(textureUnit->index); + + rsxAddressToOffset(&mesh->vertices[0].pos, &offset); + rsxBindVertexArrayAttrib(gGcmContext, GCM_VERTEX_ATTRIB_POS, 0, offset, sizeof(S3DVertex), 3, GCM_VERTEX_DATA_TYPE_F32, GCM_LOCATION_RSX); + rsxAddressToOffset(&mesh->vertices[0].nrm, &offset); + rsxBindVertexArrayAttrib(gGcmContext, GCM_VERTEX_ATTRIB_NORMAL, 0, offset, sizeof(S3DVertex), 3, GCM_VERTEX_DATA_TYPE_F32, GCM_LOCATION_RSX); + rsxAddressToOffset(&mesh->vertices[0].u, &offset); + rsxBindVertexArrayAttrib(gGcmContext, GCM_VERTEX_ATTRIB_TEX0, 0, offset, sizeof(S3DVertex), 2, GCM_VERTEX_DATA_TYPE_F32, GCM_LOCATION_RSX); + rsxAddressToOffset(&mesh->vertices[0].col, &offset); + rsxBindVertexArrayAttrib(gGcmContext, GCM_VERTEX_ATTRIB_COLOR0, 0, offset, sizeof(S3DVertex), 4, GCM_VERTEX_DATA_TYPE_U8, GCM_LOCATION_RSX); + + rsxLoadVertexProgram(gGcmContext, vpo, vp_ucode); + rsxSetVertexProgramParameter(gGcmContext, vpo, projMatrix, (float*)&tempMatrix); + + rsxSetFragmentProgramParameter(gGcmContext, fpo, scanlines, (float*)&scanlineParams, fp_offset, GCM_LOCATION_RSX); + rsxLoadFragmentProgramLocation(gGcmContext, fpo, fp_offset, GCM_LOCATION_RSX); + + rsxSetWriteTextureLabel(gGcmContext, GCM_APP_WAIT_LABEL_INDEX, sLabelValue); + + rsxSetUserClipPlaneControl(gGcmContext, GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0], &offset); + rsxDrawIndexArray(gGcmContext, GCM_TYPE_TRIANGLES, offset, mesh->cnt_indices, GCM_INDEX_TYPE_16B, GCM_LOCATION_RSX); + + rsxSetWriteTextureLabel(gGcmContext, GCM_APP_WAIT_LABEL_INDEX, sLabelValue); + rsxFlushBuffer(gGcmContext); + +} + +int main(int argc,const char *argv[]) +{ + padInfo padinfo; + padData paddata; + + if (sysModuleLoad(SYSMODULE_PNGDEC) != 0) exit(0); + + printf("rsxtest started...\n"); + + initScreen(HOSTBUFFER_SIZE); + ioPadInit(7); + + wait_label = gcmGetLabelAddress(GCM_APP_WAIT_LABEL_INDEX); + *wait_label = sLabelValue; + + //Init background Image + png = new pngData; + pngLoadFromBuffer(wall1_png_bin, wall1_png_bin_size, png); + + //Create quad + Point3 P1 = Point3(-1.0, -1.0, 0); + Point3 P2 = Point3(1.0, 1.0, 0); + Point3 P3 = Point3(-1.0, 1.0, 0); + Point3 P4 = Point3(1.0, -1.0, 0); + quad = createQuad(P1, P2, P3, P4); + + + init_shader(); + init_texture(); + + DebugFont::init(); + DebugFont::setScreenRes(display_width, display_height); + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if(paddata.BTN_CIRCLE) + goto done; + if (paddata.BTN_CROSS) + scanlineParams.setW(0.1f); + if (paddata.BTN_SQUARE) + scanlineParams.setW(0.2f); + if (paddata.BTN_TRIANGLE) + scanlineParams.setW(0.0f); + } + + } + + drawFrame(); + int ypos = 53; + int xpos = 10; + DebugFont::setPosition(xpos, ypos); + DebugFont::setColor(0.5f, 1.0f, 0.5f, 1.0f); + + DebugFont::print("CROSS Button to enable horizontal scanlines"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("SQUARE Button to enable vertical scanlines"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("TRIANGLE Button to disable scanlines"); + ypos += 12; + DebugFont::setPosition(xpos, ypos); + DebugFont::print("CIRCLE Button to exit"); + + flip(); + } + +done: + printf("rsxtest done...\n"); + DebugFont::shutdown(); + finish(); + return 0; +} diff --git a/samples/graphics/rsx_Basic_Wallpaper/source/rsxutil.cpp b/samples/graphics/rsx_Basic_Wallpaper/source/rsxutil.cpp new file mode 100644 index 00000000..63715949 --- /dev/null +++ b/samples/graphics/rsx_Basic_Wallpaper/source/rsxutil.cpp @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "rsxutil.h" + +videoResolution vResolution; + +u32 curr_fb = 0; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +void *depth_buffer; + +u32 color_pitch; +u32 color_offset[FRAME_BUFFER_COUNT]; +void *color_buffer[FRAME_BUFFER_COUNT]; + +void *state_buffer; +u32 state_offset; + +f32 aspect_ratio; + +u32 fbOnDisplay = 0; +u32 fbFlipped = 0; +bool fbOnFlip = false; +sys_event_queue_t flipEventQueue; +sys_event_port_t flipEventPort; + +gcmSurface surface; + +static u32 sLabelVal = 1; +static RSXDebugFontRenderer *fontRenderer; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_1600x1080, + VIDEO_RESOLUTION_1440x1080, + VIDEO_RESOLUTION_1280x1080, + VIDEO_RESOLUTION_960x1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); + +extern "C" { +static void flipHandler(const u32 head) +{ + (void)head; + u32 v = fbFlipped; + + for (u32 i = fbOnDisplay; i != v; i=(i + 1)%FRAME_BUFFER_COUNT) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + fbOnDisplay = v; + fbOnFlip = false; + + sysEventPortSend(flipEventPort, 0, 0, 0); +} + +static void vblankHandler(const u32 head) +{ + (void)head; + u32 data; + u32 bufferToFlip; + u32 indexToFlip; + + data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + bufferToFlip = (data >> 8); + indexToFlip = (data & 0x07); + + if (!fbOnFlip) { + if (bufferToFlip != fbOnDisplay) { + s32 ret = gcmSetFlipImmediate(indexToFlip); + if (ret != 0) { + printf("flip immediate failed\n"); + return; + } + fbFlipped = bufferToFlip; + fbOnFlip = true; + } + } +} +} + +static void syncPPUGPU() +{ + vu32 *label = (vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX); + while(((curr_fb + FRAME_BUFFER_COUNT - ((*label)>>8))%FRAME_BUFFER_COUNT) > MAX_BUFFER_QUEUE_SIZE) { + sys_event_t event; + + sysEventQueueReceive(flipEventQueue, &event, 0); + sysEventQueueDrain(flipEventQueue); + } +} + +static void waitRSXFinish() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(gGcmContext); + + while(*(vu32*)gcmGetLabelAddress(GCM_WAIT_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitRSXFinish(); +} + +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + gcmGetTiledPitchSize(vResolution.width*4) + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + +void initFlipEvent() +{ + sys_event_queue_attr_t queueAttr = { SYS_EVENT_QUEUE_PRIO, SYS_EVENT_QUEUE_PPU, "\0" }; + + sysEventQueueCreate(&flipEventQueue, &queueAttr, SYS_EVENT_QUEUE_KEY_LOCAL, 32); + sysEventPortCreate(&flipEventPort, SYS_EVENT_PORT_LOCAL, SYS_EVENT_PORT_NO_NAME); + sysEventPortConnectLocal(flipEventPort, flipEventQueue); + + gcmSetFlipHandler(flipHandler); + gcmSetVBlankHandler(vblankHandler); +} + +void initRenderTarget() +{ + memset(&surface, 0, sizeof(gcmSurface)); + + surface.colorFormat = GCM_SURFACE_X8R8G8B8; + surface.colorTarget = GCM_SURFACE_TARGET_0; + surface.colorLocation[0] = GCM_LOCATION_RSX; + surface.colorOffset[0] = color_offset[curr_fb]; + surface.colorPitch[0] = color_pitch; + + for(u32 i=1; i< GCM_MAX_MRT_COUNT;i++) { + surface.colorLocation[i] = GCM_LOCATION_RSX; + surface.colorOffset[i] = color_offset[curr_fb]; + surface.colorPitch[i] = 64; + } + + surface.depthFormat = GCM_SURFACE_ZETA_Z24S8; + surface.depthLocation = GCM_LOCATION_RSX; + surface.depthOffset = depth_offset; + surface.depthPitch = depth_pitch; + + surface.type = GCM_SURFACE_TYPE_LINEAR; + surface.antiAlias = GCM_SURFACE_CENTER_1; + + surface.width = display_width; + surface.height = display_height; + surface.x = 0; + surface.y = 0; +} + +void setRenderTarget(u32 index) +{ + surface.colorOffset[0] = color_offset[index]; + rsxSetSurface(gGcmContext,&surface); +} + +void initDefaultStateCommands() +{ + rsxSetCurrentBuffer(nullptr, (u32*)state_buffer, HOST_STATE_CB_SIZE); + { + rsxSetBlendEnable(gGcmContext, GCM_FALSE); + rsxSetBlendFunc(gGcmContext, GCM_ONE, GCM_ZERO, GCM_ONE, GCM_ZERO); + rsxSetBlendEquation(gGcmContext, GCM_FUNC_ADD, GCM_FUNC_ADD); + rsxSetDepthWriteEnable(gGcmContext, GCM_TRUE); + rsxSetDepthFunc(gGcmContext, GCM_LESS); + rsxSetDepthTestEnable(gGcmContext, GCM_TRUE); + rsxSetClearDepthStencil(gGcmContext,0xffffff00); + rsxSetShadeModel(gGcmContext,GCM_SHADE_MODEL_SMOOTH); + rsxSetFrontFace(gGcmContext, GCM_FRONTFACE_CCW); + rsxSetClearReport(gGcmContext, GCM_ZPASS_PIXEL_CNT); + rsxSetZControl(gGcmContext, GCM_TRUE, GCM_FALSE, GCM_FALSE); + rsxSetZCullControl(gGcmContext, GCM_ZCULL_LESS, GCM_ZCULL_LONES); + rsxSetSCullControl(gGcmContext, GCM_SCULL_SFUNC_LESS, 1, 0xff); + rsxSetColorMaskMrt(gGcmContext, 0); + rsxSetColorMask(gGcmContext,GCM_COLOR_MASK_B | + GCM_COLOR_MASK_G | + GCM_COLOR_MASK_R | + GCM_COLOR_MASK_A); + rsxSetReturnCommand(gGcmContext); + } + rsxSetDefaultCommandBuffer(nullptr); +} + +void initScreen(u32 hostBufferSize) +{ + u32 zs_depth = 4; + u32 color_depth = 4; + u32 bufferSize = rsxAlign(HOST_ADDR_ALIGNMENT, (DEFAULT_CB_SIZE + HOST_STATE_CB_SIZE + hostBufferSize)); + + gcmInitDefaultFifoMode(GCM_DEFAULT_FIFO_MODE_CONDITIONAL); + + void *hostAddr = memalign(HOST_ADDR_ALIGNMENT, bufferSize); + rsxInit(nullptr, DEFAULT_CB_SIZE, bufferSize, hostAddr); + + state_buffer = (void*)((intptr_t)hostAddr + DEFAULT_CB_SIZE); + rsxAddressToOffset(state_buffer, &state_offset); + printf("state_cmd: %p [%08x]\n", state_buffer, state_offset); + + initDefaultStateCommands(); + initVideoConfiguration(); + + fontRenderer = new RSXDebugFontRenderer(gGcmContext); + + waitRSXIdle(); + + gcmSetFlipMode(GCM_FLIP_HSYNC); + + color_pitch = gcmGetTiledPitchSize(display_width*color_depth); + depth_pitch = gcmGetTiledPitchSize(display_width*zs_depth); + + u32 tileIndex = 0; + u32 bufferHeight = rsxAlign(GCM_TILE_LOCAL_ALIGN_HEIGHT, display_height); + u32 colorBufferSize = bufferHeight*color_pitch; + u32 depthBufferSize = bufferHeight*depth_pitch; + for (u32 i=0; i < FRAME_BUFFER_COUNT;i++, tileIndex++) { + bufferSize = rsxAlign(GCM_TILE_ALIGN_OFFSET, colorBufferSize); + color_buffer[i] = rsxMemalign(GCM_TILE_ALIGN_SIZE, bufferSize); + rsxAddressToOffset(color_buffer[i], &color_offset[i]); + gcmSetDisplayBuffer(i, color_offset[i], color_pitch, display_width, display_height); + gcmSetTileInfo(tileIndex, GCM_LOCATION_RSX, color_offset[i], bufferSize, color_pitch, GCM_COMPMODE_DISABLED, 0, 0); + gcmBindTile(tileIndex); + printf("fb[%d]: %p (%08x) [%dx%d] %d\n", i, color_buffer[i], color_offset[i], display_width, display_height, color_pitch); + } + + bufferSize = rsxAlign(GCM_TILE_ALIGN_OFFSET, depthBufferSize); + depth_buffer = rsxMemalign(GCM_TILE_ALIGN_SIZE, bufferSize); + rsxAddressToOffset(depth_buffer, &depth_offset); + gcmSetTileInfo(tileIndex, GCM_LOCATION_RSX, depth_offset, bufferSize, depth_pitch, GCM_COMPMODE_Z32_SEPSTENCIL, 0, 2); + gcmBindTile(tileIndex); + + gcmSetZcull(0, depth_offset, rsxAlign(64, display_width), rsxAlign(64, display_height), 0, GCM_ZCULL_Z24S8, GCM_SURFACE_CENTER_1, GCM_ZCULL_LESS, GCM_ZCULL_LONES, GCM_SCULL_SFUNC_LESS, 1, 0xff); + + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)) = (fbOnDisplay << 8); + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + fbOnDisplay)) = BUFFER_BUSY; + + curr_fb = (fbOnDisplay + 1)%FRAME_BUFFER_COUNT; + + initFlipEvent(); + initRenderTarget(); + + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); +} + +void flip() +{ + s32 qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + while (qid < 0) { + usleep(100); + qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + } + + rsxSetWriteBackendLabel(gGcmContext, GCM_PREPARED_BUFFER_INDEX, ((curr_fb << 8) | qid)); + rsxFlushBuffer(gGcmContext); + + syncPPUGPU(); + + curr_fb = (curr_fb + 1)%FRAME_BUFFER_COUNT; + + rsxSetWaitLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_IDLE); + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); + + setRenderTarget(curr_fb); +} + +void finish() +{ + rsxFinish(gGcmContext,1); + + u32 data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + u32 lastBuffer = (data >> 8); + while (lastBuffer != fbOnDisplay) + usleep(100); +} diff --git a/samples/graphics/rsxtest/include/rsxutil.h b/samples/graphics/rsxtest/include/rsxutil.h index f2fe1d1c..a9f2a683 100644 --- a/samples/graphics/rsxtest/include/rsxutil.h +++ b/samples/graphics/rsxtest/include/rsxutil.h @@ -2,14 +2,29 @@ #define __RSXUTIL_H__ #include +#include #define CB_SIZE 0x100000 #define HOST_SIZE (32*1024*1024) +#define FRAME_BUFFER_COUNT 2 + extern gcmContextData *context; + +extern u32 curr_fb; + extern u32 display_width; extern u32 display_height; -extern u32 curr_fb; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern u32 *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern u32 *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; void setRenderTarget(u32 index); void init_screen(void *host_addr,u32 size); diff --git a/samples/graphics/rsxtest/source/main.cpp b/samples/graphics/rsxtest/source/main.cpp index ce736554..91578c64 100644 --- a/samples/graphics/rsxtest/source/main.cpp +++ b/samples/graphics/rsxtest/source/main.cpp @@ -48,8 +48,6 @@ Point3 eye_pos = Point3(0.0f,0.0f,20.0f); Point3 eye_dir = Point3(0.0f,0.0f,0.0f); Vector3 up_vec = Vector3(0.0f,1.0f,0.0f); -f32 aspect_ratio = 4.0f/3.0f; - void *vp_ucode = NULL; rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; @@ -63,6 +61,27 @@ static SMeshBuffer *cube = NULL; SYS_PROCESS_PARAM(1001, 0x100000); +extern "C" { +static void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context,1); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} static void init_texture() { u32 i; @@ -335,7 +354,7 @@ static void setTexture() texture.offset = texture_offset; rsxLoadTexture(context,textureUnit_id,&texture); rsxTextureControl(context,textureUnit_id,GCM_TRUE,0<<8,12<<8,GCM_TEXTURE_MAX_ANISO_1); - rsxTextureFilter(context,textureUnit_id,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureFilter(context,textureUnit_id,0,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); rsxTextureWrapMode(context,textureUnit_id,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,0,GCM_TEXTURE_ZFUNC_LESS,0); } @@ -380,47 +399,32 @@ static void setDrawEnv() void init_shader() { u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + printf("vpsize: %d\n", vpsize); - vp_ucode = rsxVertexProgramGetUCode(vpo); - projMatrix_id = rsxVertexProgramGetConst(vpo,"projMatrix"); - modelViewMatrix_id = rsxVertexProgramGetConst(vpo,"modelViewMatrix"); - vertexPosition_id = rsxVertexProgramGetAttrib(vpo,"vertexPosition"); - vertexNormal_id = rsxVertexProgramGetAttrib(vpo,"vertexNormal"); - vertexTexcoord_id = rsxVertexProgramGetAttrib(vpo,"vertexTexcoord"); + projMatrix_id = rsxVertexProgramGetConstIndex(vpo,"projMatrix"); + modelViewMatrix_id = rsxVertexProgramGetConstIndex(vpo,"modelViewMatrix"); + vertexPosition_id = rsxVertexProgramGetAttribIndex(vpo,"vertexPosition"); + vertexNormal_id = rsxVertexProgramGetAttribIndex(vpo,"vertexNormal"); + vertexTexcoord_id = rsxVertexProgramGetAttribIndex(vpo,"vertexTexcoord"); + + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + printf("fpsize: %d\n", fpsize); - fp_ucode = rsxFragmentProgramGetUCode(fpo,&fpsize); fp_buffer = (u32*)rsxMemalign(64,fpsize); memcpy(fp_buffer,fp_ucode,fpsize); rsxAddressToOffset(fp_buffer,&fp_offset); - textureUnit_id = rsxFragmentProgramGetAttrib(fpo,"texture"); - eyePosition_id = rsxFragmentProgramGetConst(fpo,"eyePosition"); - globalAmbient_id = rsxFragmentProgramGetConst(fpo,"globalAmbient"); - lightPosition_id = rsxFragmentProgramGetConst(fpo,"lightPosition"); - lightColor_id = rsxFragmentProgramGetConst(fpo,"lightColor"); - shininess_id = rsxFragmentProgramGetConst(fpo,"shininess"); - Ks_id = rsxFragmentProgramGetConst(fpo,"Ks"); - Kd_id = rsxFragmentProgramGetConst(fpo,"Kd"); -} - -void program_exit_callback() -{ - gcmSetWaitFlip(context); - rsxFinish(context,1); -} - -void sysutil_exit_callback(u64 status,u64 param,void *usrdata) -{ - switch(status) { - case SYSUTIL_EXIT_GAME: - running = 0; - break; - case SYSUTIL_DRAW_BEGIN: - case SYSUTIL_DRAW_END: - break; - default: - break; - } + textureUnit_id = rsxFragmentProgramGetAttribIndex(fpo,"texture"); + eyePosition_id = rsxFragmentProgramGetConstIndex(fpo,"eyePosition"); + globalAmbient_id = rsxFragmentProgramGetConstIndex(fpo,"globalAmbient"); + lightPosition_id = rsxFragmentProgramGetConstIndex(fpo,"lightPosition"); + lightColor_id = rsxFragmentProgramGetConstIndex(fpo,"lightColor"); + shininess_id = rsxFragmentProgramGetConstIndex(fpo,"shininess"); + Ks_id = rsxFragmentProgramGetConstIndex(fpo,"Ks"); + Kd_id = rsxFragmentProgramGetConstIndex(fpo,"Kd"); } void drawFrame() @@ -442,7 +446,7 @@ void drawFrame() setDrawEnv(); rsxSetClearColor(context,color); - rsxSetClearDepthValue(context,0xffff); + rsxSetClearDepthStencil(context,0xffff); rsxClearSurface(context,GCM_CLEAR_R | GCM_CLEAR_G | GCM_CLEAR_B | @@ -450,7 +454,7 @@ void drawFrame() GCM_CLEAR_S | GCM_CLEAR_Z); - rsxZControl(context,0,1,1); + rsxSetZControl(context,0,1,1); for(i=0;i<8;i++) rsxSetViewportClip(context,i,display_width,display_height); @@ -468,26 +472,26 @@ void drawFrame() objLightPos = modelMatrixIT*lightPos; rsxAddressToOffset(&mesh->vertices[0].pos,&offset); - rsxBindVertexArrayAttrib(context,vertexPosition_id,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); - rsxBindVertexArrayAttrib(context,vertexNormal_id,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxAddressToOffset(&mesh->vertices[0].u,&offset); - rsxBindVertexArrayAttrib(context,vertexTexcoord_id,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); - rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); - rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + rsxSetVertexProgramParameterByIndex(context,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); - rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); - rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); @@ -514,26 +518,26 @@ void drawFrame() objLightPos = modelMatrixIT*lightPos; rsxAddressToOffset(&mesh->vertices[0].pos,&offset); - rsxBindVertexArrayAttrib(context,vertexPosition_id,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); - rsxBindVertexArrayAttrib(context,vertexNormal_id,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxAddressToOffset(&mesh->vertices[0].u,&offset); - rsxBindVertexArrayAttrib(context,vertexTexcoord_id,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); - rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); - rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + rsxSetVertexProgramParameterByIndex(context,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); - rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); - rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); @@ -586,9 +590,8 @@ int main(int argc,const char *argv[]) if(padinfo.status[i]){ ioPadGetData(i, &paddata); - if(paddata.BTN_CROSS){ - return 0; - } + if(paddata.BTN_CROSS) + goto done; } } @@ -597,5 +600,8 @@ int main(int argc,const char *argv[]) flip(); } - return 0; +done: + printf("rsxtest done...\n"); + program_exit_callback(); + return 0; } diff --git a/samples/graphics/rsxtest/source/rsxutil.cpp b/samples/graphics/rsxtest/source/rsxutil.cpp index 83aa5ef8..883c8fc2 100644 --- a/samples/graphics/rsxtest/source/rsxutil.cpp +++ b/samples/graphics/rsxtest/source/rsxutil.cpp @@ -5,14 +5,13 @@ #include #include -#include #include #include "rsxutil.h" #define GCM_LABEL_INDEX 255 -videoResolution res; +videoResolution vResolution; gcmContextData *context = NULL; u32 curr_fb = 0; @@ -26,8 +25,18 @@ u32 depth_offset; u32 *depth_buffer; u32 color_pitch; -u32 color_offset[2]; -u32 *color_buffer[2]; +u32 color_offset[FRAME_BUFFER_COUNT]; +u32 *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_960x1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); static u32 sLabelVal = 1; @@ -53,12 +62,65 @@ static void waitRSXIdle() waitFinish(); } +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + (u32)vResolution.width*4 + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + void setRenderTarget(u32 index) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = color_offset[index]; sf.colorPitch[0] = color_pitch; @@ -73,13 +135,13 @@ void setRenderTarget(u32 index) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = display_width; sf.height = display_height; @@ -91,41 +153,26 @@ void setRenderTarget(u32 index) void init_screen(void *host_addr,u32 size) { - context = rsxInit(CB_SIZE,size,host_addr); + u32 zs_depth = 4; + u32 color_depth = 4; - videoState state; - videoGetState(0,0,&state); + rsxInit(&context,CB_SIZE,size,host_addr); - videoGetResolution(state.displayMode.resolution,&res); - - videoConfiguration vconfig; - memset(&vconfig,0,sizeof(videoConfiguration)); - - vconfig.resolution = state.displayMode.resolution; - vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; - vconfig.pitch = res.width*sizeof(u32); + initVideoConfiguration(); waitRSXIdle(); - videoConfigure(0,&vconfig,NULL,0); - videoGetState(0,0,&state); - gcmSetFlipMode(GCM_FLIP_VSYNC); - display_width = res.width; - display_height = res.height; - - color_pitch = display_width*sizeof(u32); - color_buffer[0] = (u32*)rsxMemalign(64,(display_height*color_pitch)); - color_buffer[1] = (u32*)rsxMemalign(64,(display_height*color_pitch)); - - rsxAddressToOffset(color_buffer[0],&color_offset[0]); - rsxAddressToOffset(color_buffer[1],&color_offset[1]); + color_pitch = display_width*color_depth; + depth_pitch = display_width*zs_depth; - gcmSetDisplayBuffer(0,color_offset[0],color_pitch,display_width,display_height); - gcmSetDisplayBuffer(1,color_offset[1],color_pitch,display_width,display_height); + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + color_buffer[i] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + rsxAddressToOffset(color_buffer[i],&color_offset[i]); + gcmSetDisplayBuffer(i,color_offset[i],color_pitch,display_width,display_height); + } - depth_pitch = display_width*sizeof(u32); depth_buffer = (u32*)rsxMemalign(64,(display_height*depth_pitch)*2); rsxAddressToOffset(depth_buffer,&depth_offset); } diff --git a/samples/graphics/rsxtest_flip/Makefile b/samples/graphics/rsxtest_flip/Makefile new file mode 100644 index 00000000..aae67e84 --- /dev/null +++ b/samples/graphics/rsxtest_flip/Makefile @@ -0,0 +1,164 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +SHADERS := shaders +INCLUDES := include + +TITLE := RSX Test - PSL1GHT +APPID := RSX00003 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lsimdmath -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(SHADERS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +VCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.vcg))) +FCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.fcg))) + +VPOFILES := $(VCGFILES:.vcg=.vpo) +FPOFILES := $(FCGFILES:.fcg=.fpo) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(addsuffix .o,$(VPOFILES)) \ + $(addsuffix .o,$(FPOFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.vpo.o : %.vpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.fpo.o : %.fpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/rsxtest_flip/include/acid.h b/samples/graphics/rsxtest_flip/include/acid.h new file mode 100644 index 00000000..d1643518 --- /dev/null +++ b/samples/graphics/rsxtest_flip/include/acid.h @@ -0,0 +1,2939 @@ +/* GIMP RGBA C-Source image dump (acid.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +} acid = { + 128, 128, 4, + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\335\335\335\0\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31" + "\31\0\15\15\15\0\5\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0))" + ")\0===\0UUU\0qqq\0\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\345\345\345\0\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\15\15\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0qqq\0---\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\15\0\0\0" + "\23\0\0\0\30\0\0\0\35\0\0\0!\0\0\0$\0\0\0&\0\0\0(\0\0\0(\0\0\0'\0\0\0$\0" + "\0\0!\0\0\0\35\0\0\0\31\0\0\0\23\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0---\0qqq\0\271\271\271\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\17\0\0\0\30\0\0\0\40\0\0\0+\0\0\0B\0" + "\0\0\\\0\0\0t\0\0\0\211\0\0\0\234\0\0\0\254\0\0\0\271\0\0\0\304\0\0\0\313" + "\0\0\0\313\0\0\0\304\0\0\0\271\0\0\0\254\0\0\0\234\0\0\0\211\0\0\0t\0\0\0" + "\\\0\0\0B\0\0\0+\0\0\0!\0\0\0\30\0\0\0\17\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\21\21\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\2\0\0\0\14\0\0\0\30\0\0\0&\0\0\0?\0\0\0d\0\0\0\211\0\0\0\254\0\0\0\311" + "\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\354\0\0\0\361\0\0\0\365\0\0\0\370\0" + "\0\0\373\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\371\0\0\0\365\0\0\0\361\0\0" + "\0\355\0\0\0\347\0\0\0\341\0\0\0\331\0\0\0\312\0\0\0\254\0\0\0\211\0\0\0" + "d\0\0\0?\0\0\0&\0\0\0\30\0\0\0\15\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0QQQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0\33\0\0" + "\0.\0\0\0Y\0\0\0\211\0\0\0\265\0\0\0\325\0\0\0\343\0\0\0\354\0\0\0\365\0" + "\0\0\374\40!\0\377FH\0\377hk\0\377\206\213\0\377\240\246\0\377\267\275\0" + "\377\311\321\0\377\330\341\0\377\344\354\0\377\344\354\0\377\330\341\0\377" + "\311\321\0\377\267\275\0\377\240\246\0\377\206\213\0\377hk\0\377FH\0\377" + "\40!\0\377\0\0\0\375\0\0\0\365\0\0\0\355\0\0\0\343\0\0\0\326\0\0\0\266\0" + "\0\0\211\0\0\0Z\0\0\0/\0\0\0\33\0\0\0\16\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0" + "\0\0\0\0QQQ\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\255\255\255\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0" + "\27\0\0\0-\0\0\0]\0\0\0\224\0\0\0\304\0\0\0\336\0\0\0\354\0\0\0\367\30\31" + "\0\376QT\0\377\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0" + "\376\0\0\0\367\0\0\0\354\0\0\0\337\0\0\0\305\0\0\0\224\0\0\0]\0\0\0-\0\0" + "\0\30\0\0\0\11\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0===\0\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265" + "\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\15\0\0\0!\0\0\0H\0\0\0\204" + "\0\0\0\274\0\0\0\336\0\0\0\357\0\0\0\373BD\0\377\206\213\0\377\306\315\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\306\315\0\377\206\213\0\377BD\0\377\0\0\0\373" + "\0\0\0\357\0\0\0\337\0\0\0\275\0\0\0\204\0\0\0I\0\0\0!\0\0\0\15\0\0\0\3\0" + "\0\0\1\0\0\0\0\0\0\0\0===\0\265\265\265\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0QQ" + "Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0'\0\0\0[\0\0\0\236\0\0" + "\0\324\0\0\0\353\0\0\0\371FH\0\377\225\232\0\377\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\340\350\0\377\225\232\0\377FH\0\377\0\0\0\371\0" + "\0\0\353\0\0\0\324\0\0\0\236\0\0\0\\\0\0\0'\0\0\0\17\0\0\0\3\0\0\0\1\0\0" + "\0\0\0\0\0\0QQQ\0\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0(\0\0\0c\0\0\0\250" + "\0\0\0\332\0\0\0\361$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\361\0\0\0" + "\333\0\0\0\251\0\0\0c\0\0\0(\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0yyy" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0)))\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\0\0\0$\0\0\0_" + "\0\0\0\250\0\0\0\334\0\0\0\364BD\0\376\244\252\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0" + "\335\0\0\0\250\0\0\0`\0\0\0%\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\0)))\0\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\4\0\0\0\34\0\0\0O\0\0\0\234\0\0\0\332\0\0\0\364FH\0\376\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH\0\376\0\0\0\364\0" + "\0\0\332\0\0\0\234\0\0\0P\0\0\0\34\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0qqq\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315" + "\0""555\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0""0\0\0\0\203\0\0\0\321\0" + "\0\0\360+-\0\375\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377+-\0\375" + "\0\0\0\360\0\0\0\322\0\0\0\203\0\0\0""1\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0" + """555\0\315\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\4\0\0\0\40\0\0\0`\0\0\0\262\0\0\0\346\0\0\0\374~\203\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\374\0\0\0\347\0\0\0\263\0\0\0a\0\0\0\40\0\0\0\5\0\0" + "\0\1\0\0\0\0\1\1\1\0\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0" + "\0/\0\0\0\207\0\0\0\326\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\311\321\0\377FH\0\376\0\0\0\366\0\0\0\327\0\0\0\207\0\0\0" + """0\0\0\0\14\0\0\0\2\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375" + "\375\375\0UUU\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\30\0\0\0S\0\0\0\252\0\0\0\345" + "\0\0\0\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\374\0\0\0\346" + "\0\0\0\253\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\0UUU\0\375\375\375\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0==" + "=\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\"\0\0\0q\0\0\0\316\0\0\0\363/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\364\0\0\0\316\0\0\0q\0\0\0\"\0\0\0\5\0\0\0\1\0\0\0\0===\0\351\351" + "\351\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\0\0\0\0\1" + "\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\\`\0\377\0\0\0\373\0\0\0\332\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1\0\0" + "\0\1---\0\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\331\331\331\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0""2\0\0\0\225\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\342\0\0\0" + "\226\0\0\0""2\0\0\0\11\0\0\0\1\0\0\0\1%%%\0\331\331\331\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\335\335\335\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0?\0\0\0\243\0\0\0\350\2\2\0\375\240\246\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377" + "\2\2\0\375\0\0\0\350\0\0\0\244\0\0\0@\0\0\0\15\0\0\0\2\0\0\0\1%%%\0\335\335" + "\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\0\0\0\0\1\0\0\0\16" + "\0\0\0H\0\0\0\257\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\355\0\0\0\257\0\0\0H\0\0\0" + "\17\0\0\0\2\0\0\0\1---\0\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\375\375\375\0===\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0H\0\0\0\264\0\0\0\360\40!\0\376\306\315\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\40!\0\376\0\0\0" + "\360\0\0\0\265\0\0\0I\0\0\0\15\0\0\0\1\0\0\0\1===\0\375\375\375\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0?\0\0\0\257\0\0\0\360$%\0\376\315\325\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\315\325" + "\0\377$%\0\377\0\0\0\360\0\0\0\257\0\0\0@\0\0\0\11\0\0\0\1\0\0\0\1UUU\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0""2" + "\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\355\0\0\0\244\0\0\0""2\0" + "\0\0\6\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\0\0\0\0\0\0\0\0\0\0" + "\0\4\0\0\0*\0\0\0\225\0\0\0\350\25\25\0\376\306\315\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\25" + "\25\0\376\0\0\0\350\0\0\0\226\0\0\0*\0\0\0\5\0\0\0\1\0\0\0\0\235\235\235" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315\0" + "\1\1\1\0\0\0\0\0\0\0\0\3\0\0\0\"\0\0\0\205\0\0\0\342\2\2\0\375\267\275\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\2\2\0\375\0\0\0\342\0\0\0" + "\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\0\315\315\315\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374" + "\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377\13\14\0\377UX\0\377" + "\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0S\0\0\0\316\0\0\0\373\202\207" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\310\317\0\3779<\0\377\0\0\0\3779<\0\377\310\317\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\306\315\0\377!\"\0\377\0\0\0\377\0\0\0\377\4\4\0\377PT\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\316\0\0\0S\0\0\0\14\0\0\0\1\0\0\0\0qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\0\0\0\0\4\0\0\0/\0\0\0\253\0\0\0\364\\`\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377/2\0\377\0\0\0\377\0\0\0\377\0\0\0\377/2\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0" + "\253\0\0\0""0\0\0\0\5\0\0\0\1\0\0\0\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0)))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0" + "\0\207\0\0\0\345/1\0\376\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\207\215\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\357\370\0\377/1\0\376\0\0\0\346" + "\0\0\0\207\0\0\0\40\0\0\0\3\0\0\0\1)))\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0`\0\0\0\326\0\0\0\374\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\5\5\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\374\0\0\0" + "\327\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\0yyy\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0" + "\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0" + "\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\0\321\321\321\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0" + "\0\0\0\0\0\0\2\0\0\0\34\0\0\0\203\0\0\0\346FH\0\376\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\376" + "\0\0\0\347\0\0\0\204\0\0\0\34\0\0\0\2\0\0\0\1QQQ\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0\0\0\0" + "\0\0\0\12\0\0\0O\0\0\0\321\0\0\0\374\311\321\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321" + "\0\377\0\0\0\374\0\0\0\322\0\0\0P\0\0\0\13\0\0\0\1\0\0\0\0\265\265\265\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0" + "\0%\0\0\0\234\0\0\0\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\361\0\0\0\234\0\0\0%\0\0\0\3\0\0\0\1===\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0_\0" + "\0\0\332+-\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377+-\0\375\0\0\0\332\0\0\0`\0\0\0\17\0\0\0\1\0\0\0\0\255\255" + "\255\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0(\0\0\0\250\0\0\0" + "\363\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\244\252\0\377\0\0\0\364\0\0\0\250\0\0\0)\0\0\0\3\0\0\0\1=" + "==\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0c\0\0\0\334FH" + "\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\17\0\0\0" + "\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'\0\0\0\251\0\0\0\363\267\275" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0" + "(\0\0\0\3\0\0\0\1QQQ\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377BD\0\376\0\0\0\333\0\0\0\\" + "\0\0\0\16\0\0\0\1\0\0\0\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\2\0\0\0!\0\0\0\235\0\0\0\361\244\252\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\361\0" + "\0\0\236\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\35\35\35\0\0\0\0\0\0\0\0\10\0\0\0H\0\0\0\324$%\0\375\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377$%\0\375\0" + "\0\0\325\0\0\0I\0\0\0\11\0\0\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0\203\0\0\0\353~\203\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203" + "\0\377\0\0\0\353\0\0\0\204\0\0\0\27\0\0\0\1\0\0\0\0\265\265\265\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\325\335\0\377\0\0\0\371\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\336FH\0\376\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0]\0\0\0\16\0\0\0\1\21\21\21\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0\0\0\0\0\0\0\0\0\0\0\0\32\0\0\0\223\0\0\0\357\225\232\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\357\0\0\0\224\0\0\0\33\0" + "\0\0\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\340\350\0\377\0\0\0\373\0\0\0\305\0\0\0" + "/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0---\0\0\0\0\0\0\0\0\14\0\0\0Y\0\0\0\336BD\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\337\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0" + "\0\0\211\0\0\0\30\0\0\0\1\0\0\0\0\345\345\345\0\377\377\377\0\377\377\377" + "\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\265\0\0\0\367\306\315\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377" + "\0\0\0\367\0\0\0\266\0\0\0&\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377\377\377\0\377\377" + "\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343QT\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT" + "\0\377\0\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0" + "\15\15\15\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15\15\15\0\377\377\377" + "\0\335\335\335\0\0\0\0\0\0\0\0\0\0\0\0\40\0\0\0\254\0\0\0\365\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0\0!\0\0\0\1\0\0\0\0\335" + "\335\335\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0+\0\0\0\311\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\210\215\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\7\7\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\344\354\0\377\0\0\0\374\0\0\0\312\0\0\0,\0\0\0\2" + "\0\0\0\1\265\265\265\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0B\0\0\0\331\40" + "!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\20\21\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\40!\0\377\0\0\0" + "\332\0\0\0B\0\0\0\7\0\0\0\1\221\221\221\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0" + "\0\0\341FH\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\37702\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\37702\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377!\"\0\377\0\0" + "\0\377\0\0\0\377\4\4\0\377PS\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0\0\0\342\0" + "\0\0]\0\0\0\15\0\0\0\1qqq\0UUU\0\0\0\0\0\0\0\0\23\0\0\0t\0\0\0\347hk\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\3779<\0\377\0" + "\0\0\3779<\0\377\310\317\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377" + "\13\14\0\377UX\0\377\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0" + "\0\0u\0\0\0\23\0\0\0\1UUU\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206" + "\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===" + "\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0\361\240\246\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246" + "\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0\1)))\0\31\31\31\0\0\0\0\0\0\0\0" + "\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0\15\15\15\0\0\0\0\0\0\0\0$\0\0\0\271\0" + "\0\0\370\311\321\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\311\321\0\377\0\0\0\371\0\0\0\272\0\0\0" + "$\0\0\0\1\15\15\15\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\1\1\1" + "\0\0\0\0\0\0\0\0(\0\0\0\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\313\0\0\0)\0\0\0\1\1\1\1\0\1\1\1\0\0\0\0\0\0\0\0(\0\0\0" + "\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\344\354\0\377\0\0\0\375\0\0\0\313\0\0" + "\0)\0\0\0\1\1\1\1\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\15\15" + "\15\0\0\0\0\0\0\0\0$\0\0\0\271\0\0\0\370\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321\0" + "\377\0\0\0\371\0\0\0\272\0\0\0$\0\0\0\1\15\15\15\0\31\31\31\0\0\0\0\0\0\0" + "\0\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0" + "\361\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\240\246\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0" + "\1)))\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206" + "\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===\0UUU\0\0\0\0\0\0\0\0\23" + "\0\0\0t\0\0\0\347hk\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0\0\0u\0\0\0\23\0\0\0" + "\1UUU\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\341FH\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0" + "\0\0\342\0\0\0]\0\0\0\15\0\0\0\1qqq\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0" + "B\0\0\0\331\40!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\40!\0\377\0\0\0\332\0\0\0C\0\0\0\7\0\0\0\1\221" + "\221\221\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0,\0\0\0\312\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\312\0\0\0,\0\0\0\2\0\0\0\1\265\265\265\0\335\335\335\0\0" + "\0\0\0\0\0\0\1\0\0\0!\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0" + "\0\"\0\0\0\1\0\0\0\1\335\335\335\0\377\377\377\0\15\15\15\0\0\0\0\0\0\0\0" + "\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15" + "\15\15\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343" + "QT\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT\0\377\0" + "\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0qqq\0\0" + "\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377" + "\377\377\0\377\377\377\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\266\0" + "\0\0\367\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\335\345\0\377\261\270\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\0\0\0\370" + "\0\0\0\266\0\0\0'\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377\377\377" + "\0\345\345\345\0\0\0\0\0\0\0\0\1\0\0\0\31\0\0\0\212\0\0\0\354\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\322\332\0\377\36" + "\37\0\377\10\10\0\377\265\273\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\316\326\0\377\230\235\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\0" + "\0\0\1\345\345\345\0\377\377\377\0\377\377\377\0\377\377\377\0---\0\0\0\0" + "\0\0\0\0\14\0\0\0Z\0\0\0\337BD\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\1\1\0\377\201\206\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0\377\17" + "\20\0\377\2\2\0\377\224\231\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\340\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377SV\0\377\353\364\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377w{\0\377\1\1\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377;>\0\377<>\0\377<>\0\377\303\312\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\0\0\0\373\0\0\0\305\0\0\0/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\1" + "\0\0\0\33\0\0\0\224\0\0\0\357\225\232\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\26\26\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377.0\0\377" + "\330\340\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\345\355\0\377?A" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\1\1\0\377\310\320\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\360\0\0\0" + "\225\0\0\0\34\0\0\0\1\0\0\0\1\271\271\271\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0" + "]\0\0\0\337FH\0\376\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\257\266\0\377\4\4\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\16\17\0\377\265\273" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\277\306\0\377\23\24\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\0\377\226\233\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0^\0\0\0\16\0\0\0\1\21\21" + "\21\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\300\307\0\377\30\31\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377z\177\0\377\355\366" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377pt\0\377\2\2\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2" + "\0\377\235\243\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\325\335\0\377\0\0\0\371" + "\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\1\0\0\0\27\0\0\0\204\0\0\0\353~\203\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\330\341\0\377&'\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\25\25\0\377\277\306\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\377" + "-/\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\25\25\0\377\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377~\203\0\377\0\0\0\354\0\0\0\205\0\0\0\30\0\0\0\1\0\0\0\1\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\35\35\35\0\0\0\0\0\0\0\0\11\0\0\0I\0\0\0\324" + "$%\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\350\360\0\377EG\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\2\2\0\377mq\0\377\352\363\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\342\352\0" + "\377fi\0\377\2\2\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377*,\0\377\333\344\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377$%\0\375\0\0\0\325\0\0\0J\0\0\0\11\0\0" + "\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\2" + "\0\0\0!\0\0\0\236\0\0\0\361\244\252\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377tx\0\377\1\1\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\36\0\377\235\243\0" + "\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\220" + "\225\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377gj\0\377\353\364\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\362\0" + "\0\0\237\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\1\0\0\0\16\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0" + "\377\13\14\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377-/\0\377\273\302\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355\366\0\377\177\204" + "\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\11\12\0\377\246\254\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "BD\0\376\0\0\0\333\0\0\0]\0\0\0\17\0\0\0\1\0\0\0\1\331\331\331\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'" + "\0\0\0\251\0\0\0\363\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\346\356\0\377HK\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377=?\0\377\247\255\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377\206\213\0\377" + "\34\35\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377/1\0\377\325\335\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0(\0\0\0\3\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0" + "\0\0\0\0\0\0\1\0\0\0\20\0\0\0d\0\0\0\335FH\0\375\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\211\217\0\377\10\11\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\14\15\0\377qu\0\377" + "\343\353\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\356\367\0\377\254\263\0\377hl\0\377\5\5\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\16\17\0\377\231\237\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\20\0\0\0\1\0\0\0\1\271\271\271" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0)\0\0\0\251\0\0\0\363\244\252\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\346\356\0\377fi\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\4\4\0\377BD\0\377\206\213\0\377\301\310\0\377\354\365\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340\350\0\377\230\235\0" + "\377^b\0\377\25\25\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377Z^" + "\0\377\335\345\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377" + "\0\0\0\364\0\0\0\251\0\0\0*\0\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255" + "\255\255\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0`\0\0\0\332+-\0\375\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\254\263\0\377\25\25\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\13\0\377;>\0\377UX\0" + "\377lp\0\377x|\0\377x|\0\377x|\0\377bf\0\377HK\0\377\6\6\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37713\0\377\275\304" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "+-\0\375\0\0\0\332\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\1\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0%\0\0\0\234\0\0\0" + "\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\216\223\0\377\16\17\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + ",.\0\377\247\255\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0\361\0\0\0\235\0\0\0%\0" + "\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265" + "\265\265\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0P\0\0\0\322\0\0\0\374\311\321\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355" + "\366\0\377\213\221\0\377\17\20\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\37724\0\377\246\254\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\311\321\0\377\0\0\0\374\0\0\0\323\0\0\0Q\0\0\0\14\0\0\0\1\0\0\0\1" + "\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0\34\0\0\0\204\0\0\0\347FH\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\356\367\0\377\235\243\0\377(*\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\5\5\0" + "\377hl\0\377\270\276\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377FH\0\377\0\0\0\347\0\0\0\204\0\0\0\35\0\0\0\2\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321" + "\321\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\320\330\0\377\\`\0\377\7" + "\7\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\3778:\0\377\226\233\0" + "\377\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\206\213\0\377\0\0\0\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\1" + "\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0a\0\0\0" + "\327\0\0\0\374\276\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\357\370\0\377\245\253\0\377w{\0\377:=\0\377\3\3\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377*,\0\377dh\0\377\217\224\0\377\350" + "\361\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\375\0\0\0\330\0\0\0b\0\0" + "\0\20\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + ")))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0\0\207\0\0\0\346/1\0\376\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\357\370\0\377\305\314\0\377\247\255\0\377" + "\212\220\0\377x}\0\377x}\0\377x}\0\377x}\0\377{\200\0\377\240\246\0\377\270" + "\276\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377/1\0\376\0\0\0\347\0\0\0\210\0\0\0!\0\0\0\3\0\0\0" + "\1)))\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""0\0\0\0\253\0\0\0\364\\`\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0\254\0\0\0""1" + "\0\0\0\6\0\0\0\1\0\0\0\1\265\265\265\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\1\0\0\0\14\0\0" + "\0T\0\0\0\317\0\0\0\373\202\207\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\317\0\0\0T\0\0\0\15\0\0\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374\240\246\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\315\315\315\0\1\1\1\0\0\0\0\1\0\0\0\4\0\0\0\"\0" + "\0\0\205\0\0\0\342\2\2\0\375\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267" + "\275\0\377\2\2\0\375\0\0\0\342\0\0\0\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\1\315" + "\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235" + "\235\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0+\0\0\0\226\0\0\0\350\25\25\0\376\306" + "\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\306\315\0\377\25\25\0\376\0\0\0\351\0\0\0\226\0\0\0+\0\0\0\6\0" + "\0\0\1\0\0\0\1\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0" + """2\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\356\0\0\0\245\0\0\0""3\0" + "\0\0\7\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0" + "\0\0\0\0\0\0\1\0\0\0\11\0\0\0@\0\0\0\260\0\0\0\360$%\0\376\315\325\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377$%\0\377\0\0\0\361\0\0\0\260\0\0\0A\0\0\0" + "\12\0\0\0\1\0\0\0\1UUU\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\375\375\375\0===\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0H\0\0\0\264\0\0\0\360" + "\40!\0\376\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\306\315\0\377\40!\0\376\0\0\0\361\0\0\0\265\0\0\0I\0\0\0\16" + "\0\0\0\2\0\0\0\1===\1\375\375\375\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\1\0\0\0\2\0\0\0\17" + "\0\0\0I\0\0\0\260\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\356\0\0\0\260\0\0\0I\0\0\0" + "\20\0\0\0\2\0\0\0\1---\1\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "%%%\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0@\0\0\0\244\0\0\0\350\2\2\0\375\240\246" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\240\246\0\377\2\2\0\375\0\0\0\351\0\0\0\245\0\0\0@\0\0\0\16" + "\0\0\0\2\0\0\0\1%%%\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\331\331\331\0%%%\0\0\0\0\1\0\0\0\2\0\0\0\12\0\0\0""2\0\0\0\226" + "\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\343\0\0\0\226\0\0\0""3\0\0\0" + "\12\0\0\0\2\0\0\0\1%%%\1\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\1\0\0" + "\0\1\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357" + "\370\0\377\\`\0\377\0\0\0\373\0\0\0\333\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1" + "\0\0\0\1---\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0" + "===\0\0\0\0\1\0\0\0\1\0\0\0\5\0\0\0#\0\0\0r\0\0\0\317\0\0\0\364/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\365\0\0\0\317\0\0\0r\0\0\0#\0\0\0\6\0\0\0\1\0\0\0\1===\1\351\351\351" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375\375\375" + "\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0S\0\0\0\253\0\0\0\346\0\0\0" + "\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\375\0\0\0\347\0\0\0" + "\254\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\1UUU\0\375\375\375\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0/\0\0\0\210\0" + "\0\0\327\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\311\321\0\377FH\0\377\0\0\0\367\0\0\0\330\0\0\0\210\0\0\0""0\0\0\0\15\0" + "\0\0\3\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\5\0" + "\0\0!\0\0\0a\0\0\0\263\0\0\0\347\0\0\0\374~\203\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0" + "\374\0\0\0\347\0\0\0\264\0\0\0b\0\0\0!\0\0\0\6\0\0\0\1\0\0\0\1\1\1\1\1\235" + "\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\315\315\315\0""555\0\0\0\0\0\0\0\0\1\0" + "\0\0\3\0\0\0\17\0\0\0""1\0\0\0\204\0\0\0\322\0\0\0\361+-\0\375\244\252\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\244\252\0\377+-\0\375\0\0\0\361\0\0\0\323\0\0\0" + "\204\0\0\0""1\0\0\0\20\0\0\0\3\0\0\0\1\0\0\0\1""555\0\315\315\315\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0" + "\0\0\1\0\0\0\1\0\0\0\5\0\0\0\34\0\0\0P\0\0\0\234\0\0\0\332\0\0\0\364FH\0" + "\376\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH" + "\0\376\0\0\0\364\0\0\0\333\0\0\0\235\0\0\0Q\0\0\0\35\0\0\0\5\0\0\0\1\0\0" + "\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0)))\0\0" + "\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0%\0\0\0`\0\0\0\251\0\0\0\335\0\0\0\364" + "BD\0\376\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0\336\0\0\0\251\0\0\0a\0\0\0&" + "\0\0\0\14\0\0\0\3\0\0\0\1\0\0\0\1)))\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0" + "\0\1\0\0\0\1\0\0\0\3\0\0\0\17\0\0\0)\0\0\0d\0\0\0\251\0\0\0\333\0\0\0\362" + "$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\362\0\0\0\334\0\0\0\252\0\0\0" + "d\0\0\0)\0\0\0\17\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\321\321\321\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1\0" + "\0\0\4\0\0\0\20\0\0\0(\0\0\0\\\0\0\0\236\0\0\0\325\0\0\0\354\0\0\0\372FH" + "\0\377\225\232\0\377\340\350\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\225\232\0\377FH\0\377\0\0\0\372\0\0\0\354\0\0\0\325\0\0\0\236" + "\0\0\0]\0\0\0(\0\0\0\20\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\321\321\321" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\265\265\265\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0" + "\16\0\0\0\"\0\0\0I\0\0\0\205\0\0\0\275\0\0\0\337\0\0\0\360\0\0\0\374BD\0" + "\377\206\213\0\377\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\206" + "\213\0\377BD\0\377\0\0\0\374\0\0\0\360\0\0\0\340\0\0\0\276\0\0\0\205\0\0" + "\0J\0\0\0\"\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1===\0\265\265\265\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255\255" + "\255\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\11\0\0\0\27\0\0\0-\0\0" + "\0]\0\0\0\225\0\0\0\305\0\0\0\337\0\0\0\355\0\0\0\370\30\31\0\376QT\0\377" + "\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0\376\0\0\0\370" + "\0\0\0\355\0\0\0\340\0\0\0\306\0\0\0\225\0\0\0^\0\0\0-\0\0\0\30\0\0\0\11" + "\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1===\0\255\255\255\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\271\271\271\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0\33\0\0\0/\0\0\0Z\0\0\0\212\0\0\0\266\0\0" + "\0\326\0\0\0\344\0\0\0\355\0\0\0\365\0\0\0\374\40!\0\377FH\0\377hk\0\377" + "\206\213\0\377\240\246\0\377\267\275\0\377\311\321\0\377\330\341\0\377\344" + "\354\0\377\344\354\0\377\330\341\0\377\311\321\0\377\267\275\0\377\240\246" + "\0\377\206\213\0\377hk\0\377FH\0\377\40!\0\377\0\0\0\375\0\0\0\366\0\0\0" + "\355\0\0\0\344\0\0\0\326\0\0\0\266\0\0\0\212\0\0\0Z\0\0\0/\0\0\0\33\0\0\0" + "\16\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\271\271\271\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\3\0\0\0\15\0\0\0\31\0\0\0'\0\0\0@\0\0\0e\0\0\0\212\0" + "\0\0\255\0\0\0\312\0\0\0\332\0\0\0\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0" + "\0\365\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0" + "\366\0\0\0\362\0\0\0\355\0\0\0\350\0\0\0\342\0\0\0\332\0\0\0\313\0\0\0\255" + "\0\0\0\212\0\0\0e\0\0\0@\0\0\0'\0\0\0\31\0\0\0\16\0\0\0\4\0\0\0\2\0\0\0\1" + "\0\0\0\1\0\0\0\1\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\2\0\0\0\6\0\0\0\17\0\0\0\31\0\0\0!\0\0\0,\0\0\0C\0\0\0]\0\0\0u\0\0\0\212" + "\0\0\0\235\0\0\0\255\0\0\0\272\0\0\0\305\0\0\0\314\0\0\0\314\0\0\0\305\0" + "\0\0\272\0\0\0\255\0\0\0\235\0\0\0\212\0\0\0u\0\0\0]\0\0\0C\0\0\0,\0\0\0" + "\"\0\0\0\31\0\0\0\20\0\0\0\7\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\21\21" + "\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0qqq\0---\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\7\0\0\0\15\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!\0\0\0$\0\0\0'\0\0\0)" + "\0\0\0)\0\0\0'\0\0\0%\0\0\0!\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\16\0\0\0\10" + "\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1---\0qqq\0\271\271" + "\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\15\15" + "\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31\31\0\15\15\15\0\5" + "\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0)))\0===\0UUU\0qqq\0" + "\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0", +}; + diff --git a/samples/graphics/rsxtest_flip/include/mesh.h b/samples/graphics/rsxtest_flip/include/mesh.h new file mode 100644 index 00000000..63665494 --- /dev/null +++ b/samples/graphics/rsxtest_flip/include/mesh.h @@ -0,0 +1,62 @@ +#ifndef __MESH_H__ +#define __MESH_H__ + +#include + +using namespace Vectormath::Aos; + +template< class T > +inline const T& min_(const T& a,const T& b) +{ + return a +inline const T& max_(const T& a,const T& b) +{ + return a +inline const T clamp(const T& val,const T& low,const T& high) +{ + return min_(max_(val,low),high); +} + +struct S3DVertex +{ + S3DVertex() {}; + S3DVertex(f32 x,f32 y,f32 z,f32 nx,f32 ny,f32 nz,f32 tu,f32 tv) + : pos(x,y,z),nrm(nx,ny,nz),u(tu),v(tv) {}; + + inline S3DVertex& operator=(const S3DVertex& other) + { + pos = other.pos; + nrm = other.nrm; + u = other.u; + v = other.v; + return *this; + } + + Vector3 pos; + Vector3 nrm; + + f32 u,v; +}; + +template< class T > +class CMeshBuffer +{ +public: + CMeshBuffer() : indices(NULL),cnt_indices(0),vertices(NULL),cnt_vertices(0) {}; + + u16 *indices; + u32 cnt_indices; + + S3DVertex *vertices; + u32 cnt_vertices; +}; + +typedef CMeshBuffer SMeshBuffer; + +#endif diff --git a/samples/graphics/rsxtest_flip/include/rsxutil.h b/samples/graphics/rsxtest_flip/include/rsxutil.h new file mode 100644 index 00000000..fc5d132a --- /dev/null +++ b/samples/graphics/rsxtest_flip/include/rsxutil.h @@ -0,0 +1,44 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include + +#define DEFAULT_CB_SIZE 0x80000 // 512Kb default command buffer size +#define HOST_ADDR_ALIGNMENT (1024*1024) +#define HOST_SIZE (32*1024*1024) + +#define GCM_PREPARED_BUFFER_INDEX 65 +#define GCM_BUFFER_STATUS_INDEX 66 +#define GCM_WAIT_LABEL_INDEX 255 + +#define MAX_BUFFER_QUEUE_SIZE 1 + +#define BUFFER_IDLE 0 +#define BUFFER_BUSY 1 + +#define FRAME_BUFFER_COUNT 4 + +extern gcmContextData *gGcmContext; + +extern u32 curr_fb; + +extern u32 display_width; +extern u32 display_height; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern u32 *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern u32 *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; + +void initScreen(); +void flip(); +void finish(); + +void setRenderTarget(u32 index); + +#endif // __RSXUTIL_H__ diff --git a/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.fcg b/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.fcg new file mode 100644 index 00000000..6ebb917e --- /dev/null +++ b/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.fcg @@ -0,0 +1,35 @@ +void main +( + float4 position : TEXCOORD0, + float3 normal : TEXCOORD1, + float2 texcoord : TEXCOORD2, + + uniform float3 globalAmbient, + uniform float3 lightPosition, + uniform float3 lightColor, + uniform float3 eyePosition, + uniform float3 Kd, + uniform float3 Ks, + uniform float shininess, + + uniform sampler2D texture, + + out float4 oColor +) +{ + float3 N = normalize(normal); + + float3 L = normalize(lightPosition - position.xyz); + float diffuseLight = max(dot(N,L),0.0f); + float3 diffuse = Kd*lightColor*diffuseLight; + + float3 V = normalize(eyePosition - position.xyz); + float3 H = normalize(L + V); + float specularLight = pow(max(dot(H,N),0.0f),shininess); + if(diffuseLight<=0) specularLight = 0; + float3 specular = Ks*specularLight; + + float3 color = tex2D(texture,texcoord).xyz*(diffuse + globalAmbient) + specular; + + oColor = float4(color,1.0f); +} diff --git a/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.vcg b/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.vcg new file mode 100644 index 00000000..c11e6228 --- /dev/null +++ b/samples/graphics/rsxtest_flip/shaders/diffuse_specular_shader.vcg @@ -0,0 +1,21 @@ +void main +( + float3 vertexPosition : POSITION, + float3 vertexNormal : NORMAL, + float2 vertexTexcoord : TEXCOORD0, + + uniform float4x4 projMatrix, + uniform float4x4 modelViewMatrix, + + out float4 ePosition : POSITION, + out float4 oPosition : TEXCOORD0, + out float3 oNormal : TEXCOORD1, + out float2 oTexcoord : TEXCOORD2 +) +{ + ePosition = mul(mul(projMatrix,modelViewMatrix),float4(vertexPosition,1.0f)); + + oPosition = float4(vertexPosition,1.0f); + oNormal = vertexNormal; + oTexcoord = vertexTexcoord; +} diff --git a/samples/graphics/rsxtest_flip/source/main.cpp b/samples/graphics/rsxtest_flip/source/main.cpp new file mode 100644 index 00000000..9f0c2394 --- /dev/null +++ b/samples/graphics/rsxtest_flip/source/main.cpp @@ -0,0 +1,603 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "acid.h" +#include "mesh.h" +#include "rsxutil.h" + +#include "diffuse_specular_shader_vpo.h" +#include "diffuse_specular_shader_fpo.h" + +#define DEGTORAD(a) ( (a) * 0.01745329252f ) +#define RADTODEG(a) ( (a) * 57.29577951f ) + +SYS_PROCESS_PARAM(1001, 0x100000); + +u32 running = 0; + +u32 fp_offset; +u32 *fp_buffer; + +u32 *texture_buffer; +u32 texture_offset; + +s32 projMatrix_id = -1; +s32 modelViewMatrix_id = -1; +s32 vertexPosition_id = -1; +s32 vertexNormal_id = -1; +s32 vertexTexcoord_id = -1; +s32 textureUnit_id = -1; +s32 eyePosition_id = -1; +s32 globalAmbient_id = -1; +s32 lightPosition_id = -1; +s32 lightColor_id = -1; +s32 Kd_id = -1; +s32 Ks_id = -1; +s32 shininess_id = -1; + +Point3 eye_pos = Point3(0.0f,0.0f,20.0f); +Point3 eye_dir = Point3(0.0f,0.0f,0.0f); +Vector3 up_vec = Vector3(0.0f,1.0f,0.0f); + +void *vp_ucode = NULL; +rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; + +void *fp_ucode = NULL; +rsxFragmentProgram *fpo = (rsxFragmentProgram*)diffuse_specular_shader_fpo; + +static Matrix4 P; +static SMeshBuffer *sphere = NULL; +static SMeshBuffer *donut = NULL; +static SMeshBuffer *cube = NULL; + +extern "C" { +static void program_exit_callback() +{ + finish(); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + +static void init_texture() +{ + u32 i; + u8 *buffer; + const u8 *data = acid.pixel_data; + + texture_buffer = (u32*)rsxMemalign(128,(acid.width*acid.height*4)); + if(!texture_buffer) return; + + rsxAddressToOffset(texture_buffer,&texture_offset); + + buffer = (u8*)texture_buffer; + for(i=0;icnt_indices = 36; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + for(i=0;i<36;i++) buffer->indices[i] = u[i]; + + buffer->cnt_vertices = 12; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->vertices[0] = S3DVertex(0,0,0, -1,-1,-1, 1, 0); + buffer->vertices[1] = S3DVertex(1,0,0, 1,-1,-1, 1, 1); + buffer->vertices[2] = S3DVertex(1,1,0, 1, 1,-1, 0, 1); + buffer->vertices[3] = S3DVertex(0,1,0, -1, 1,-1, 0, 0); + buffer->vertices[4] = S3DVertex(1,0,1, 1,-1, 1, 1, 0); + buffer->vertices[5] = S3DVertex(1,1,1, 1, 1, 1, 0, 0); + buffer->vertices[6] = S3DVertex(0,1,1, -1, 1, 1, 0, 1); + buffer->vertices[7] = S3DVertex(0,0,1, -1,-1, 1, 1, 1); + buffer->vertices[8] = S3DVertex(0,1,1, -1, 1, 1, 1, 0); + buffer->vertices[9] = S3DVertex(0,1,0, -1, 1,-1, 1, 1); + buffer->vertices[10] = S3DVertex(1,0,1, 1,-1, 1, 0, 1); + buffer->vertices[11] = S3DVertex(1,0,0, 1,-1,-1, 0, 0); + + for(i=0;i<12;i++) { + buffer->vertices[i].pos -= Vector3(0.5f,0.5f,0.5f); + buffer->vertices[i].pos *= size; + } + + return buffer; +} + +static SMeshBuffer* createDonut(f32 outerRadius,f32 innerRadius,u32 polyCntX,u32 polyCntY) +{ + u32 i,x,y,level; + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + while(polyCntX*polyCntY>32767) { + polyCntX /= 2; + polyCntY /= 2; + } + + f32 ay = 0; + const f32 angleX = 2*M_PI/polyCntX; + const f32 angleY = 2*M_PI/polyCntY; + const u32 polyCntXpitch = polyCntX +1; + const u32 polyCntYpitch = polyCntY + 1; + + buffer->cnt_vertices = polyCntYpitch*polyCntXpitch; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->cnt_indices = polyCntY*polyCntX*6; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + i = 0; + for(y=0;y<=polyCntY;y++) { + f32 axz = 0; + + const f32 sinay = sinf(ay); + const f32 cosay = cosf(ay); + const f32 tu = (f32)y/(f32)polyCntY; + for(x=0;x<=polyCntX;x++) { + const Vector3 pos(static_cast((outerRadius - (innerRadius*cosf(axz)))*cosay), + static_cast((outerRadius - (innerRadius*cosf(axz)))*sinay), + static_cast(innerRadius*sinf(axz))); + + const Vector3 nrm(static_cast(-cosf(axz)*cosay), + static_cast(-cosf(axz)*sinay), + static_cast(sinf(axz))); + + buffer->vertices[i] = S3DVertex(pos.getX(),pos.getY(),pos.getZ(),nrm.getX(),nrm.getY(),nrm.getZ(),tu,(f32)x/(f32)polyCntX); + + axz += angleX; + i++; + } + ay += angleY; + } + + i = 0; + level = 0; + for(y=0;yindices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + return buffer; +} + +static SMeshBuffer* createSphere(f32 radius,u32 polyCntX,u32 polyCntY) +{ + u32 i,p1,p2,level; + u32 x,y,polyCntXpitch; + const f32 RECIPROCAL_PI = 1.0f/M_PI; + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + if(polyCntX*polyCntY>32767) { + if(polyCntX>polyCntY) + polyCntX = 32767/polyCntY-1; + else + polyCntY = 32767/(polyCntX+1); + } + polyCntXpitch = polyCntX+1; + + buffer->cnt_vertices = (polyCntXpitch*polyCntY)+2; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->cnt_indices = (polyCntX*polyCntY)*6; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + i = 0; + level = 0; + for(p1=0;p1indices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + const u32 polyCntSq = polyCntXpitch*polyCntY; + const u32 polyCntSq1 = polyCntSq+1; + const u32 polyCntSqM1 = (polyCntY-1)*polyCntXpitch; + + for(p2=0;p2indices[i++] = polyCntSq; + buffer->indices[i++] = p2; + buffer->indices[i++] = p2+1; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1+p2; + buffer->indices[i++] = polyCntSqM1+p2+1; + } + + buffer->indices[i++] = polyCntSq; + buffer->indices[i++] = polyCntX-1; + buffer->indices[i++] = polyCntX; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1; + buffer->indices[i++] = polyCntSqM1+polyCntX-1; + + f32 axz; + f32 ay = 0; + const f32 angelX = 2*M_PI/polyCntX; + const f32 angelY = M_PI/polyCntY; + + i = 0; + for(y=0;y(radius*cosf(axz)*sinay), static_cast(radius*cosf(ay)), static_cast(radius*sinf(axz)*sinay)); + + Vector3 normal = normalize(pos); + + f32 tu = 0.5F; + if(y==0) { + if(normal.getY()!=-1.0F && normal.getY()!=1.0F) + tu = static_cast(acosf(clamp(normal.getX()/sinay,-1.0f,1.0f))*0.5F*RECIPROCAL_PI); + if(normal.getZ()<0.0F) + tu = 1-tu; + } else + tu = buffer->vertices[i - polyCntXpitch].u; + + buffer->vertices[i] = S3DVertex(pos.getX(),pos.getY(),pos.getZ(),normal.getX(),normal.getY(),normal.getZ(),tu,static_cast(ay*RECIPROCAL_PI)); + axz += angelX; + i++; + } + buffer->vertices[i] = S3DVertex(buffer->vertices[i-polyCntX]); + buffer->vertices[i].u = 1.0F; + i++; + } + + buffer->vertices[i++] = S3DVertex(0.0F,radius,0.0F,0.0F,1.0F,0.0F,0.5F,0.0F); + buffer->vertices[i] = S3DVertex(0.0F,-radius,0.0F,0.0F,-1.0F,0.0F,0.5F,1.0F); + + return buffer; +} + +static void setTexture() +{ + u32 width = 128; + u32 height = 128; + u32 pitch = (width*4); + gcmTexture texture; + + if(!texture_buffer) return; + + rsxInvalidateTextureCache(gGcmContext,GCM_INVALIDATE_TEXTURE); + + texture.format = (GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN); + texture.mipmap = 1; + texture.dimension = GCM_TEXTURE_DIMS_2D; + texture.cubemap = GCM_FALSE; + texture.remap = ((GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_B_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_G_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_R_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_A_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_B << GCM_TEXTURE_REMAP_COLOR_B_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_G << GCM_TEXTURE_REMAP_COLOR_G_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_R << GCM_TEXTURE_REMAP_COLOR_R_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_A << GCM_TEXTURE_REMAP_COLOR_A_SHIFT)); + texture.width = width; + texture.height = height; + texture.depth = 1; + texture.location = GCM_LOCATION_RSX; + texture.pitch = pitch; + texture.offset = texture_offset; + rsxLoadTexture(gGcmContext,textureUnit_id,&texture); + rsxTextureControl(gGcmContext,textureUnit_id,GCM_TRUE,0<<8,12<<8,GCM_TEXTURE_MAX_ANISO_1); + rsxTextureFilter(gGcmContext,textureUnit_id,0,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureWrapMode(gGcmContext,textureUnit_id,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,0,GCM_TEXTURE_ZFUNC_LESS,0); +} + +static void setDrawEnv() +{ + rsxSetColorMask(gGcmContext,GCM_COLOR_MASK_B | + GCM_COLOR_MASK_G | + GCM_COLOR_MASK_R | + GCM_COLOR_MASK_A); + + rsxSetColorMaskMRT(gGcmContext,0); + + u16 x,y,w,h; + f32 min, max; + f32 scale[4],offset[4]; + + x = 0; + y = 0; + w = display_width; + h = display_height; + min = 0.0f; + max = 1.0f; + scale[0] = w*0.5f; + scale[1] = h*-0.5f; + scale[2] = (max - min)*0.5f; + scale[3] = 0.0f; + offset[0] = x + w*0.5f; + offset[1] = y + h*0.5f; + offset[2] = (max + min)*0.5f; + offset[3] = 0.0f; + + rsxSetViewport(gGcmContext,x, y, w, h, min, max, scale, offset); + rsxSetScissor(gGcmContext,x,y,w,h); + + rsxSetDepthTestEnable(gGcmContext,GCM_TRUE); + rsxSetDepthFunc(gGcmContext,GCM_LESS); + rsxSetShadeModel(gGcmContext,GCM_SHADE_MODEL_SMOOTH); + rsxSetDepthWriteEnable(gGcmContext,1); + rsxSetFrontFace(gGcmContext,GCM_FRONTFACE_CCW); +} + +void init_shader() +{ + u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + printf("vpsize: %d\n", vpsize); + + projMatrix_id = rsxVertexProgramGetConstIndex(vpo,"projMatrix"); + modelViewMatrix_id = rsxVertexProgramGetConstIndex(vpo,"modelViewMatrix"); + vertexPosition_id = rsxVertexProgramGetAttribIndex(vpo,"vertexPosition"); + vertexNormal_id = rsxVertexProgramGetAttribIndex(vpo,"vertexNormal"); + vertexTexcoord_id = rsxVertexProgramGetAttribIndex(vpo,"vertexTexcoord"); + + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + printf("fpsize: %d\n", fpsize); + + fp_buffer = (u32*)rsxMemalign(64,fpsize); + memcpy(fp_buffer,fp_ucode,fpsize); + rsxAddressToOffset(fp_buffer,&fp_offset); + + textureUnit_id = rsxFragmentProgramGetAttribIndex(fpo,"texture"); + eyePosition_id = rsxFragmentProgramGetConstIndex(fpo,"eyePosition"); + globalAmbient_id = rsxFragmentProgramGetConstIndex(fpo,"globalAmbient"); + lightPosition_id = rsxFragmentProgramGetConstIndex(fpo,"lightPosition"); + lightColor_id = rsxFragmentProgramGetConstIndex(fpo,"lightColor"); + shininess_id = rsxFragmentProgramGetConstIndex(fpo,"shininess"); + Ks_id = rsxFragmentProgramGetConstIndex(fpo,"Ks"); + Kd_id = rsxFragmentProgramGetConstIndex(fpo,"Kd"); +} + +void drawFrame() +{ + u32 i,offset,color = 0; + Matrix4 rotX,rotY; + Vector4 objEyePos,objLightPos; + Matrix4 viewMatrix,modelMatrix,modelMatrixIT,modelViewMatrix; + Point3 lightPos = Point3(250.0f,150.0f,150.0f); + f32 globalAmbientColor[3] = {0.1f,0.1f,0.1f}; + f32 lightColor[3] = {0.95f,0.95f,0.95f}; + f32 materialColorDiffuse[3] = {0.5f,0.0f,0.0f}; + f32 materialColorSpecular[3] = {0.7f,0.6f,0.6f}; + f32 shininess = 17.8954f; + static f32 rot = 0.0f; + SMeshBuffer *mesh = NULL; + + setTexture(); + setDrawEnv(); + + rsxSetClearColor(gGcmContext,color); + rsxSetClearDepthStencil(gGcmContext,0xffff); + rsxClearSurface(gGcmContext,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + rsxSetZControl(gGcmContext,0,1,1); + + for(i=0;i<8;i++) + rsxSetViewportClip(gGcmContext,i,display_width,display_height); + + viewMatrix = Matrix4::lookAt(eye_pos,eye_dir,up_vec); + + mesh = sphere; + rotX = Matrix4::rotationX(DEGTORAD(30.0f)); + rotY = Matrix4::rotationY(DEGTORAD(rot)); + modelMatrix = rotX*rotY; + modelMatrixIT = inverse(modelMatrix); + modelViewMatrix = transpose(viewMatrix*modelMatrix); + + objEyePos = modelMatrixIT*eye_pos; + objLightPos = modelMatrixIT*lightPos; + + rsxAddressToOffset(&mesh->vertices[0].pos,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].u,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxLoadVertexProgram(gGcmContext,vpo,vp_ucode); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); + + rsxLoadFragmentProgramLocation(gGcmContext,fpo,fp_offset,GCM_LOCATION_RSX); + + rsxSetUserClipPlaneControl(gGcmContext,GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0],&offset); + rsxDrawIndexArray(gGcmContext,GCM_TYPE_TRIANGLES,offset,mesh->cnt_indices,GCM_INDEX_TYPE_16B,GCM_LOCATION_RSX); + + mesh = donut; + rotX = Matrix4::rotationX(DEGTORAD(rot)); + rotY = Matrix4::rotationY(DEGTORAD(30.0f)); + modelMatrix = rotX*rotY; + modelMatrix.setTranslation(Vector3(3.0f,5.0f,-8.0f)); + + modelMatrixIT = inverse(modelMatrix); + modelViewMatrix = transpose(viewMatrix*modelMatrix); + + objEyePos = modelMatrixIT*eye_pos; + objLightPos = modelMatrixIT*lightPos; + + rsxAddressToOffset(&mesh->vertices[0].pos,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].u,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxLoadVertexProgram(gGcmContext,vpo,vp_ucode); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); + + rsxLoadFragmentProgramLocation(gGcmContext,fpo,fp_offset,GCM_LOCATION_RSX); + + rsxSetUserClipPlaneControl(gGcmContext,GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0],&offset); + rsxDrawIndexArray(gGcmContext,GCM_TYPE_TRIANGLES,offset,mesh->cnt_indices,GCM_INDEX_TYPE_16B,GCM_LOCATION_RSX); + + rot += 4.0f; + if(rot>=360.0f) rot = 0.0f; +} + +int main(int argc,const char *argv[]) +{ + padInfo padinfo; + padData paddata; + + printf("rsxtest_flip started...\n"); + + ioPadInit(7); + initScreen(); + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + init_shader(); + init_texture(); + + sphere = createSphere(3.0f,32,32); + donut = createDonut(3.0f,1.5f,32,32); + cube = createCube(5.0f); + + P = transpose(Matrix4::perspective(DEGTORAD(45.0f),aspect_ratio,1.0f,3000.0f)); + + setTexture(); + setDrawEnv(); + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if(paddata.BTN_CROSS) + goto done; + } + } + + drawFrame(); + flip(); + } + +done: + printf("rsxtest_flip done...\n"); + finish(); + return 0; +} diff --git a/samples/graphics/rsxtest_flip/source/rsxutil.cpp b/samples/graphics/rsxtest_flip/source/rsxutil.cpp new file mode 100644 index 00000000..53b5be20 --- /dev/null +++ b/samples/graphics/rsxtest_flip/source/rsxutil.cpp @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rsxutil.h" + +videoResolution vResolution; +gcmContextData *gGcmContext = NULL; + +u32 curr_fb = 0; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +u32 *depth_buffer; + +u32 color_pitch; +u32 color_offset[FRAME_BUFFER_COUNT]; +u32 *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +u32 fbOnDisplay = 0; +u32 fbFlipped = 0; +bool fbOnFlip = false; +sys_event_queue_t flipEventQueue; +sys_event_port_t flipEventPort; + +gcmSurface surface; + +static u32 sLabelVal = 1; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_960x1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); + +extern "C" { +static void flipHandler(const u32 head) +{ + (void)head; + u32 v = fbFlipped; + + for (u32 i = fbOnDisplay; i != v; i=(i + 1)%FRAME_BUFFER_COUNT) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + fbOnDisplay = v; + fbOnFlip = false; + + sysEventPortSend(flipEventPort, 0, 0, 0); +} + +static void vblankHandler(const u32 head) +{ + (void)head; + u32 data; + u32 bufferToFlip; + u32 indexToFlip; + + data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + bufferToFlip = (data >> 8); + indexToFlip = (data & 0x07); + + if (!fbOnFlip) { + if (bufferToFlip != fbOnDisplay) { + s32 ret = gcmSetFlipImmediate(indexToFlip); + if (ret != 0) { + printf("flip immediate failed\n"); + return; + } + fbFlipped = bufferToFlip; + fbOnFlip = true; + } + } +} +} + +static void syncPPUGPU() +{ + vu32 *label = (vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX); + while(((curr_fb + FRAME_BUFFER_COUNT - ((*label)>>8))%FRAME_BUFFER_COUNT) > MAX_BUFFER_QUEUE_SIZE) { + sys_event_t event; + + sysEventQueueReceive(flipEventQueue, &event, 0); + sysEventQueueDrain(flipEventQueue); + } +} + +static void waitRSXFinish() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(gGcmContext); + + while(*(vu32*)gcmGetLabelAddress(GCM_WAIT_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitRSXFinish(); +} + +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + (u32)vResolution.width*4 + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + +void initFlipEvent() +{ + sys_event_queue_attr_t queueAttr = { SYS_EVENT_QUEUE_PRIO, SYS_EVENT_QUEUE_PPU, "\0" }; + + sysEventQueueCreate(&flipEventQueue, &queueAttr, SYS_EVENT_QUEUE_KEY_LOCAL, 32); + sysEventPortCreate(&flipEventPort, SYS_EVENT_PORT_LOCAL, SYS_EVENT_PORT_NO_NAME); + sysEventPortConnectLocal(flipEventPort, flipEventQueue); + + gcmSetFlipHandler(flipHandler); + gcmSetVBlankHandler(vblankHandler); +} + +void initRenderTarget() +{ + memset(&surface, 0, sizeof(gcmSurface)); + + surface.colorFormat = GCM_SURFACE_X8R8G8B8; + surface.colorTarget = GCM_SURFACE_TARGET_0; + surface.colorLocation[0] = GCM_LOCATION_RSX; + surface.colorOffset[0] = color_offset[curr_fb]; + surface.colorPitch[0] = color_pitch; + + for(u32 i=1; i< GCM_MAX_MRT_COUNT;i++) { + surface.colorLocation[i] = GCM_LOCATION_RSX; + surface.colorOffset[i] = color_offset[curr_fb]; + surface.colorPitch[i] = 64; + } + + surface.depthFormat = GCM_SURFACE_ZETA_Z16; + surface.depthLocation = GCM_LOCATION_RSX; + surface.depthOffset = depth_offset; + surface.depthPitch = depth_pitch; + + surface.type = GCM_SURFACE_TYPE_LINEAR; + surface.antiAlias = GCM_SURFACE_CENTER_1; + + surface.width = display_width; + surface.height = display_height; + surface.x = 0; + surface.y = 0; + +} + +void setRenderTarget(u32 index) +{ + surface.colorOffset[0] = color_offset[index]; + rsxSetSurface(gGcmContext,&surface); +} + +void initScreen() +{ + u32 zs_depth = 4; + u32 color_depth = 4; + u32 bufferSize = rsxAlign(HOST_ADDR_ALIGNMENT, (DEFAULT_CB_SIZE + HOST_SIZE)); + + gcmInitDefaultFifoMode(GCM_DEFAULT_FIFO_MODE_CONDITIONAL); + + void *hostAddr = memalign(HOST_ADDR_ALIGNMENT, bufferSize); + rsxInit(&gGcmContext, DEFAULT_CB_SIZE, bufferSize, hostAddr); + + initVideoConfiguration(); + + color_pitch = display_width*color_depth; + depth_pitch = display_width*zs_depth; + + waitRSXIdle(); + + gcmSetFlipMode(GCM_FLIP_HSYNC); + + void *buffer; + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + buffer = rsxMemalign(64,(display_height*color_pitch)); + rsxAddressToOffset(buffer,&color_offset[i]); + printf("fb[%d]: %p (%08x) [%dx%d] %d\n", i, buffer, color_offset[i], display_width, display_height, color_pitch); + gcmSetDisplayBuffer(i,color_offset[i],color_pitch,display_width,display_height); + } + + buffer = rsxMemalign(64,(display_height*depth_pitch)*2); + rsxAddressToOffset(buffer, &depth_offset); + + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)) = (fbOnDisplay << 8); + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + fbOnDisplay)) = BUFFER_BUSY; + + curr_fb = (fbOnDisplay + 1)%FRAME_BUFFER_COUNT; + + initFlipEvent(); + initRenderTarget(); + + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); +} + +void flip() +{ + s32 qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + while (qid < 0) { + usleep(100); + qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + } + + rsxSetWriteBackendLabel(gGcmContext, GCM_PREPARED_BUFFER_INDEX, ((curr_fb << 8) | qid)); + rsxFlushBuffer(gGcmContext); + + syncPPUGPU(); + + curr_fb = (curr_fb + 1)%FRAME_BUFFER_COUNT; + + rsxSetWaitLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_IDLE); + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); + + setRenderTarget(curr_fb); +} + +void finish() +{ + rsxFinish(gGcmContext,1); + + u32 data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + u32 lastBuffer = (data >> 8); + while (lastBuffer != fbOnDisplay) + usleep(100); +} diff --git a/samples/graphics/rsxtest_spu/include/rsxutil.h b/samples/graphics/rsxtest_spu/include/rsxutil.h index f2fe1d1c..a9f2a683 100644 --- a/samples/graphics/rsxtest_spu/include/rsxutil.h +++ b/samples/graphics/rsxtest_spu/include/rsxutil.h @@ -2,14 +2,29 @@ #define __RSXUTIL_H__ #include +#include #define CB_SIZE 0x100000 #define HOST_SIZE (32*1024*1024) +#define FRAME_BUFFER_COUNT 2 + extern gcmContextData *context; + +extern u32 curr_fb; + extern u32 display_width; extern u32 display_height; -extern u32 curr_fb; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern u32 *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern u32 *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; void setRenderTarget(u32 index); void init_screen(void *host_addr,u32 size); diff --git a/samples/graphics/rsxtest_spu/source/main.cpp b/samples/graphics/rsxtest_spu/source/main.cpp index d3686660..6dd7e7f0 100644 --- a/samples/graphics/rsxtest_spu/source/main.cpp +++ b/samples/graphics/rsxtest_spu/source/main.cpp @@ -50,8 +50,6 @@ Point3 eye_pos = Point3(0.0f,0.0f,20.0f); Point3 eye_dir = Point3(0.0f,0.0f,0.0f); Vector3 up_vec = Vector3(0.0f,1.0f,0.0f); -f32 aspect_ratio = 4.0f/3.0f; - void *vp_ucode = NULL; rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; @@ -63,6 +61,29 @@ static SMeshBuffer *sphere = NULL; static SMeshBuffer *donut = NULL; static SMeshBuffer *cube = NULL; +extern "C" { +static void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context,1); + + shutdown_spu(); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} static void init_texture() { u32 i; @@ -114,7 +135,7 @@ static void setTexture() texture.offset = texture_offset; rsxLoadTexture(context,textureUnit_id,&texture); rsxTextureControl(context,textureUnit_id,GCM_TRUE,0<<8,12<<8,GCM_TEXTURE_MAX_ANISO_1); - rsxTextureFilter(context,textureUnit_id,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureFilter(context,textureUnit_id,0,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); rsxTextureWrapMode(context,textureUnit_id,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,0,GCM_TEXTURE_ZFUNC_LESS,0); } @@ -160,49 +181,32 @@ static void setDrawEnv() void init_shader() { u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + printf("vpsize: %d\n", vpsize); + + projMatrix_id = rsxVertexProgramGetConstIndex(vpo,"projMatrix"); + modelViewMatrix_id = rsxVertexProgramGetConstIndex(vpo,"modelViewMatrix"); + vertexPosition_id = rsxVertexProgramGetAttribIndex(vpo,"vertexPosition"); + vertexNormal_id = rsxVertexProgramGetAttribIndex(vpo,"vertexNormal"); + vertexTexcoord_id = rsxVertexProgramGetAttribIndex(vpo,"vertexTexcoord"); - vp_ucode = rsxVertexProgramGetUCode(vpo); - projMatrix_id = rsxVertexProgramGetConst(vpo,"projMatrix"); - modelViewMatrix_id = rsxVertexProgramGetConst(vpo,"modelViewMatrix"); - vertexPosition_id = rsxVertexProgramGetAttrib(vpo,"vertexPosition"); - vertexNormal_id = rsxVertexProgramGetAttrib(vpo,"vertexNormal"); - vertexTexcoord_id = rsxVertexProgramGetAttrib(vpo,"vertexTexcoord"); + rsxFragmentProgramGetUCode(fpo,&fp_ucode,&fpsize); + printf("fpsize: %d\n", fpsize); - fp_ucode = rsxFragmentProgramGetUCode(fpo,&fpsize); fp_buffer = (u32*)rsxMemalign(128,fpsize); memcpy(fp_buffer,fp_ucode,fpsize); rsxAddressToOffset(fp_buffer,&fp_offset); - textureUnit_id = rsxFragmentProgramGetAttrib(fpo,"texture"); - eyePosition_id = rsxFragmentProgramGetConst(fpo,"eyePosition"); - globalAmbient_id = rsxFragmentProgramGetConst(fpo,"globalAmbient"); - lightPosition_id = rsxFragmentProgramGetConst(fpo,"lightPosition"); - lightColor_id = rsxFragmentProgramGetConst(fpo,"lightColor"); - shininess_id = rsxFragmentProgramGetConst(fpo,"shininess"); - Ks_id = rsxFragmentProgramGetConst(fpo,"Ks"); - Kd_id = rsxFragmentProgramGetConst(fpo,"Kd"); -} - -void program_exit_callback() -{ - gcmSetWaitFlip(context); - rsxFinish(context,1); - - shutdown_spu(); -} - -void sysutil_exit_callback(u64 status,u64 param,void *usrdata) -{ - switch(status) { - case SYSUTIL_EXIT_GAME: - running = 0; - break; - case SYSUTIL_DRAW_BEGIN: - case SYSUTIL_DRAW_END: - break; - default: - break; - } + textureUnit_id = rsxFragmentProgramGetAttribIndex(fpo,"texture"); + eyePosition_id = rsxFragmentProgramGetConstIndex(fpo,"eyePosition"); + globalAmbient_id = rsxFragmentProgramGetConstIndex(fpo,"globalAmbient"); + lightPosition_id = rsxFragmentProgramGetConstIndex(fpo,"lightPosition"); + lightColor_id = rsxFragmentProgramGetConstIndex(fpo,"lightColor"); + shininess_id = rsxFragmentProgramGetConstIndex(fpo,"shininess"); + Ks_id = rsxFragmentProgramGetConstIndex(fpo,"Ks"); + Kd_id = rsxFragmentProgramGetConstIndex(fpo,"Kd"); } void initialize() @@ -236,7 +240,7 @@ void drawFrame() setDrawEnv(); rsxSetClearColor(context,color); - rsxSetClearDepthValue(context,0xffff); + rsxSetClearDepthStencil(context,0xffff); rsxClearSurface(context,GCM_CLEAR_R | GCM_CLEAR_G | GCM_CLEAR_B | @@ -244,7 +248,7 @@ void drawFrame() GCM_CLEAR_S | GCM_CLEAR_Z); - rsxZControl(context,0,1,1); + rsxSetZControl(context,0,1,1); for(i=0;i<8;i++) rsxSetViewportClip(context,i,display_width,display_height); @@ -263,22 +267,22 @@ void drawFrame() wait_signal_spu(); - rsxBindVertexArrayAttrib(context,vertexPosition_id,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); - rsxBindVertexArrayAttrib(context,vertexNormal_id,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); - rsxBindVertexArrayAttrib(context,vertexTexcoord_id,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexPosition_id,0,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexNormal_id,0,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexTexcoord_id,0,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); - rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); - rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + rsxSetVertexProgramParameterByIndex(context,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); - rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); - //rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); - rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); @@ -303,22 +307,22 @@ void drawFrame() objEyePos = modelMatrixIT*eye_pos; objLightPos = modelMatrixIT*lightPos; - rsxBindVertexArrayAttrib(context,vertexPosition_id,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); - rsxBindVertexArrayAttrib(context,vertexNormal_id,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); - rsxBindVertexArrayAttrib(context,vertexTexcoord_id,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexPosition_id,0,mesh->pos_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexNormal_id,0,mesh->nrm_off,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + rsxBindVertexArrayAttrib(context,vertexTexcoord_id,0,mesh->uv_off,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); rsxLoadVertexProgram(context,vpo,vp_ucode); - rsxSetVertexProgramParameter(context,vpo,projMatrix_id,(float*)&P); - rsxSetVertexProgramParameter(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + rsxSetVertexProgramParameterByIndex(context,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(context,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); - rsxSetFragmentProgramParameter(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,lightColor_id,lightColor,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,shininess_id,&shininess,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); - rsxSetFragmentProgramParameter(context,fpo,Kd_id,materialColorDiffuse,fp_offset); - rsxSetFragmentProgramParameter(context,fpo,Ks_id,materialColorSpecular,fp_offset); + rsxSetFragmentProgramParameterByIndex(context,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(context,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); rsxLoadFragmentProgramLocation(context,fpo,fp_offset,GCM_LOCATION_RSX); @@ -344,6 +348,8 @@ int main(int argc,const char *argv[]) padData paddata; rsxProgramConst *consts = rsxFragmentProgramGetConsts(fpo); + printf("rsxtest_spu started...\n"); + initialize(); ioPadInit(7); @@ -376,9 +382,8 @@ int main(int argc,const char *argv[]) if(padinfo.status[i]){ ioPadGetData(i, &paddata); - if(paddata.BTN_CROSS){ - return 0; - } + if(paddata.BTN_CROSS) + goto done; } } @@ -386,6 +391,9 @@ int main(int argc,const char *argv[]) drawFrame(); flip(); } - - return 0; + +done: + printf("rsxtest_spu done...\n"); + program_exit_callback(); + return 0; } diff --git a/samples/graphics/rsxtest_spu/source/rsxutil.cpp b/samples/graphics/rsxtest_spu/source/rsxutil.cpp index f13a77bf..89448912 100644 --- a/samples/graphics/rsxtest_spu/source/rsxutil.cpp +++ b/samples/graphics/rsxtest_spu/source/rsxutil.cpp @@ -5,14 +5,13 @@ #include #include -#include #include #include "rsxutil.h" #define GCM_LABEL_INDEX 255 -videoResolution res; +videoResolution vResolution; gcmContextData *context = NULL; u32 curr_fb = 0; @@ -26,8 +25,18 @@ u32 depth_offset; u32 *depth_buffer; u32 color_pitch; -u32 color_offset[2]; -u32 *color_buffer[2]; +u32 color_offset[FRAME_BUFFER_COUNT]; +u32 *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_960x1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); static u32 sLabelVal = 1; @@ -55,12 +64,65 @@ static void waitRSXIdle() waitFinish(); } +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + (u32)vResolution.width*4 + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + void setRenderTarget(u32 index) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = color_offset[index]; sf.colorPitch[0] = color_pitch; @@ -75,13 +137,13 @@ void setRenderTarget(u32 index) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = display_width; sf.height = display_height; @@ -93,47 +155,28 @@ void setRenderTarget(u32 index) void init_screen(void *host_addr,u32 size) { - printf("initializing screen....\n"); - - context = rsxInit(CB_SIZE,size,host_addr); + u32 zs_depth = 4; + u32 color_depth = 4; - videoState state; - videoGetState(0,0,&state); + rsxInit(&context,CB_SIZE,size,host_addr); - videoGetResolution(state.displayMode.resolution,&res); - - videoConfiguration vconfig; - memset(&vconfig,0,sizeof(videoConfiguration)); - - vconfig.resolution = state.displayMode.resolution; - vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; - vconfig.pitch = res.width*sizeof(u32); + initVideoConfiguration(); waitRSXIdle(); - videoConfigure(0,&vconfig,NULL,0); - videoGetState(0,0,&state); - gcmSetFlipMode(GCM_FLIP_VSYNC); - display_width = res.width; - display_height = res.height; + color_pitch = display_width*color_depth; + depth_pitch = display_width*zs_depth; - color_pitch = display_width*sizeof(u32); - color_buffer[0] = (u32*)rsxMemalign(64,(display_height*color_pitch)); - color_buffer[1] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + color_buffer[i] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + rsxAddressToOffset(color_buffer[i],&color_offset[i]); + gcmSetDisplayBuffer(i,color_offset[i],color_pitch,display_width,display_height); + } - rsxAddressToOffset(color_buffer[0],&color_offset[0]); - rsxAddressToOffset(color_buffer[1],&color_offset[1]); - - gcmSetDisplayBuffer(0,color_offset[0],color_pitch,display_width,display_height); - gcmSetDisplayBuffer(1,color_offset[1],color_pitch,display_width,display_height); - - depth_pitch = display_width*sizeof(u32); depth_buffer = (u32*)rsxMemalign(64,(display_height*depth_pitch)*2); rsxAddressToOffset(depth_buffer,&depth_offset); - - printf("screen initialized....\n"); } void waitflip() diff --git a/samples/graphics/rsxtest_tile/Makefile b/samples/graphics/rsxtest_tile/Makefile new file mode 100644 index 00000000..aae67e84 --- /dev/null +++ b/samples/graphics/rsxtest_tile/Makefile @@ -0,0 +1,164 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +SHADERS := shaders +INCLUDES := include + +TITLE := RSX Test - PSL1GHT +APPID := RSX00003 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lsimdmath -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(SHADERS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) +VCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.vcg))) +FCGFILES := $(foreach dir,$(SHADERS),$(notdir $(wildcard $(dir)/*.fcg))) + +VPOFILES := $(VCGFILES:.vcg=.vpo) +FPOFILES := $(FCGFILES:.fcg=.fpo) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(addsuffix .o,$(VPOFILES)) \ + $(addsuffix .o,$(FPOFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.vpo.o : %.vpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +#--------------------------------------------------------------------------------- +%.fpo.o : %.fpo +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/graphics/rsxtest_tile/include/acid.h b/samples/graphics/rsxtest_tile/include/acid.h new file mode 100644 index 00000000..d1643518 --- /dev/null +++ b/samples/graphics/rsxtest_tile/include/acid.h @@ -0,0 +1,2939 @@ +/* GIMP RGBA C-Source image dump (acid.c) */ + +static const struct { + unsigned int width; + unsigned int height; + unsigned int bytes_per_pixel; /* 3:RGB, 4:RGBA */ + unsigned char pixel_data[128 * 128 * 4 + 1]; +} acid = { + 128, 128, 4, + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\335\335\335\0\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31" + "\31\0\15\15\15\0\5\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0))" + ")\0===\0UUU\0qqq\0\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\345\345\345\0\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\15\15\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0qqq\0---\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\0\0\0\7\0\0\0\15\0\0\0" + "\23\0\0\0\30\0\0\0\35\0\0\0!\0\0\0$\0\0\0&\0\0\0(\0\0\0(\0\0\0'\0\0\0$\0" + "\0\0!\0\0\0\35\0\0\0\31\0\0\0\23\0\0\0\15\0\0\0\7\0\0\0\2\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0---\0qqq\0\271\271\271\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0\17\0\0\0\30\0\0\0\40\0\0\0+\0\0\0B\0" + "\0\0\\\0\0\0t\0\0\0\211\0\0\0\234\0\0\0\254\0\0\0\271\0\0\0\304\0\0\0\313" + "\0\0\0\313\0\0\0\304\0\0\0\271\0\0\0\254\0\0\0\234\0\0\0\211\0\0\0t\0\0\0" + "\\\0\0\0B\0\0\0+\0\0\0!\0\0\0\30\0\0\0\17\0\0\0\6\0\0\0\1\0\0\0\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\21\21\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\2\0\0\0\14\0\0\0\30\0\0\0&\0\0\0?\0\0\0d\0\0\0\211\0\0\0\254\0\0\0\311" + "\0\0\0\331\0\0\0\341\0\0\0\347\0\0\0\354\0\0\0\361\0\0\0\365\0\0\0\370\0" + "\0\0\373\0\0\0\375\0\0\0\375\0\0\0\373\0\0\0\371\0\0\0\365\0\0\0\361\0\0" + "\0\355\0\0\0\347\0\0\0\341\0\0\0\331\0\0\0\312\0\0\0\254\0\0\0\211\0\0\0" + "d\0\0\0?\0\0\0&\0\0\0\30\0\0\0\15\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0QQQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0\33\0\0" + "\0.\0\0\0Y\0\0\0\211\0\0\0\265\0\0\0\325\0\0\0\343\0\0\0\354\0\0\0\365\0" + "\0\0\374\40!\0\377FH\0\377hk\0\377\206\213\0\377\240\246\0\377\267\275\0" + "\377\311\321\0\377\330\341\0\377\344\354\0\377\344\354\0\377\330\341\0\377" + "\311\321\0\377\267\275\0\377\240\246\0\377\206\213\0\377hk\0\377FH\0\377" + "\40!\0\377\0\0\0\375\0\0\0\365\0\0\0\355\0\0\0\343\0\0\0\326\0\0\0\266\0" + "\0\0\211\0\0\0Z\0\0\0/\0\0\0\33\0\0\0\16\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0" + "\0\0\0\0QQQ\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\255\255\255\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\11\0\0\0" + "\27\0\0\0-\0\0\0]\0\0\0\224\0\0\0\304\0\0\0\336\0\0\0\354\0\0\0\367\30\31" + "\0\376QT\0\377\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0" + "\376\0\0\0\367\0\0\0\354\0\0\0\337\0\0\0\305\0\0\0\224\0\0\0]\0\0\0-\0\0" + "\0\30\0\0\0\11\0\0\0\2\0\0\0\1\0\0\0\0\0\0\0\0===\0\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265" + "\0===\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\15\0\0\0!\0\0\0H\0\0\0\204" + "\0\0\0\274\0\0\0\336\0\0\0\357\0\0\0\373BD\0\377\206\213\0\377\306\315\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\306\315\0\377\206\213\0\377BD\0\377\0\0\0\373" + "\0\0\0\357\0\0\0\337\0\0\0\275\0\0\0\204\0\0\0I\0\0\0!\0\0\0\15\0\0\0\3\0" + "\0\0\1\0\0\0\0\0\0\0\0===\0\265\265\265\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0QQ" + "Q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0'\0\0\0[\0\0\0\236\0\0" + "\0\324\0\0\0\353\0\0\0\371FH\0\377\225\232\0\377\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\340\350\0\377\225\232\0\377FH\0\377\0\0\0\371\0" + "\0\0\353\0\0\0\324\0\0\0\236\0\0\0\\\0\0\0'\0\0\0\17\0\0\0\3\0\0\0\1\0\0" + "\0\0\0\0\0\0QQQ\0\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\16\0\0\0(\0\0\0c\0\0\0\250" + "\0\0\0\332\0\0\0\361$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\361\0\0\0" + "\333\0\0\0\251\0\0\0c\0\0\0(\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0\0\0\0\0yyy" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0)))\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\13\0\0\0$\0\0\0_" + "\0\0\0\250\0\0\0\334\0\0\0\364BD\0\376\244\252\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0" + "\335\0\0\0\250\0\0\0`\0\0\0%\0\0\0\13\0\0\0\2\0\0\0\1\0\0\0\0)))\0\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\4\0\0\0\34\0\0\0O\0\0\0\234\0\0\0\332\0\0\0\364FH\0\376\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH\0\376\0\0\0\364\0" + "\0\0\332\0\0\0\234\0\0\0P\0\0\0\34\0\0\0\4\0\0\0\1\0\0\0\0\0\0\0\0qqq\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315" + "\0""555\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\17\0\0\0""0\0\0\0\203\0\0\0\321\0" + "\0\0\360+-\0\375\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377+-\0\375" + "\0\0\0\360\0\0\0\322\0\0\0\203\0\0\0""1\0\0\0\17\0\0\0\3\0\0\0\1\0\0\0\0" + """555\0\315\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\4\0\0\0\40\0\0\0`\0\0\0\262\0\0\0\346\0\0\0\374~\203\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\374\0\0\0\347\0\0\0\263\0\0\0a\0\0\0\40\0\0\0\5\0\0" + "\0\1\0\0\0\0\1\1\1\0\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\14\0\0" + "\0/\0\0\0\207\0\0\0\326\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\311\321\0\377FH\0\376\0\0\0\366\0\0\0\327\0\0\0\207\0\0\0" + """0\0\0\0\14\0\0\0\2\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375" + "\375\375\0UUU\0\0\0\0\0\0\0\0\0\0\0\0\3\0\0\0\30\0\0\0S\0\0\0\252\0\0\0\345" + "\0\0\0\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\374\0\0\0\346" + "\0\0\0\253\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\0UUU\0\375\375\375\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0==" + "=\0\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0\"\0\0\0q\0\0\0\316\0\0\0\363/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\364\0\0\0\316\0\0\0q\0\0\0\"\0\0\0\5\0\0\0\1\0\0\0\0===\0\351\351" + "\351\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\0\0\0\0\1" + "\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\\`\0\377\0\0\0\373\0\0\0\332\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1\0\0" + "\0\1---\0\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\331\331\331\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0""2\0\0\0\225\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\342\0\0\0" + "\226\0\0\0""2\0\0\0\11\0\0\0\1\0\0\0\1%%%\0\331\331\331\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\335\335\335\0%%%\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0?\0\0\0\243\0\0\0\350\2\2\0\375\240\246\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377" + "\2\2\0\375\0\0\0\350\0\0\0\244\0\0\0@\0\0\0\15\0\0\0\2\0\0\0\1%%%\0\335\335" + "\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\0\0\0\0\1\0\0\0\16" + "\0\0\0H\0\0\0\257\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\355\0\0\0\257\0\0\0H\0\0\0" + "\17\0\0\0\2\0\0\0\1---\0\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\375\375\375\0===\0\0\0\0\0\0\0\0\1\0\0\0\15" + "\0\0\0H\0\0\0\264\0\0\0\360\40!\0\376\306\315\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\40!\0\376\0\0\0" + "\360\0\0\0\265\0\0\0I\0\0\0\15\0\0\0\1\0\0\0\1===\0\375\375\375\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\11" + "\0\0\0?\0\0\0\257\0\0\0\360$%\0\376\315\325\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\315\325" + "\0\377$%\0\377\0\0\0\360\0\0\0\257\0\0\0@\0\0\0\11\0\0\0\1\0\0\0\1UUU\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\0\0\0\0\5\0\0\0""2" + "\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\355\0\0\0\244\0\0\0""2\0" + "\0\0\6\0\0\0\1\0\0\0\0uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\235\235\235\0\0\0\0\0\0\0\0\0\0\0" + "\0\4\0\0\0*\0\0\0\225\0\0\0\350\25\25\0\376\306\315\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\25" + "\25\0\376\0\0\0\350\0\0\0\226\0\0\0*\0\0\0\5\0\0\0\1\0\0\0\0\235\235\235" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\315\315\315\0" + "\1\1\1\0\0\0\0\0\0\0\0\3\0\0\0\"\0\0\0\205\0\0\0\342\2\2\0\375\267\275\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\2\2\0\375\0\0\0\342\0\0\0" + "\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\0\315\315\315\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374" + "\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377\13\14\0\377UX\0\377" + "\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\0\0\0\0\14\0\0\0S\0\0\0\316\0\0\0\373\202\207" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\310\317\0\3779<\0\377\0\0\0\3779<\0\377\310\317\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\306\315\0\377!\"\0\377\0\0\0\377\0\0\0\377\4\4\0\377PT\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\316\0\0\0S\0\0\0\14\0\0\0\1\0\0\0\0qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\0\0\0\0\4\0\0\0/\0\0\0\253\0\0\0\364\\`\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377/2\0\377\0\0\0\377\0\0\0\377\0\0\0\377/2\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\20\20\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0" + "\253\0\0\0""0\0\0\0\5\0\0\0\1\0\0\0\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0)))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0" + "\0\207\0\0\0\345/1\0\376\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\207\215\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\357\370\0\377/1\0\376\0\0\0\346" + "\0\0\0\207\0\0\0\40\0\0\0\3\0\0\0\1)))\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0yyy\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0`\0\0\0\326\0\0\0\374\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\5\5\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\374\0\0\0" + "\327\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\0yyy\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321\321\0" + "\0\0\0\0\0\0\0\0\0\0\0\4\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0" + "\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\0\321\321\321\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0" + "\0\0\0\0\0\0\2\0\0\0\34\0\0\0\203\0\0\0\346FH\0\376\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\376" + "\0\0\0\347\0\0\0\204\0\0\0\34\0\0\0\2\0\0\0\1QQQ\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0\0\0\0" + "\0\0\0\12\0\0\0O\0\0\0\321\0\0\0\374\311\321\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321" + "\0\377\0\0\0\374\0\0\0\322\0\0\0P\0\0\0\13\0\0\0\1\0\0\0\0\265\265\265\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0" + "\0%\0\0\0\234\0\0\0\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377~\203\0\377\0\0\0\361\0\0\0\234\0\0\0%\0\0\0\3\0\0\0\1===\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\255\255\255\0\0\0\0\0\0\0\0\0\0\0\0\16\0\0\0_\0" + "\0\0\332+-\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377+-\0\375\0\0\0\332\0\0\0`\0\0\0\17\0\0\0\1\0\0\0\0\255\255" + "\255\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0(\0\0\0\250\0\0\0" + "\363\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\244\252\0\377\0\0\0\364\0\0\0\250\0\0\0)\0\0\0\3\0\0\0\1=" + "==\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\0\0\0\0\17\0\0\0c\0\0\0\334FH" + "\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\17\0\0\0" + "\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'\0\0\0\251\0\0\0\363\267\275" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0" + "(\0\0\0\3\0\0\0\1QQQ\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377BD\0\376\0\0\0\333\0\0\0\\" + "\0\0\0\16\0\0\0\1\0\0\0\0\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0yyy\0\0\0\0\0\0\0\0\2\0\0\0!\0\0\0\235\0\0\0\361\244\252\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\361\0" + "\0\0\236\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\35\35\35\0\0\0\0\0\0\0\0\10\0\0\0H\0\0\0\324$%\0\375\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377$%\0\375\0" + "\0\0\325\0\0\0I\0\0\0\11\0\0\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\0\0\0\0\26\0\0\0\203\0\0\0\353~\203\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203" + "\0\377\0\0\0\353\0\0\0\204\0\0\0\27\0\0\0\1\0\0\0\0\265\265\265\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\325\335\0\377\0\0\0\371\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\336FH\0\376\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0]\0\0\0\16\0\0\0\1\21\21\21\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0\0\0\0\0\0\0\0\0\0\0\0\32\0\0\0\223\0\0\0\357\225\232\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\357\0\0\0\224\0\0\0\33\0" + "\0\0\1\0\0\0\0\271\271\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\340\350\0\377\0\0\0\373\0\0\0\305\0\0\0" + "/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0---\0\0\0\0\0\0\0\0\14\0\0\0Y\0\0\0\336BD\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\337\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\0\0\0\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\203\210\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0" + "\0\0\211\0\0\0\30\0\0\0\1\0\0\0\0\345\345\345\0\377\377\377\0\377\377\377" + "\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\265\0\0\0\367\306\315\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377" + "\0\0\0\367\0\0\0\266\0\0\0&\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377" + "\377\377\0qqq\0\0\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377\377\377\0\377\377" + "\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343QT\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT" + "\0\377\0\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0" + "\15\15\15\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\6\6\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15\15\15\0\377\377\377" + "\0\335\335\335\0\0\0\0\0\0\0\0\0\0\0\0\40\0\0\0\254\0\0\0\365\267\275\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\203\210\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\6\6\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0\0!\0\0\0\1\0\0\0\0\335" + "\335\335\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0+\0\0\0\311\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\210\215\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\7\7\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\344\354\0\377\0\0\0\374\0\0\0\312\0\0\0,\0\0\0\2" + "\0\0\0\1\265\265\265\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0B\0\0\0\331\40" + "!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\237\245\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\20\21\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\40!\0\377\0\0\0" + "\332\0\0\0B\0\0\0\7\0\0\0\1\221\221\221\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0" + "\0\0\341FH\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\37702\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\37702\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377!\"\0\377\0\0" + "\0\377\0\0\0\377\4\4\0\377PS\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0\0\0\342\0" + "\0\0]\0\0\0\15\0\0\0\1qqq\0UUU\0\0\0\0\0\0\0\0\23\0\0\0t\0\0\0\347hk\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\3779<\0\377\0" + "\0\0\3779<\0\377\310\317\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\350\361\0\377\254\263\0\377.0\0\377" + "\13\14\0\377UX\0\377\317\327\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0" + "\0\0u\0\0\0\23\0\0\0\1UUU\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206" + "\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===" + "\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0\361\240\246\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246" + "\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0\1)))\0\31\31\31\0\0\0\0\0\0\0\0" + "\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0\15\15\15\0\0\0\0\0\0\0\0$\0\0\0\271\0" + "\0\0\370\311\321\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\311\321\0\377\0\0\0\371\0\0\0\272\0\0\0" + "$\0\0\0\1\15\15\15\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\1\1\1" + "\0\0\0\0\0\0\0\0(\0\0\0\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\313\0\0\0)\0\0\0\1\1\1\1\0\1\1\1\0\0\0\0\0\0\0\0(\0\0\0" + "\313\0\0\0\374\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\344\354\0\377\0\0\0\375\0\0\0\313\0\0" + "\0)\0\0\0\1\1\1\1\0\5\5\5\0\0\0\0\0\0\0\0&\0\0\0\304\0\0\0\373\330\341\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\330\341\0\377\0\0\0\373\0\0\0\305\0\0\0'\0\0\0\1\5\5\5\0\15\15" + "\15\0\0\0\0\0\0\0\0$\0\0\0\271\0\0\0\370\311\321\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\311\321\0" + "\377\0\0\0\371\0\0\0\272\0\0\0$\0\0\0\1\15\15\15\0\31\31\31\0\0\0\0\0\0\0" + "\0\40\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0" + "\0\0\255\0\0\0!\0\0\0\1\31\31\31\0)))\0\0\0\0\0\0\0\0\35\0\0\0\234\0\0\0" + "\361\240\246\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\240\246\0\377\0\0\0\361\0\0\0\235\0\0\0\35\0\0\0" + "\1)))\0===\0\0\0\0\0\0\0\0\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\206" + "\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1===\0UUU\0\0\0\0\0\0\0\0\23" + "\0\0\0t\0\0\0\347hk\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377hk\0\377\0\0\0\350\0\0\0u\0\0\0\23\0\0\0" + "\1UUU\0qqq\0\0\0\0\0\0\0\0\15\0\0\0\\\0\0\0\341FH\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377FH\0\377\0" + "\0\0\342\0\0\0]\0\0\0\15\0\0\0\1qqq\0\221\221\221\0\0\0\0\0\0\0\0\6\0\0\0" + "B\0\0\0\331\40!\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\40!\0\377\0\0\0\332\0\0\0C\0\0\0\7\0\0\0\1\221" + "\221\221\0\265\265\265\0\0\0\0\0\0\0\0\1\0\0\0,\0\0\0\312\0\0\0\374\344\354" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377" + "\0\0\0\375\0\0\0\312\0\0\0,\0\0\0\2\0\0\0\1\265\265\265\0\335\335\335\0\0" + "\0\0\0\0\0\0\1\0\0\0!\0\0\0\254\0\0\0\365\267\275\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\267\275\0\377\0\0\0\365\0\0\0\255\0\0" + "\0\"\0\0\0\1\0\0\0\1\335\335\335\0\377\377\377\0\15\15\15\0\0\0\0\0\0\0\0" + "\30\0\0\0\211\0\0\0\354\206\213\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\15" + "\15\15\0\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\17\0\0\0d\0\0\0\343" + "QT\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377QT\0\377\0" + "\0\0\344\0\0\0e\0\0\0\17\0\0\0\1===\0\377\377\377\0\377\377\377\0qqq\0\0" + "\0\0\0\0\0\0\6\0\0\0?\0\0\0\325\30\31\0\376\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\30\31\0\376\0\0\0\326\0\0\0?\0\0\0\6\0\0\0\1qqq\0\377" + "\377\377\0\377\377\377\0\251\251\251\0\0\0\0\0\0\0\0\1\0\0\0&\0\0\0\266\0" + "\0\0\367\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\335\345\0\377\261\270\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\0\0\0\370" + "\0\0\0\266\0\0\0'\0\0\0\2\0\0\0\1\251\251\251\0\377\377\377\0\377\377\377" + "\0\345\345\345\0\0\0\0\0\0\0\0\1\0\0\0\31\0\0\0\212\0\0\0\354\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\322\332\0\377\36" + "\37\0\377\10\10\0\377\265\273\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\316\326\0\377\230\235\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\206\213\0\377\0\0\0\355\0\0\0\212\0\0\0\31\0\0\0\1\0" + "\0\0\1\345\345\345\0\377\377\377\0\377\377\377\0\377\377\377\0---\0\0\0\0" + "\0\0\0\0\14\0\0\0Z\0\0\0\337BD\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\1\1\0\377\201\206\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0\377\17" + "\20\0\377\2\2\0\377\224\231\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377BD\0\377\0\0\0\340\0\0\0Z\0\0\0" + "\15\0\0\0\1---\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "qqq\0\0\0\0\0\0\0\0\2\0\0\0.\0\0\0\305\0\0\0\372\340\350\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\322\332\0\377\36\37\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377SV\0\377\353\364\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377w{\0\377\1\1\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377;>\0\377<>\0\377<>\0\377\303\312\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\0\0\0\373\0\0\0\305\0\0\0/\0\0\0\3\0\0\0\1qqq\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0\0\0\0\0\0\0\1" + "\0\0\0\33\0\0\0\224\0\0\0\357\225\232\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\26\26\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377.0\0\377" + "\330\340\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\345\355\0\377?A" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\1\1\0\377\310\320\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\225\232\0\377\0\0\0\360\0\0\0" + "\225\0\0\0\34\0\0\0\1\0\0\0\1\271\271\271\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\21\21\21\0\0\0\0\0\0\0\0\15\0\0\0" + "]\0\0\0\337FH\0\376\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\257\266\0\377\4\4\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\16\17\0\377\265\273" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\277\306\0\377\23\24\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2\0\377\226\233\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377FH\0\377\0\0\0\337\0\0\0^\0\0\0\16\0\0\0\1\21\21" + "\21\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0aaa\0\0\0\0\0\0\0\0\3\0\0\0-\0\0\0\275\0\0\0\370\325\335" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\300\307\0\377\30\31\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377z\177\0\377\355\366" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377pt\0\377\2\2\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\2\2" + "\0\377\235\243\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\325\335\0\377\0\0\0\371" + "\0\0\0\276\0\0\0-\0\0\0\3\0\0\0\1aaa\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0\0\0\0\0\0" + "\0\0\1\0\0\0\27\0\0\0\204\0\0\0\353~\203\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\330\341\0\377&'\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\25\25\0\377\277\306\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\310\317\0\377" + "-/\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\25\25\0\377\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377~\203\0\377\0\0\0\354\0\0\0\205\0\0\0\30\0\0\0\1\0\0\0\1\265\265" + "\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\35\35\35\0\0\0\0\0\0\0\0\11\0\0\0I\0\0\0\324" + "$%\0\375\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\350\360\0\377EG\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\2\2\0\377mq\0\377\352\363\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\342\352\0" + "\377fi\0\377\2\2\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377*,\0\377\333\344\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377$%\0\375\0\0\0\325\0\0\0J\0\0\0\11\0\0" + "\0\1\35\35\35\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\2" + "\0\0\0!\0\0\0\236\0\0\0\361\244\252\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377tx\0\377\1\1\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\35\36\0\377\235\243\0" + "\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\356\367\0\377\220" + "\225\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377gj\0\377\353\364\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377\0\0\0\362\0" + "\0\0\237\0\0\0\"\0\0\0\2\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\331\331\331\0\0\0\0\0\0\0\0\1\0\0\0\16\0\0\0\\\0\0\0\333BD\0\375\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\265\273\0" + "\377\13\14\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377-/\0\377\273\302\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355\366\0\377\177\204" + "\0\377\15\16\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\11\12\0\377\246\254\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "BD\0\376\0\0\0\333\0\0\0]\0\0\0\17\0\0\0\1\0\0\0\1\331\331\331\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0'" + "\0\0\0\251\0\0\0\363\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\346\356\0\377HK\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377=?\0\377\247\255\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\344\354\0\377\206\213\0\377" + "\34\35\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377/1\0\377\325\335\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\267\275\0\377\0\0\0\364\0\0\0\251\0\0\0(\0\0\0\3\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271\271\0\0" + "\0\0\0\0\0\0\1\0\0\0\20\0\0\0d\0\0\0\335FH\0\375\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\211\217\0\377\10\11\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\14\15\0\377qu\0\377" + "\343\353\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\356\367\0\377\254\263\0\377hl\0\377\5\5\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\16\17\0\377\231\237\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377FH\0\376\0\0\0\335\0\0\0d\0\0\0\20\0\0\0\1\0\0\0\1\271\271\271" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0)\0\0\0\251\0\0\0\363\244\252\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\346\356\0\377fi\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\4\4\0\377BD\0\377\206\213\0\377\301\310\0\377\354\365\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340\350\0\377\230\235\0" + "\377^b\0\377\25\25\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377Z^" + "\0\377\335\345\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\244\252\0\377" + "\0\0\0\364\0\0\0\251\0\0\0*\0\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255" + "\255\255\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0`\0\0\0\332+-\0\375\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\254\263\0\377\25\25\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\12\13\0\377;>\0\377UX\0" + "\377lp\0\377x|\0\377x|\0\377x|\0\377bf\0\377HK\0\377\6\6\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\37713\0\377\275\304" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "+-\0\375\0\0\0\332\0\0\0a\0\0\0\17\0\0\0\1\0\0\0\1\255\255\255\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0===\0\0\0\0\0\0\0\0\3\0\0\0%\0\0\0\234\0\0\0" + "\360~\203\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357\370" + "\0\377\216\223\0\377\16\17\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + ",.\0\377\247\255\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0\361\0\0\0\235\0\0\0%\0" + "\0\0\3\0\0\0\1===\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265" + "\265\265\0\0\0\0\0\0\0\0\1\0\0\0\13\0\0\0P\0\0\0\322\0\0\0\374\311\321\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\355" + "\366\0\377\213\221\0\377\17\20\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\37724\0\377\246\254\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\311\321\0\377\0\0\0\374\0\0\0\323\0\0\0Q\0\0\0\14\0\0\0\1\0\0\0\1" + "\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0QQQ\0\0\0\0\0\0\0\0\2\0\0\0\34\0\0\0\204\0\0\0\347FH\0\376\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\356\367\0\377\235\243\0\377(*\0\377\0\0\0\377\0\0\0\377\0\0\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\5\5\0" + "\377hl\0\377\270\276\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377FH\0\377\0\0\0\347\0\0\0\204\0\0\0\35\0\0\0\2\0\0\0\1QQQ\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\321\321" + "\321\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""1\0\0\0\263\0\0\0\365\206\213\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\320\330\0\377\\`\0\377\7" + "\7\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0" + "\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0" + "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\1\1\0\3778:\0\377\226\233\0" + "\377\344\354\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\206\213\0\377\0\0\0\366\0\0\0\263\0\0\0""1\0\0\0\5\0\0\0\1\0\0\0\1" + "\321\321\321\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0\0\1\0\0\0\17\0\0\0a\0\0\0" + "\327\0\0\0\374\276\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\357\370\0\377\245\253\0\377w{\0\377:=\0\377\3\3\0\377" + "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0" + "\0\0\377\0\0\0\377\0\0\0\377\1\1\0\377*,\0\377dh\0\377\217\224\0\377\350" + "\361\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\276\305\0\377\0\0\0\375\0\0\0\330\0\0\0b\0\0" + "\0\20\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + ")))\0\0\0\0\0\0\0\0\3\0\0\0\40\0\0\0\207\0\0\0\346/1\0\376\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\357\370\0\377\305\314\0\377\247\255\0\377" + "\212\220\0\377x}\0\377x}\0\377x}\0\377x}\0\377{\200\0\377\240\246\0\377\270" + "\276\0\377\357\370\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\357\370\0\377/1\0\376\0\0\0\347\0\0\0\210\0\0\0!\0\0\0\3\0\0\0" + "\1)))\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265" + "\265\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0""0\0\0\0\253\0\0\0\364\\`\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\\`\0\377\0\0\0\364\0\0\0\254\0\0\0""1" + "\0\0\0\6\0\0\0\1\0\0\0\1\265\265\265\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0\0\0\1\0\0\0\14\0\0" + "\0T\0\0\0\317\0\0\0\373\202\207\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\202\207\0\377\0\0\0\373" + "\0\0\0\317\0\0\0T\0\0\0\15\0\0\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0""555\0\0\0\0\0\0\0\0\2\0\0\0\30\0\0\0q\0\0\0\332\0\0\0\374\240\246\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\240\246\0\377\0" + "\0\0\374\0\0\0\333\0\0\0r\0\0\0\31\0\0\0\2\0\0\0\1""555\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\315\315\315\0\1\1\1\0\0\0\0\1\0\0\0\4\0\0\0\"\0" + "\0\0\205\0\0\0\342\2\2\0\375\267\275\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267" + "\275\0\377\2\2\0\375\0\0\0\342\0\0\0\206\0\0\0#\0\0\0\4\0\0\0\1\1\1\1\1\315" + "\315\315\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\235\235" + "\235\0\0\0\0\0\0\0\0\1\0\0\0\5\0\0\0+\0\0\0\226\0\0\0\350\25\25\0\376\306" + "\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\306\315\0\377\25\25\0\376\0\0\0\351\0\0\0\226\0\0\0+\0\0\0\6\0" + "\0\0\1\0\0\0\1\235\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\6\0\0\0" + """2\0\0\0\244\0\0\0\355\40!\0\376\315\325\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377\40!\0\376\0\0\0\356\0\0\0\245\0\0\0""3\0" + "\0\0\7\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0UUU\0\0" + "\0\0\0\0\0\0\1\0\0\0\11\0\0\0@\0\0\0\260\0\0\0\360$%\0\376\315\325\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\315\325\0\377$%\0\377\0\0\0\361\0\0\0\260\0\0\0A\0\0\0" + "\12\0\0\0\1\0\0\0\1UUU\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\375\375\375\0===\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0H\0\0\0\264\0\0\0\360" + "\40!\0\376\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\306\315\0\377\40!\0\376\0\0\0\361\0\0\0\265\0\0\0I\0\0\0\16" + "\0\0\0\2\0\0\0\1===\1\375\375\375\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\351\351\351\0---\0\0\0\0\1\0\0\0\2\0\0\0\17" + "\0\0\0I\0\0\0\260\0\0\0\355\25\25\0\376\267\275\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\267\275\0\377\25\25\0\376\0\0\0\356\0\0\0\260\0\0\0I\0\0\0" + "\20\0\0\0\2\0\0\0\1---\1\351\351\351\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "%%%\0\0\0\0\1\0\0\0\2\0\0\0\16\0\0\0@\0\0\0\244\0\0\0\350\2\2\0\375\240\246" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\240\246\0\377\2\2\0\375\0\0\0\351\0\0\0\245\0\0\0@\0\0\0\16" + "\0\0\0\2\0\0\0\1%%%\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\331\331\331\0%%%\0\0\0\0\1\0\0\0\2\0\0\0\12\0\0\0""2\0\0\0\226" + "\0\0\0\342\0\0\0\374\202\207\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\202\207\0\377\0\0\0\374\0\0\0\343\0\0\0\226\0\0\0""3\0\0\0" + "\12\0\0\0\2\0\0\0\1%%%\1\331\331\331\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0---\0\0\0\0\1\0\0" + "\0\1\0\0\0\6\0\0\0*\0\0\0\205\0\0\0\332\0\0\0\373\\`\0\377\357\370\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\357" + "\370\0\377\\`\0\377\0\0\0\373\0\0\0\333\0\0\0\206\0\0\0+\0\0\0\6\0\0\0\1" + "\0\0\0\1---\1\335\335\335\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\351\351\351\0" + "===\0\0\0\0\1\0\0\0\1\0\0\0\5\0\0\0#\0\0\0r\0\0\0\317\0\0\0\364/1\0\376\276" + "\305\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\276\305\0\377/1\0\376" + "\0\0\0\365\0\0\0\317\0\0\0r\0\0\0#\0\0\0\6\0\0\0\1\0\0\0\1===\1\351\351\351" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\375\375\375" + "\0UUU\0\0\0\0\0\0\0\0\1\0\0\0\4\0\0\0\31\0\0\0S\0\0\0\253\0\0\0\346\0\0\0" + "\374\206\213\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\206\213\0\377\0\0\0\375\0\0\0\347\0\0\0" + "\254\0\0\0T\0\0\0\31\0\0\0\4\0\0\0\1\0\0\0\1UUU\0\375\375\375\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0uuu\0\0\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0/\0\0\0\210\0" + "\0\0\327\0\0\0\366FH\0\376\311\321\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\311\321\0\377FH\0\377\0\0\0\367\0\0\0\330\0\0\0\210\0\0\0""0\0\0\0\15\0" + "\0\0\3\0\0\0\1\0\0\0\1uuu\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\235\235\235\0\1\1\1\0\0\0\0\1\0\0\0\1\0\0\0\5\0" + "\0\0!\0\0\0a\0\0\0\263\0\0\0\347\0\0\0\374~\203\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377~\203\0\377\0\0\0" + "\374\0\0\0\347\0\0\0\264\0\0\0b\0\0\0!\0\0\0\6\0\0\0\1\0\0\0\1\1\1\1\1\235" + "\235\235\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\315\315\315\0""555\0\0\0\0\0\0\0\0\1\0" + "\0\0\3\0\0\0\17\0\0\0""1\0\0\0\204\0\0\0\322\0\0\0\361+-\0\375\244\252\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\244\252\0\377+-\0\375\0\0\0\361\0\0\0\323\0\0\0" + "\204\0\0\0""1\0\0\0\20\0\0\0\3\0\0\0\1\0\0\0\1""555\0\315\315\315\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0qqq\0\0\0\0\0\0" + "\0\0\1\0\0\0\1\0\0\0\5\0\0\0\34\0\0\0P\0\0\0\234\0\0\0\332\0\0\0\364FH\0" + "\376\267\275\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\267\275\0\377FH" + "\0\376\0\0\0\364\0\0\0\333\0\0\0\235\0\0\0Q\0\0\0\35\0\0\0\5\0\0\0\1\0\0" + "\0\1\0\0\0\1qqq\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\265\265\265\0)))\0\0" + "\0\0\0\0\0\0\1\0\0\0\3\0\0\0\14\0\0\0%\0\0\0`\0\0\0\251\0\0\0\335\0\0\0\364" + "BD\0\376\244\252\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\244\252\0\377BD\0\376\0\0\0\364\0\0\0\336\0\0\0\251\0\0\0a\0\0\0&" + "\0\0\0\14\0\0\0\3\0\0\0\1\0\0\0\1)))\0\265\265\265\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0yyy\0\0\0\0\0\0\0" + "\0\1\0\0\0\1\0\0\0\3\0\0\0\17\0\0\0)\0\0\0d\0\0\0\251\0\0\0\333\0\0\0\362" + "$%\0\375~\203\0\377\325\335\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\325\335\0\377~\203\0\377$%\0\375\0\0\0\362\0\0\0\334\0\0\0\252\0\0\0" + "d\0\0\0)\0\0\0\17\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1yyy\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\321\321\321\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1\0" + "\0\0\4\0\0\0\20\0\0\0(\0\0\0\\\0\0\0\236\0\0\0\325\0\0\0\354\0\0\0\372FH" + "\0\377\225\232\0\377\340\350\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\340" + "\350\0\377\225\232\0\377FH\0\377\0\0\0\372\0\0\0\354\0\0\0\325\0\0\0\236" + "\0\0\0]\0\0\0(\0\0\0\20\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\321\321\321" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\265\265\265\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\3\0\0\0" + "\16\0\0\0\"\0\0\0I\0\0\0\205\0\0\0\275\0\0\0\337\0\0\0\360\0\0\0\374BD\0" + "\377\206\213\0\377\306\315\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\306\315\0\377\206" + "\213\0\377BD\0\377\0\0\0\374\0\0\0\360\0\0\0\340\0\0\0\276\0\0\0\205\0\0" + "\0J\0\0\0\"\0\0\0\16\0\0\0\4\0\0\0\1\0\0\0\1\0\0\0\1===\0\265\265\265\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\255\255" + "\255\0===\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\2\0\0\0\11\0\0\0\27\0\0\0-\0\0" + "\0]\0\0\0\225\0\0\0\305\0\0\0\337\0\0\0\355\0\0\0\370\30\31\0\376QT\0\377" + "\206\213\0\377\267\275\0\377\344\354\0\377\360\371\0\377\360\371\0\377\360" + "\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371" + "\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0" + "\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377\360\371\0\377" + "\344\354\0\377\267\275\0\377\206\213\0\377QT\0\377\30\31\0\376\0\0\0\370" + "\0\0\0\355\0\0\0\340\0\0\0\306\0\0\0\225\0\0\0^\0\0\0-\0\0\0\30\0\0\0\11" + "\0\0\0\3\0\0\0\1\0\0\0\1\0\0\0\1===\0\255\255\255\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\271\271\271\0QQQ\0\0\0\0\0\0\0\0\1\0\0\0\1" + "\0\0\0\1\0\0\0\3\0\0\0\16\0\0\0\33\0\0\0/\0\0\0Z\0\0\0\212\0\0\0\266\0\0" + "\0\326\0\0\0\344\0\0\0\355\0\0\0\365\0\0\0\374\40!\0\377FH\0\377hk\0\377" + "\206\213\0\377\240\246\0\377\267\275\0\377\311\321\0\377\330\341\0\377\344" + "\354\0\377\344\354\0\377\330\341\0\377\311\321\0\377\267\275\0\377\240\246" + "\0\377\206\213\0\377hk\0\377FH\0\377\40!\0\377\0\0\0\375\0\0\0\366\0\0\0" + "\355\0\0\0\344\0\0\0\326\0\0\0\266\0\0\0\212\0\0\0Z\0\0\0/\0\0\0\33\0\0\0" + "\16\0\0\0\4\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1QQQ\0\271\271\271\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\331\331\331\0yyy\0\35\35\35\0\0\0\0\0\0\0\0\1\0" + "\0\0\1\0\0\0\1\0\0\0\3\0\0\0\15\0\0\0\31\0\0\0'\0\0\0@\0\0\0e\0\0\0\212\0" + "\0\0\255\0\0\0\312\0\0\0\332\0\0\0\342\0\0\0\350\0\0\0\355\0\0\0\361\0\0" + "\0\365\0\0\0\371\0\0\0\373\0\0\0\375\0\0\0\375\0\0\0\374\0\0\0\371\0\0\0" + "\366\0\0\0\362\0\0\0\355\0\0\0\350\0\0\0\342\0\0\0\332\0\0\0\313\0\0\0\255" + "\0\0\0\212\0\0\0e\0\0\0@\0\0\0'\0\0\0\31\0\0\0\16\0\0\0\4\0\0\0\2\0\0\0\1" + "\0\0\0\1\0\0\0\1\35\35\35\0yyy\0\331\331\331\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\265\265\265\0aaa\0\21\21\21\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0" + "\0\2\0\0\0\6\0\0\0\17\0\0\0\31\0\0\0!\0\0\0,\0\0\0C\0\0\0]\0\0\0u\0\0\0\212" + "\0\0\0\235\0\0\0\255\0\0\0\272\0\0\0\305\0\0\0\314\0\0\0\314\0\0\0\305\0" + "\0\0\272\0\0\0\255\0\0\0\235\0\0\0\212\0\0\0u\0\0\0]\0\0\0C\0\0\0,\0\0\0" + "\"\0\0\0\31\0\0\0\20\0\0\0\7\0\0\0\2\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\21\21" + "\21\0aaa\0\265\265\265\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\271\271" + "\271\0qqq\0---\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2" + "\0\0\0\7\0\0\0\15\0\0\0\23\0\0\0\31\0\0\0\35\0\0\0!\0\0\0$\0\0\0'\0\0\0)" + "\0\0\0)\0\0\0'\0\0\0%\0\0\0!\0\0\0\36\0\0\0\31\0\0\0\24\0\0\0\16\0\0\0\10" + "\0\0\0\3\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1---\0qqq\0\271\271" + "\271\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\345\345\345\0" + "\251\251\251\0qqq\0===\0\15\15\15\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0" + "\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\1\15\15" + "\15\0===\0qqq\0\251\251\251\0\345\345\345\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\335\335\335\0" + "\265\265\265\0\221\221\221\0qqq\0UUU\0===\0)))\0\31\31\31\0\15\15\15\0\5" + "\5\5\0\1\1\1\0\1\1\1\0\5\5\5\0\15\15\15\0\31\31\31\0)))\0===\0UUU\0qqq\0" + "\221\221\221\0\265\265\265\0\335\335\335\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377" + "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0" + "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377" + "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377" + "\377\0\377\377\377\0\377\377\377\0\377\377\377\0", +}; + diff --git a/samples/graphics/rsxtest_tile/include/mesh.h b/samples/graphics/rsxtest_tile/include/mesh.h new file mode 100644 index 00000000..63665494 --- /dev/null +++ b/samples/graphics/rsxtest_tile/include/mesh.h @@ -0,0 +1,62 @@ +#ifndef __MESH_H__ +#define __MESH_H__ + +#include + +using namespace Vectormath::Aos; + +template< class T > +inline const T& min_(const T& a,const T& b) +{ + return a +inline const T& max_(const T& a,const T& b) +{ + return a +inline const T clamp(const T& val,const T& low,const T& high) +{ + return min_(max_(val,low),high); +} + +struct S3DVertex +{ + S3DVertex() {}; + S3DVertex(f32 x,f32 y,f32 z,f32 nx,f32 ny,f32 nz,f32 tu,f32 tv) + : pos(x,y,z),nrm(nx,ny,nz),u(tu),v(tv) {}; + + inline S3DVertex& operator=(const S3DVertex& other) + { + pos = other.pos; + nrm = other.nrm; + u = other.u; + v = other.v; + return *this; + } + + Vector3 pos; + Vector3 nrm; + + f32 u,v; +}; + +template< class T > +class CMeshBuffer +{ +public: + CMeshBuffer() : indices(NULL),cnt_indices(0),vertices(NULL),cnt_vertices(0) {}; + + u16 *indices; + u32 cnt_indices; + + S3DVertex *vertices; + u32 cnt_vertices; +}; + +typedef CMeshBuffer SMeshBuffer; + +#endif diff --git a/samples/graphics/rsxtest_tile/include/rsxutil.h b/samples/graphics/rsxtest_tile/include/rsxutil.h new file mode 100644 index 00000000..1b520d6b --- /dev/null +++ b/samples/graphics/rsxtest_tile/include/rsxutil.h @@ -0,0 +1,44 @@ +#ifndef __RSXUTIL_H__ +#define __RSXUTIL_H__ + +#include + +#define DEFAULT_CB_SIZE 0x80000 // 512Kb default command buffer size +#define HOST_ADDR_ALIGNMENT (1024*1024) +#define HOST_SIZE (32*1024*1024) + +#define GCM_PREPARED_BUFFER_INDEX 65 +#define GCM_BUFFER_STATUS_INDEX 66 +#define GCM_WAIT_LABEL_INDEX 255 + +#define MAX_BUFFER_QUEUE_SIZE 1 + +#define BUFFER_IDLE 0 +#define BUFFER_BUSY 1 + +#define FRAME_BUFFER_COUNT 4 + +extern gcmContextData *gGcmContext; + +extern u32 curr_fb; + +extern u32 display_width; +extern u32 display_height; + +extern u32 depth_pitch; +extern u32 depth_offset; +extern void *depth_buffer; + +extern u32 color_pitch; +extern u32 color_offset[FRAME_BUFFER_COUNT]; +extern void *color_buffer[FRAME_BUFFER_COUNT]; + +extern f32 aspect_ratio; + +void initScreen(); +void flip(); +void finish(); + +void setRenderTarget(u32 index); + +#endif // __RSXUTIL_H__ diff --git a/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.fcg b/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.fcg new file mode 100644 index 00000000..6ebb917e --- /dev/null +++ b/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.fcg @@ -0,0 +1,35 @@ +void main +( + float4 position : TEXCOORD0, + float3 normal : TEXCOORD1, + float2 texcoord : TEXCOORD2, + + uniform float3 globalAmbient, + uniform float3 lightPosition, + uniform float3 lightColor, + uniform float3 eyePosition, + uniform float3 Kd, + uniform float3 Ks, + uniform float shininess, + + uniform sampler2D texture, + + out float4 oColor +) +{ + float3 N = normalize(normal); + + float3 L = normalize(lightPosition - position.xyz); + float diffuseLight = max(dot(N,L),0.0f); + float3 diffuse = Kd*lightColor*diffuseLight; + + float3 V = normalize(eyePosition - position.xyz); + float3 H = normalize(L + V); + float specularLight = pow(max(dot(H,N),0.0f),shininess); + if(diffuseLight<=0) specularLight = 0; + float3 specular = Ks*specularLight; + + float3 color = tex2D(texture,texcoord).xyz*(diffuse + globalAmbient) + specular; + + oColor = float4(color,1.0f); +} diff --git a/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.vcg b/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.vcg new file mode 100644 index 00000000..c11e6228 --- /dev/null +++ b/samples/graphics/rsxtest_tile/shaders/diffuse_specular_shader.vcg @@ -0,0 +1,21 @@ +void main +( + float3 vertexPosition : POSITION, + float3 vertexNormal : NORMAL, + float2 vertexTexcoord : TEXCOORD0, + + uniform float4x4 projMatrix, + uniform float4x4 modelViewMatrix, + + out float4 ePosition : POSITION, + out float4 oPosition : TEXCOORD0, + out float3 oNormal : TEXCOORD1, + out float2 oTexcoord : TEXCOORD2 +) +{ + ePosition = mul(mul(projMatrix,modelViewMatrix),float4(vertexPosition,1.0f)); + + oPosition = float4(vertexPosition,1.0f); + oNormal = vertexNormal; + oTexcoord = vertexTexcoord; +} diff --git a/samples/graphics/rsxtest_tile/source/main.cpp b/samples/graphics/rsxtest_tile/source/main.cpp new file mode 100644 index 00000000..ad19210e --- /dev/null +++ b/samples/graphics/rsxtest_tile/source/main.cpp @@ -0,0 +1,603 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "acid.h" +#include "mesh.h" +#include "rsxutil.h" + +#include "diffuse_specular_shader_vpo.h" +#include "diffuse_specular_shader_fpo.h" + +#define DEGTORAD(a) ( (a) * 0.01745329252f ) +#define RADTODEG(a) ( (a) * 57.29577951f ) + +SYS_PROCESS_PARAM(1001, 0x100000); + +u32 running = 0; + +u32 fp_offset; +u32 *fp_buffer; + +u32 *texture_buffer; +u32 texture_offset; + +s32 projMatrix_id = -1; +s32 modelViewMatrix_id = -1; +s32 vertexPosition_id = -1; +s32 vertexNormal_id = -1; +s32 vertexTexcoord_id = -1; +s32 textureUnit_id = -1; +s32 eyePosition_id = -1; +s32 globalAmbient_id = -1; +s32 lightPosition_id = -1; +s32 lightColor_id = -1; +s32 Kd_id = -1; +s32 Ks_id = -1; +s32 shininess_id = -1; + +Point3 eye_pos = Point3(0.0f,0.0f,20.0f); +Point3 eye_dir = Point3(0.0f,0.0f,0.0f); +Vector3 up_vec = Vector3(0.0f,1.0f,0.0f); + +void *vp_ucode = NULL; +rsxVertexProgram *vpo = (rsxVertexProgram*)diffuse_specular_shader_vpo; + +void *fp_ucode = NULL; +rsxFragmentProgram *fpo = (rsxFragmentProgram*)diffuse_specular_shader_fpo; + +static Matrix4 P; +static SMeshBuffer *sphere = NULL; +static SMeshBuffer *donut = NULL; +static SMeshBuffer *cube = NULL; + +extern "C" { +static void program_exit_callback() +{ + finish(); +} + +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + running = 0; + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + default: + break; + } +} +} + +static void init_texture() +{ + u32 i; + u8 *buffer; + const u8 *data = acid.pixel_data; + + texture_buffer = (u32*)rsxMemalign(128,(acid.width*acid.height*4)); + if(!texture_buffer) return; + + rsxAddressToOffset(texture_buffer,&texture_offset); + + buffer = (u8*)texture_buffer; + for(i=0;icnt_indices = 36; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + for(i=0;i<36;i++) buffer->indices[i] = u[i]; + + buffer->cnt_vertices = 12; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->vertices[0] = S3DVertex(0,0,0, -1,-1,-1, 1, 0); + buffer->vertices[1] = S3DVertex(1,0,0, 1,-1,-1, 1, 1); + buffer->vertices[2] = S3DVertex(1,1,0, 1, 1,-1, 0, 1); + buffer->vertices[3] = S3DVertex(0,1,0, -1, 1,-1, 0, 0); + buffer->vertices[4] = S3DVertex(1,0,1, 1,-1, 1, 1, 0); + buffer->vertices[5] = S3DVertex(1,1,1, 1, 1, 1, 0, 0); + buffer->vertices[6] = S3DVertex(0,1,1, -1, 1, 1, 0, 1); + buffer->vertices[7] = S3DVertex(0,0,1, -1,-1, 1, 1, 1); + buffer->vertices[8] = S3DVertex(0,1,1, -1, 1, 1, 1, 0); + buffer->vertices[9] = S3DVertex(0,1,0, -1, 1,-1, 1, 1); + buffer->vertices[10] = S3DVertex(1,0,1, 1,-1, 1, 0, 1); + buffer->vertices[11] = S3DVertex(1,0,0, 1,-1,-1, 0, 0); + + for(i=0;i<12;i++) { + buffer->vertices[i].pos -= Vector3(0.5f,0.5f,0.5f); + buffer->vertices[i].pos *= size; + } + + return buffer; +} + +static SMeshBuffer* createDonut(f32 outerRadius,f32 innerRadius,u32 polyCntX,u32 polyCntY) +{ + u32 i,x,y,level; + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + while(polyCntX*polyCntY>32767) { + polyCntX /= 2; + polyCntY /= 2; + } + + f32 ay = 0; + const f32 angleX = 2*M_PI/polyCntX; + const f32 angleY = 2*M_PI/polyCntY; + const u32 polyCntXpitch = polyCntX +1; + const u32 polyCntYpitch = polyCntY + 1; + + buffer->cnt_vertices = polyCntYpitch*polyCntXpitch; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->cnt_indices = polyCntY*polyCntX*6; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + i = 0; + for(y=0;y<=polyCntY;y++) { + f32 axz = 0; + + const f32 sinay = sinf(ay); + const f32 cosay = cosf(ay); + const f32 tu = (f32)y/(f32)polyCntY; + for(x=0;x<=polyCntX;x++) { + const Vector3 pos(static_cast((outerRadius - (innerRadius*cosf(axz)))*cosay), + static_cast((outerRadius - (innerRadius*cosf(axz)))*sinay), + static_cast(innerRadius*sinf(axz))); + + const Vector3 nrm(static_cast(-cosf(axz)*cosay), + static_cast(-cosf(axz)*sinay), + static_cast(sinf(axz))); + + buffer->vertices[i] = S3DVertex(pos.getX(),pos.getY(),pos.getZ(),nrm.getX(),nrm.getY(),nrm.getZ(),tu,(f32)x/(f32)polyCntX); + + axz += angleX; + i++; + } + ay += angleY; + } + + i = 0; + level = 0; + for(y=0;yindices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + return buffer; +} + +static SMeshBuffer* createSphere(f32 radius,u32 polyCntX,u32 polyCntY) +{ + u32 i,p1,p2,level; + u32 x,y,polyCntXpitch; + const f32 RECIPROCAL_PI = 1.0f/M_PI; + SMeshBuffer *buffer = new SMeshBuffer(); + + if(polyCntX<2) polyCntX = 2; + if(polyCntY<2) polyCntY = 2; + if(polyCntX*polyCntY>32767) { + if(polyCntX>polyCntY) + polyCntX = 32767/polyCntY-1; + else + polyCntY = 32767/(polyCntX+1); + } + polyCntXpitch = polyCntX+1; + + buffer->cnt_vertices = (polyCntXpitch*polyCntY)+2; + buffer->vertices = (S3DVertex*)rsxMemalign(128,buffer->cnt_vertices*sizeof(S3DVertex)); + + buffer->cnt_indices = (polyCntX*polyCntY)*6; + buffer->indices = (u16*)rsxMemalign(128,buffer->cnt_indices*sizeof(u16)); + + i = 0; + level = 0; + for(p1=0;p1indices[i++] = curr; + buffer->indices[i++] = curr + polyCntXpitch; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + + buffer->indices[i++] = curr; + buffer->indices[i++] = curr + 1 + polyCntXpitch; + buffer->indices[i++] = curr + 1; + } + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + + buffer->indices[i++] = level + polyCntX; + buffer->indices[i++] = level + polyCntX - 1 + polyCntXpitch; + buffer->indices[i++] = level + polyCntX + polyCntXpitch; + + level += polyCntXpitch; + } + + const u32 polyCntSq = polyCntXpitch*polyCntY; + const u32 polyCntSq1 = polyCntSq+1; + const u32 polyCntSqM1 = (polyCntY-1)*polyCntXpitch; + + for(p2=0;p2indices[i++] = polyCntSq; + buffer->indices[i++] = p2; + buffer->indices[i++] = p2+1; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1+p2; + buffer->indices[i++] = polyCntSqM1+p2+1; + } + + buffer->indices[i++] = polyCntSq; + buffer->indices[i++] = polyCntX-1; + buffer->indices[i++] = polyCntX; + + buffer->indices[i++] = polyCntSq1; + buffer->indices[i++] = polyCntSqM1; + buffer->indices[i++] = polyCntSqM1+polyCntX-1; + + f32 axz; + f32 ay = 0; + const f32 angelX = 2*M_PI/polyCntX; + const f32 angelY = M_PI/polyCntY; + + i = 0; + for(y=0;y(radius*cosf(axz)*sinay), static_cast(radius*cosf(ay)), static_cast(radius*sinf(axz)*sinay)); + + Vector3 normal = normalize(pos); + + f32 tu = 0.5F; + if(y==0) { + if(normal.getY()!=-1.0F && normal.getY()!=1.0F) + tu = static_cast(acosf(clamp(normal.getX()/sinay,-1.0f,1.0f))*0.5F*RECIPROCAL_PI); + if(normal.getZ()<0.0F) + tu = 1-tu; + } else + tu = buffer->vertices[i - polyCntXpitch].u; + + buffer->vertices[i] = S3DVertex(pos.getX(),pos.getY(),pos.getZ(),normal.getX(),normal.getY(),normal.getZ(),tu,static_cast(ay*RECIPROCAL_PI)); + axz += angelX; + i++; + } + buffer->vertices[i] = S3DVertex(buffer->vertices[i-polyCntX]); + buffer->vertices[i].u = 1.0F; + i++; + } + + buffer->vertices[i++] = S3DVertex(0.0F,radius,0.0F,0.0F,1.0F,0.0F,0.5F,0.0F); + buffer->vertices[i] = S3DVertex(0.0F,-radius,0.0F,0.0F,-1.0F,0.0F,0.5F,1.0F); + + return buffer; +} + +static void setTexture() +{ + u32 width = 128; + u32 height = 128; + u32 pitch = (width*4); + gcmTexture texture; + + if(!texture_buffer) return; + + rsxInvalidateTextureCache(gGcmContext,GCM_INVALIDATE_TEXTURE); + + texture.format = (GCM_TEXTURE_FORMAT_A8R8G8B8 | GCM_TEXTURE_FORMAT_LIN); + texture.mipmap = 1; + texture.dimension = GCM_TEXTURE_DIMS_2D; + texture.cubemap = GCM_FALSE; + texture.remap = ((GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_B_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_G_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_R_SHIFT) | + (GCM_TEXTURE_REMAP_TYPE_REMAP << GCM_TEXTURE_REMAP_TYPE_A_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_B << GCM_TEXTURE_REMAP_COLOR_B_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_G << GCM_TEXTURE_REMAP_COLOR_G_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_R << GCM_TEXTURE_REMAP_COLOR_R_SHIFT) | + (GCM_TEXTURE_REMAP_COLOR_A << GCM_TEXTURE_REMAP_COLOR_A_SHIFT)); + texture.width = width; + texture.height = height; + texture.depth = 1; + texture.location = GCM_LOCATION_RSX; + texture.pitch = pitch; + texture.offset = texture_offset; + rsxLoadTexture(gGcmContext,textureUnit_id,&texture); + rsxTextureControl(gGcmContext,textureUnit_id,GCM_TRUE,0<<8,12<<8,GCM_TEXTURE_MAX_ANISO_1); + rsxTextureFilter(gGcmContext,textureUnit_id,0,GCM_TEXTURE_LINEAR,GCM_TEXTURE_LINEAR,GCM_TEXTURE_CONVOLUTION_QUINCUNX); + rsxTextureWrapMode(gGcmContext,textureUnit_id,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,GCM_TEXTURE_CLAMP_TO_EDGE,0,GCM_TEXTURE_ZFUNC_LESS,0); +} + +static void setDrawEnv() +{ + rsxSetColorMask(gGcmContext,GCM_COLOR_MASK_B | + GCM_COLOR_MASK_G | + GCM_COLOR_MASK_R | + GCM_COLOR_MASK_A); + + rsxSetColorMaskMRT(gGcmContext,0); + + u16 x,y,w,h; + f32 min, max; + f32 scale[4],offset[4]; + + x = 0; + y = 0; + w = display_width; + h = display_height; + min = 0.0f; + max = 1.0f; + scale[0] = w*0.5f; + scale[1] = h*-0.5f; + scale[2] = (max - min)*0.5f; + scale[3] = 0.0f; + offset[0] = x + w*0.5f; + offset[1] = y + h*0.5f; + offset[2] = (max + min)*0.5f; + offset[3] = 0.0f; + + rsxSetViewport(gGcmContext,x, y, w, h, min, max, scale, offset); + rsxSetScissor(gGcmContext,x,y,w,h); + + rsxSetDepthTestEnable(gGcmContext,GCM_TRUE); + rsxSetDepthFunc(gGcmContext,GCM_LESS); + rsxSetShadeModel(gGcmContext,GCM_SHADE_MODEL_SMOOTH); + rsxSetDepthWriteEnable(gGcmContext,1); + rsxSetFrontFace(gGcmContext,GCM_FRONTFACE_CCW); +} + +void init_shader() +{ + u32 fpsize = 0; + u32 vpsize = 0; + + rsxVertexProgramGetUCode(vpo, &vp_ucode, &vpsize); + printf("vpsize: %d\n", vpsize); + + projMatrix_id = rsxVertexProgramGetConstIndex(vpo,"projMatrix"); + modelViewMatrix_id = rsxVertexProgramGetConstIndex(vpo,"modelViewMatrix"); + vertexPosition_id = rsxVertexProgramGetAttribIndex(vpo,"vertexPosition"); + vertexNormal_id = rsxVertexProgramGetAttribIndex(vpo,"vertexNormal"); + vertexTexcoord_id = rsxVertexProgramGetAttribIndex(vpo,"vertexTexcoord"); + + rsxFragmentProgramGetUCode(fpo, &fp_ucode, &fpsize); + printf("fpsize: %d\n", fpsize); + + fp_buffer = (u32*)rsxMemalign(64,fpsize); + memcpy(fp_buffer,fp_ucode,fpsize); + rsxAddressToOffset(fp_buffer,&fp_offset); + + textureUnit_id = rsxFragmentProgramGetAttribIndex(fpo,"texture"); + eyePosition_id = rsxFragmentProgramGetConstIndex(fpo,"eyePosition"); + globalAmbient_id = rsxFragmentProgramGetConstIndex(fpo,"globalAmbient"); + lightPosition_id = rsxFragmentProgramGetConstIndex(fpo,"lightPosition"); + lightColor_id = rsxFragmentProgramGetConstIndex(fpo,"lightColor"); + shininess_id = rsxFragmentProgramGetConstIndex(fpo,"shininess"); + Ks_id = rsxFragmentProgramGetConstIndex(fpo,"Ks"); + Kd_id = rsxFragmentProgramGetConstIndex(fpo,"Kd"); +} + +void drawFrame() +{ + u32 i,offset,color = 0; + Matrix4 rotX,rotY; + Vector4 objEyePos,objLightPos; + Matrix4 viewMatrix,modelMatrix,modelMatrixIT,modelViewMatrix; + Point3 lightPos = Point3(250.0f,150.0f,150.0f); + f32 globalAmbientColor[3] = {0.1f,0.1f,0.1f}; + f32 lightColor[3] = {0.95f,0.95f,0.95f}; + f32 materialColorDiffuse[3] = {0.5f,0.0f,0.0f}; + f32 materialColorSpecular[3] = {0.7f,0.6f,0.6f}; + f32 shininess = 17.8954f; + static f32 rot = 0.0f; + SMeshBuffer *mesh = NULL; + + setTexture(); + setDrawEnv(); + + rsxSetClearColor(gGcmContext,color); + rsxSetClearDepthStencil(gGcmContext,0xffffff00); + rsxClearSurface(gGcmContext,GCM_CLEAR_R | + GCM_CLEAR_G | + GCM_CLEAR_B | + GCM_CLEAR_A | + GCM_CLEAR_S | + GCM_CLEAR_Z); + + rsxSetZControl(gGcmContext,0,1,1); + + for(i=0;i<8;i++) + rsxSetViewportClip(gGcmContext,i,display_width,display_height); + + viewMatrix = Matrix4::lookAt(eye_pos,eye_dir,up_vec); + + mesh = sphere; + rotX = Matrix4::rotationX(DEGTORAD(30.0f)); + rotY = Matrix4::rotationY(DEGTORAD(rot)); + modelMatrix = rotX*rotY; + modelMatrixIT = inverse(modelMatrix); + modelViewMatrix = transpose(viewMatrix*modelMatrix); + + objEyePos = modelMatrixIT*eye_pos; + objLightPos = modelMatrixIT*lightPos; + + rsxAddressToOffset(&mesh->vertices[0].pos,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].u,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxLoadVertexProgram(gGcmContext,vpo,vp_ucode); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); + + rsxLoadFragmentProgramLocation(gGcmContext,fpo,fp_offset,GCM_LOCATION_RSX); + + rsxSetUserClipPlaneControl(gGcmContext,GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0],&offset); + rsxDrawIndexArray(gGcmContext,GCM_TYPE_TRIANGLES,offset,mesh->cnt_indices,GCM_INDEX_TYPE_16B,GCM_LOCATION_RSX); + + mesh = donut; + rotX = Matrix4::rotationX(DEGTORAD(rot)); + rotY = Matrix4::rotationY(DEGTORAD(30.0f)); + modelMatrix = rotX*rotY; + modelMatrix.setTranslation(Vector3(3.0f,5.0f,-8.0f)); + + modelMatrixIT = inverse(modelMatrix); + modelViewMatrix = transpose(viewMatrix*modelMatrix); + + objEyePos = modelMatrixIT*eye_pos; + objLightPos = modelMatrixIT*lightPos; + + rsxAddressToOffset(&mesh->vertices[0].pos,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexPosition_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].nrm,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexNormal_id,0,offset,sizeof(S3DVertex),3,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxAddressToOffset(&mesh->vertices[0].u,&offset); + rsxBindVertexArrayAttrib(gGcmContext,vertexTexcoord_id,0,offset,sizeof(S3DVertex),2,GCM_VERTEX_DATA_TYPE_F32,GCM_LOCATION_RSX); + + rsxLoadVertexProgram(gGcmContext,vpo,vp_ucode); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,projMatrix_id,(float*)&P); + rsxSetVertexProgramParameterByIndex(gGcmContext,vpo,modelViewMatrix_id,(float*)&modelViewMatrix); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,eyePosition_id,(float*)&objEyePos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,globalAmbient_id,globalAmbientColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightPosition_id,(float*)&objLightPos,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,lightColor_id,lightColor,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,shininess_id,&shininess,fp_offset,GCM_LOCATION_RSX); + + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Kd_id,materialColorDiffuse,fp_offset,GCM_LOCATION_RSX); + rsxSetFragmentProgramParameterByIndex(gGcmContext,fpo,Ks_id,materialColorSpecular,fp_offset,GCM_LOCATION_RSX); + + rsxLoadFragmentProgramLocation(gGcmContext,fpo,fp_offset,GCM_LOCATION_RSX); + + rsxSetUserClipPlaneControl(gGcmContext,GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE, + GCM_USER_CLIP_PLANE_DISABLE); + + rsxAddressToOffset(&mesh->indices[0],&offset); + rsxDrawIndexArray(gGcmContext,GCM_TYPE_TRIANGLES,offset,mesh->cnt_indices,GCM_INDEX_TYPE_16B,GCM_LOCATION_RSX); + + rot += 4.0f; + if(rot>=360.0f) rot = 0.0f; +} + +int main(int argc,const char *argv[]) +{ + padInfo padinfo; + padData paddata; + + printf("rsxtest_flip started...\n"); + + ioPadInit(7); + initScreen(); + + atexit(program_exit_callback); + sysUtilRegisterCallback(0,sysutil_exit_callback,NULL); + + init_shader(); + init_texture(); + + sphere = createSphere(3.0f,32,32); + donut = createDonut(3.0f,1.5f,32,32); + cube = createCube(5.0f); + + P = transpose(Matrix4::perspective(DEGTORAD(45.0f),aspect_ratio,1.0f,3000.0f)); + + setTexture(); + setDrawEnv(); + + running = 1; + while(running) { + sysUtilCheckCallback(); + + ioPadGetInfo(&padinfo); + for(int i=0; i < MAX_PADS; i++){ + if(padinfo.status[i]){ + ioPadGetData(i, &paddata); + + if(paddata.BTN_CROSS) + goto done; + } + } + + drawFrame(); + flip(); + } + +done: + printf("rsxtest_flip done...\n"); + finish(); + return 0; +} diff --git a/samples/graphics/rsxtest_tile/source/rsxutil.cpp b/samples/graphics/rsxtest_tile/source/rsxutil.cpp new file mode 100644 index 00000000..7dcb1507 --- /dev/null +++ b/samples/graphics/rsxtest_tile/source/rsxutil.cpp @@ -0,0 +1,308 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rsxutil.h" + +videoResolution vResolution; +gcmContextData *gGcmContext = NULL; + +u32 curr_fb = 0; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +void *depth_buffer; + +u32 color_pitch; +u32 color_offset[FRAME_BUFFER_COUNT]; +void *color_buffer[FRAME_BUFFER_COUNT]; + +f32 aspect_ratio; + +u32 fbOnDisplay = 0; +u32 fbFlipped = 0; +bool fbOnFlip = false; +sys_event_queue_t flipEventQueue; +sys_event_port_t flipEventPort; + +gcmSurface surface; + +static u32 sLabelVal = 1; + +static u32 sResolutionIds[] = { + VIDEO_RESOLUTION_960x1080, + VIDEO_RESOLUTION_720, + VIDEO_RESOLUTION_480, + VIDEO_RESOLUTION_576 +}; +static size_t RESOLUTION_ID_COUNT = sizeof(sResolutionIds)/sizeof(u32); + +extern "C" { +static void flipHandler(const u32 head) +{ + (void)head; + u32 v = fbFlipped; + + for (u32 i = fbOnDisplay; i != v; i=(i + 1)%FRAME_BUFFER_COUNT) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + fbOnDisplay = v; + fbOnFlip = false; + + sysEventPortSend(flipEventPort, 0, 0, 0); +} + +static void vblankHandler(const u32 head) +{ + (void)head; + u32 data; + u32 bufferToFlip; + u32 indexToFlip; + + data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + bufferToFlip = (data >> 8); + indexToFlip = (data & 0x07); + + if (!fbOnFlip) { + if (bufferToFlip != fbOnDisplay) { + s32 ret = gcmSetFlipImmediate(indexToFlip); + if (ret != 0) { + printf("flip immediate failed\n"); + return; + } + fbFlipped = bufferToFlip; + fbOnFlip = true; + } + } +} +} + +static void syncPPUGPU() +{ + vu32 *label = (vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX); + while(((curr_fb + FRAME_BUFFER_COUNT - ((*label)>>8))%FRAME_BUFFER_COUNT) > MAX_BUFFER_QUEUE_SIZE) { + sys_event_t event; + + sysEventQueueReceive(flipEventQueue, &event, 0); + sysEventQueueDrain(flipEventQueue); + } +} + +static void waitRSXFinish() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(gGcmContext); + + while(*(vu32*)gcmGetLabelAddress(GCM_WAIT_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(gGcmContext,GCM_WAIT_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitRSXFinish(); +} + +void initVideoConfiguration() +{ + s32 rval = 0; + s32 resId = 0; + + for (size_t i=0;i < RESOLUTION_ID_COUNT;i++) { + rval = videoGetResolutionAvailability(VIDEO_PRIMARY, sResolutionIds[i], VIDEO_ASPECT_AUTO, 0); + if (rval != 1) continue; + + resId = sResolutionIds[i]; + rval = videoGetResolution(resId, &vResolution); + if(!rval) break; + } + + if(rval) { + printf("Error: videoGetResolutionAvailability failed. No usable resolution.\n"); + exit(1); + } + + videoConfiguration config = { + (u8)resId, + VIDEO_BUFFER_FORMAT_XRGB, + VIDEO_ASPECT_AUTO, + {0,0,0,0,0,0,0,0,0}, + gcmGetTiledPitchSize(vResolution.width*4) + }; + + rval = videoConfigure(VIDEO_PRIMARY, &config, NULL, 0); + if(rval) { + printf("Error: videoConfigure failed.\n"); + exit(1); + } + + videoState state; + + rval = videoGetState(VIDEO_PRIMARY, 0, &state); + switch(state.displayMode.aspect) { + case VIDEO_ASPECT_4_3: + aspect_ratio = 4.0f/3.0f; + break; + case VIDEO_ASPECT_16_9: + aspect_ratio = 16.0f/9.0f; + break; + default: + printf("unknown aspect ratio %x\n", state.displayMode.aspect); + aspect_ratio = 16.0f/9.0f; + break; + } + + display_height = vResolution.height; + display_width = vResolution.width; +} + +void initFlipEvent() +{ + sys_event_queue_attr_t queueAttr = { SYS_EVENT_QUEUE_PRIO, SYS_EVENT_QUEUE_PPU, "\0" }; + + sysEventQueueCreate(&flipEventQueue, &queueAttr, SYS_EVENT_QUEUE_KEY_LOCAL, 32); + sysEventPortCreate(&flipEventPort, SYS_EVENT_PORT_LOCAL, SYS_EVENT_PORT_NO_NAME); + sysEventPortConnectLocal(flipEventPort, flipEventQueue); + + gcmSetFlipHandler(flipHandler); + gcmSetVBlankHandler(vblankHandler); +} + +void initRenderTarget() +{ + memset(&surface, 0, sizeof(gcmSurface)); + + surface.colorFormat = GCM_SURFACE_X8R8G8B8; + surface.colorTarget = GCM_SURFACE_TARGET_0; + surface.colorLocation[0] = GCM_LOCATION_RSX; + surface.colorOffset[0] = color_offset[curr_fb]; + surface.colorPitch[0] = color_pitch; + + for(u32 i=1; i< GCM_MAX_MRT_COUNT;i++) { + surface.colorLocation[i] = GCM_LOCATION_RSX; + surface.colorOffset[i] = color_offset[curr_fb]; + surface.colorPitch[i] = 64; + } + + surface.depthFormat = GCM_SURFACE_ZETA_Z24S8; + surface.depthLocation = GCM_LOCATION_RSX; + surface.depthOffset = depth_offset; + surface.depthPitch = depth_pitch; + + surface.type = GCM_SURFACE_TYPE_LINEAR; + surface.antiAlias = GCM_SURFACE_CENTER_1; + + surface.width = display_width; + surface.height = display_height; + surface.x = 0; + surface.y = 0; +} + +void setRenderTarget(u32 index) +{ + surface.colorOffset[0] = color_offset[index]; + rsxSetSurface(gGcmContext,&surface); +} + +void initScreen() +{ + u32 zs_depth = 4; + u32 color_depth = 4; + u32 bufferSize = rsxAlign(HOST_ADDR_ALIGNMENT, (DEFAULT_CB_SIZE + HOST_SIZE)); + + gcmInitDefaultFifoMode(GCM_DEFAULT_FIFO_MODE_CONDITIONAL); + + void *hostAddr = memalign(HOST_ADDR_ALIGNMENT, bufferSize); + rsxInit(&gGcmContext, DEFAULT_CB_SIZE, bufferSize, hostAddr); + + initVideoConfiguration(); + + waitRSXIdle(); + + gcmSetFlipMode(GCM_FLIP_HSYNC); + + color_pitch = gcmGetTiledPitchSize(display_width*color_depth); + depth_pitch = gcmGetTiledPitchSize(display_width*zs_depth); + + u32 tileIndex = 0; + u32 bufferHeight = rsxAlign(GCM_TILE_LOCAL_ALIGN_HEIGHT, display_height); + u32 colorBufferSize = bufferHeight*color_pitch; + u32 depthBufferSize = bufferHeight*depth_pitch; + for (u32 i=0; i < FRAME_BUFFER_COUNT;i++, tileIndex++) { + bufferSize = rsxAlign(GCM_TILE_ALIGN_OFFSET, colorBufferSize); + color_buffer[i] = rsxMemalign(GCM_TILE_ALIGN_SIZE, bufferSize); + rsxAddressToOffset(color_buffer[i], &color_offset[i]); + gcmSetDisplayBuffer(i, color_offset[i], color_pitch, display_width, display_height); + gcmSetTileInfo(tileIndex, GCM_LOCATION_RSX, color_offset[i], bufferSize, color_pitch, GCM_COMPMODE_DISABLED, 0, 0); + gcmBindTile(tileIndex); + printf("fb[%d]: %p (%08x) [%dx%d] %d\n", i, color_buffer[i], color_offset[i], display_width, display_height, color_pitch); + } + + bufferSize = rsxAlign(GCM_TILE_ALIGN_OFFSET, depthBufferSize); + depth_buffer = rsxMemalign(GCM_TILE_ALIGN_SIZE, bufferSize); + rsxAddressToOffset(depth_buffer, &depth_offset); + gcmSetTileInfo(tileIndex, GCM_LOCATION_RSX, depth_offset, bufferSize, depth_pitch, GCM_COMPMODE_Z32_SEPSTENCIL, 0, 2); + gcmBindTile(tileIndex); + + gcmSetZcull(0, depth_offset, rsxAlign(64, display_width), rsxAlign(64, display_height), 0, GCM_ZCULL_Z24S8, GCM_SURFACE_CENTER_1, GCM_ZCULL_LESS, GCM_ZCULL_LONES, GCM_SCULL_SFUNC_LESS, 1, 0xff); + + for (u32 i=0;i < FRAME_BUFFER_COUNT;i++) { + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + i)) = BUFFER_IDLE; + } + *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)) = (fbOnDisplay << 8); + *((vu32*) gcmGetLabelAddress(GCM_BUFFER_STATUS_INDEX + fbOnDisplay)) = BUFFER_BUSY; + + curr_fb = (fbOnDisplay + 1)%FRAME_BUFFER_COUNT; + + initFlipEvent(); + initRenderTarget(); + + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); +} + +void flip() +{ + s32 qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + while (qid < 0) { + usleep(100); + qid = gcmSetPrepareFlip(gGcmContext, curr_fb); + } + + rsxSetWriteBackendLabel(gGcmContext, GCM_PREPARED_BUFFER_INDEX, ((curr_fb << 8) | qid)); + rsxFlushBuffer(gGcmContext); + + syncPPUGPU(); + + curr_fb = (curr_fb + 1)%FRAME_BUFFER_COUNT; + + rsxSetWaitLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_IDLE); + rsxSetWriteCommandLabel(gGcmContext, GCM_BUFFER_STATUS_INDEX + curr_fb, BUFFER_BUSY); + + setRenderTarget(curr_fb); +} + +void finish() +{ + rsxFinish(gGcmContext,1); + + u32 data = *((vu32*) gcmGetLabelAddress(GCM_PREPARED_BUFFER_INDEX)); + u32 lastBuffer = (data >> 8); + while (lastBuffer != fbOnDisplay) + usleep(100); +} diff --git a/samples/graphics/videoTest/source/rsxutil.c b/samples/graphics/videoTest/source/rsxutil.c index bce58746..ec417867 100644 --- a/samples/graphics/videoTest/source/rsxutil.c +++ b/samples/graphics/videoTest/source/rsxutil.c @@ -108,7 +108,7 @@ initScreen (void *host_addr, u32 size) videoResolution res; /* Screen Resolution */ /* Initilise Reality, which sets up the command buffer and shared IO memory */ - context = rsxInit (CB_SIZE, size, host_addr); + rsxInit (&context, CB_SIZE, size, host_addr); if (context == NULL) goto error; @@ -191,8 +191,8 @@ setRenderTarget(gcmContextData *context, rsxBuffer *buffer) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = buffer->offset; sf.colorPitch[0] = depth_pitch; @@ -207,13 +207,13 @@ setRenderTarget(gcmContextData *context, rsxBuffer *buffer) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_TEXTURE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = buffer->width; sf.height = buffer->height; diff --git a/samples/network/httptest/Makefile b/samples/network/httptest/Makefile new file mode 100644 index 00000000..f93ba9e4 --- /dev/null +++ b/samples/network/httptest/Makefile @@ -0,0 +1,140 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include + +TITLE := HTTP sample - PSL1GHT +APPID := DEBUGPR01 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lrsx -lgcm_sys -lio -lsysutil -lrt -llv2 -lm -lnet -lsysmodule -lssl -lhttp -lhttputil + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/network/httptest/source/http.c b/samples/network/httptest/source/http.c new file mode 100644 index 00000000..d3b68ae8 --- /dev/null +++ b/samples/network/httptest/source/http.c @@ -0,0 +1,319 @@ +#include +#include +#include +#include + +#include +#include +#include + +#define HTTP_YES 1 +#define HTTP_NO 0 +#define HTTP_SUCCESS 1 +#define HTTP_FAILED 0 + +#define HTTP_USER_AGENT "Mozilla/5.0 (PLAYSTATION 3; 1.00)" + +typedef struct +{ + void* http_pool; + void* ssl_pool; + httpsData* caList; + void* cert_buffer; +} t_http_pools; + +static t_http_pools http_pools; +u8 cancel = HTTP_NO; + +static char getBuffer[64*1024]; + + +int http_init(void) +{ + int ret; + u32 cert_size=0; + u8 module_https_loaded=HTTP_NO; + u8 module_http_loaded=HTTP_NO; + u8 module_net_loaded=HTTP_NO; + u8 module_ssl_loaded=HTTP_NO; + + u8 https_init=HTTP_NO; + u8 http_init=HTTP_NO; + u8 net_init=HTTP_NO; + u8 ssl_init=HTTP_NO; + + //init + ret = sysModuleLoad(SYSMODULE_NET); + if (ret < 0) { + printf("Error : sysModuleLoad(SYSMODULE_NET) HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else module_net_loaded=HTTP_YES; + + ret = netInitialize(); + if (ret < 0) { + printf("Error : netInitialize HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else net_init=HTTP_YES; + + ret = sysModuleLoad(SYSMODULE_HTTP); + if (ret < 0) { + printf("Error : sysModuleLoad(SYSMODULE_HTTP) HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else module_http_loaded=HTTP_YES; + + http_pools.http_pool = malloc(0x10000); + if (http_pools.http_pool == NULL) { + printf("Error : out of memory (http_pool)"); + ret=HTTP_FAILED; + goto end; + } + + ret = httpInit(http_pools.http_pool, 0x10000); + if (ret < 0) { + printf("Error : httpInit HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else http_init=HTTP_YES; + + ret = sysModuleLoad(SYSMODULE_HTTPS); + if (ret < 0) { + printf("Error : sysModuleLoad(SYSMODULE_HTTP) HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else module_https_loaded=HTTP_YES; + + ret = sysModuleLoad(SYSMODULE_SSL); + if (ret < 0) { + printf("Error : sysModuleLoad(SYSMODULE_HTTP) HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else module_ssl_loaded=HTTP_YES; + + http_pools.ssl_pool = malloc(0x40000); + if (http_pools.ssl_pool == NULL) { + printf("Error : out of memory (ssl_pool)"); + ret=HTTP_FAILED; + goto end; + } + + ret = sslInit(http_pools.ssl_pool, 0x40000); + if (ret < 0) { + printf("Error : sslInit HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else ssl_init=HTTP_YES; + + http_pools.caList = (httpsData *)malloc(sizeof(httpsData)); + ret = sslCertificateLoader(SSL_LOAD_CERT_ALL, NULL, 0, &cert_size); + if (ret < 0) { + printf("Error : sslCertificateLoader HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + http_pools.cert_buffer = malloc(cert_size); + if (http_pools.cert_buffer==NULL) { + printf("Error : out of memory (cert_buffer)"); + ret=HTTP_FAILED; + goto end; + } + + ret = sslCertificateLoader(SSL_LOAD_CERT_ALL, http_pools.cert_buffer, cert_size, NULL); + if (ret < 0) { + printf("Error : sslCertificateLoader HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + (&http_pools.caList[0])->ptr = http_pools.cert_buffer; + (&http_pools.caList[0])->size = cert_size; + + ret = httpsInit(1, (httpsData *) http_pools.caList); + if (ret < 0) { + printf("Error : httpsInit HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } else https_init=HTTP_YES; + + return HTTP_SUCCESS; + +end: + if(http_pools.caList) free(http_pools.caList); + if(https_init) httpsEnd(); + if(ssl_init) sslEnd(); + if(http_init) httpEnd(); + if(net_init) netDeinitialize(); + + if(module_http_loaded) sysModuleUnload(SYSMODULE_HTTP); + if(module_https_loaded) sysModuleUnload(SYSMODULE_HTTPS); + if(module_ssl_loaded) sysModuleUnload(SYSMODULE_SSL); + if(module_net_loaded) sysModuleUnload(SYSMODULE_NET); + + if(http_pools.http_pool) free(http_pools.http_pool); + if(http_pools.ssl_pool) free(http_pools.ssl_pool); + if(http_pools.cert_buffer) free(http_pools.cert_buffer); + + return ret; +} + +void http_end(void) +{ + if(http_pools.caList) free(http_pools.caList); + httpsEnd(); + sslEnd(); + httpEnd(); + netDeinitialize(); + + sysModuleUnload(SYSMODULE_HTTP); + sysModuleUnload(SYSMODULE_HTTPS); + sysModuleUnload(SYSMODULE_SSL); + sysModuleUnload(SYSMODULE_NET); + + if(http_pools.http_pool) free(http_pools.http_pool); + if(http_pools.ssl_pool) free(http_pools.ssl_pool); + if(http_pools.cert_buffer) free(http_pools.cert_buffer); + + return; +} + +char* escape_filename(const char* filename) +{ + int len = strlen(filename); + char* ret = (char *)calloc(1, len*3); + + httpUtilEscapeUri(ret, len*3, (uint8_t*) filename, len, 0); + + return ret; +} + +int http_download(const char* url, const char* filename, const char* local_dst) +{ + int ret = 0, httpCode = 0; + httpUri uri; + httpClientId httpClient = 0; + httpTransId httpTrans = 0; + FILE* fp=NULL; + u32 nRecv = 1; + u32 size = 0; + uint64_t length = 0; + void *uri_pool = NULL; + char* escaped_name = NULL; + char* escaped_url = NULL; + + ret = httpCreateClient(&httpClient); + if (ret < 0) { + printf("Error : httpCreateClient HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + httpClientSetConnTimeout(httpClient, 10 * 1000 * 1000); + httpClientSetUserAgent(httpClient, HTTP_USER_AGENT); + httpClientSetAutoRedirect(httpClient, 1); + + // Escape URL file name characters + escaped_name = escape_filename(filename); + asprintf(&escaped_url, "%s%s", url, escaped_name); + + printf("Downloading (%s) -> (%s)", escaped_url, local_dst); + + //URI + ret = httpUtilParseUri(&uri, escaped_url, NULL, 0, &size); + if (ret < 0) { + printf("Error : httpUtilParseUri() HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + uri_pool = malloc(size); + if (uri_pool == NULL) { + printf("Error : out of memory (uri_pool)"); + ret=HTTP_FAILED; + goto end; + } + + ret = httpUtilParseUri(&uri, escaped_url, uri_pool, size, 0); + if (ret < 0) { + printf("Error : httpUtilParseUri() HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + //END of URI + + //SEND REQUEST + ret = httpCreateTransaction(&httpTrans, httpClient, HTTP_METHOD_GET, &uri); + if (ret < 0) { + printf("Error : httpCreateTransaction() HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + ret = httpSendRequest(httpTrans, NULL, 0, NULL); + if (ret < 0) { + printf("Error : httpSendRequest() HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + //GET SIZE + httpResponseGetContentLength(httpTrans, &length); + + ret = httpResponseGetStatusCode(httpTrans, &httpCode); + if (ret < 0) { + printf("Error : cellHttpResponseGetStatusCode() HTTP_FAILED (%x)", ret); + ret=HTTP_FAILED; + goto end; + } + + if(httpCode != HTTP_STATUS_CODE_OK && httpCode >= 400 ) { + printf("Error : Status code (%d)", httpCode); + ret=HTTP_FAILED; + goto end; + } + + //TRANSFER + fp = fopen(local_dst, "wb"); + if(fp == NULL) { + printf("Error : fopen() HTTP_FAILED : %s", local_dst); + ret=HTTP_FAILED; + goto end; + } + + while(nRecv != 0) { + if(httpRecvResponse(httpTrans, (void*) getBuffer, sizeof(getBuffer)-1, &nRecv) > 0) break; + if(nRecv == 0) break; + fwrite((char*) getBuffer, nRecv, 1, fp); + if(cancel==HTTP_YES) break; + } + fclose(fp); + + if(cancel==HTTP_YES) { + unlink((char*)local_dst); + ret=HTTP_FAILED; + cancel=HTTP_NO; + } + + //END of TRANSFER + ret=HTTP_SUCCESS; + +end: + if(httpTrans) httpDestroyTransaction(httpTrans); + if(httpClient) httpDestroyClient(httpClient); + if(uri_pool) free(uri_pool); + if(escaped_url) free(escaped_url); + if(escaped_name) free(escaped_name); + + return ret; +} + +s32 main(s32 argc, const char* argv[]) +{ + if (http_init() == HTTP_SUCCESS) + { + http_download("https://google.com/", "robots.txt", "/dev_hdd0/tmp/file.txt"); + http_end(); + } + return 0; +} diff --git a/samples/network/ps3load/Makefile b/samples/network/ps3load/Makefile index 5690d720..b40b9189 100644 --- a/samples/network/ps3load/Makefile +++ b/samples/network/ps3load/Makefile @@ -114,6 +114,9 @@ clean: run: ps3load $(OUTPUT).self +#--------------------------------------------------------------------------------- +pkg: $(BUILD) $(OUTPUT).pkg + #--------------------------------------------------------------------------------- else diff --git a/samples/network/ps3load/source/main.c b/samples/network/ps3load/source/main.c index 7ed6c9af..ad0bfa55 100644 --- a/samples/network/ps3load/source/main.c +++ b/samples/network/ps3load/source/main.c @@ -79,12 +79,10 @@ static void empty_directory(const char *path) static void control_thread(void *arg) { - u32 btns; - printf("PS3Load Control thread\n"); while(running) { - btns = pad_read(); + (void)pad_read(); flip(); } diff --git a/samples/network/ps3load/source/rsxutil.c b/samples/network/ps3load/source/rsxutil.c index b7803e6f..df37acfd 100644 --- a/samples/network/ps3load/source/rsxutil.c +++ b/samples/network/ps3load/source/rsxutil.c @@ -53,8 +53,8 @@ void set_render_target(u32 index) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = color_offset[index]; sf.colorPitch[0] = color_pitch; @@ -69,13 +69,13 @@ void set_render_target(u32 index) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_TEXTURE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = display_width; sf.height = display_height; @@ -87,7 +87,7 @@ void set_render_target(u32 index) void init_screen(void *host_addr,u32 size) { - context = rsxInit(CB_SIZE,size,host_addr); + rsxInit(&context, CB_SIZE,size,host_addr); videoState state; videoGetState(0,0,&state); diff --git a/samples/spu/Makefile b/samples/spu/Makefile index 0f1e94d9..0d735cb0 100644 --- a/samples/spu/Makefile +++ b/samples/spu/Makefile @@ -1,4 +1,4 @@ -TARGETS := spuchain spudma sputest sputhread spuparallel +TARGETS := spuchain spudma sputest sputhread spuparallel spumars all: @for TARGET in $(TARGETS); do $(MAKE) --no-print-directory -C $$TARGET bin; done diff --git a/samples/spu/spumars/Makefile b/samples/spu/spumars/Makefile new file mode 100644 index 00000000..e517ccab --- /dev/null +++ b/samples/spu/spumars/Makefile @@ -0,0 +1,146 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/ppu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := + +TITLE := SPU MARS sample - PSL1GHT +APPID := SPUMARS001 +CONTENTID := UP0001-$(APPID)_00-0000000000000000 +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lspumars -lrt -llv2 -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) \ + spu.bin + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean bin + +#--------------------------------------------------------------------------------- +$(BUILD): bin + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +bin: + @$(MAKE) --no-print-directory -C spu + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @$(MAKE) --no-print-directory -C spu clean + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).self $(DATA)/spu.bin + +#--------------------------------------------------------------------------------- +run: + ps3load $(OUTPUT).self + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).self: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .bin extension +#--------------------------------------------------------------------------------- +%.bin.o: %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/spu/spumars/data/.gitignore b/samples/spu/spumars/data/.gitignore new file mode 100644 index 00000000..900ec39a --- /dev/null +++ b/samples/spu/spumars/data/.gitignore @@ -0,0 +1 @@ +spu.bin diff --git a/samples/spu/spumars/source/main.c b/samples/spu/spumars/source/main.c new file mode 100644 index 00000000..7d03ecca --- /dev/null +++ b/samples/spu/spumars/source/main.c @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "spu_bin.h" + +#define NUM_TASKS 10 + +int main(int argc,char *argv[]) +{ + struct mars_task_args task_args; + struct mars_context *mars_ctx; + struct mars_task_id task_id[NUM_TASKS]; + int i; + u64 barrier_ea; + + sysSpuInitialize(6,0); + sysSpuPrintfInitialize(200, NULL); + + mars_context_create(&mars_ctx, 6, 200, 100); + mars_task_barrier_create(mars_ctx, &barrier_ea, NUM_TASKS); + + for(i=0;i < NUM_TASKS;i++) { + char name[16]; + + sprintf(name, "Task %d", i); + + mars_task_create(mars_ctx, &task_id[i], name, spu_bin, MARS_TASK_CONTEXT_SAVE_SIZE_MAX); + + task_args.type.u64[0] = barrier_ea; + mars_task_schedule(&task_id[i], &task_args, 0); + } + + for(i=0;i < NUM_TASKS;i++) { + mars_task_wait(&task_id[i], NULL); + mars_task_destroy(&task_id[i]); + } + + mars_task_barrier_destroy(barrier_ea); + mars_context_destroy(mars_ctx); + + return 0; +} \ No newline at end of file diff --git a/samples/spu/spumars/spu/Makefile b/samples/spu/spumars/spu/Makefile new file mode 100644 index 00000000..17a6df1b --- /dev/null +++ b/samples/spu/spumars/spu/Makefile @@ -0,0 +1,126 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/spu_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +CFLAGS = -O2 -Wall $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) + +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := -lspumars -lsputhread + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +export BUILDDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES), -I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + $(LIBPSL1GHT_INC) \ + -I$(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + $(LIBPSL1GHT_LIB) + +export OUTPUT := $(CURDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +../../data/spu.bin: $(OUTPUT).task + cp $< $@ + +$(OUTPUT).task: $(OFILES) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/samples/spu/spumars/spu/source/main.c b/samples/spu/spumars/spu/source/main.c new file mode 100644 index 00000000..d3910c1a --- /dev/null +++ b/samples/spu/spumars/spu/source/main.c @@ -0,0 +1,22 @@ +#include +#include +#include + +#define ITERATIONS 3 + +int mars_task_main(const struct mars_task_args *task_args) +{ + int i; + uint64_t barrier_ea = task_args->type.u64[0]; + + spu_printf("MPU(%d): %s - Hello!\n", mars_task_get_kernel_id(), mars_task_get_name()); + + for(i=0;i < ITERATIONS;i++) { + spu_printf("MPU(%d): %s pre barrier work\n", mars_task_get_kernel_id(), mars_task_get_name()); + mars_task_barrier_notify(barrier_ea); + mars_task_barrier_wait(barrier_ea); + spu_printf("MPU(%d): %s post barrier work\n", mars_task_get_kernel_id(), mars_task_get_name()); + } + + return 0; +} diff --git a/samples/spu/spuparallel/source/main.c b/samples/spu/spuparallel/source/main.c index 7ef041c6..eabdc045 100644 --- a/samples/spu/spuparallel/source/main.c +++ b/samples/spu/spuparallel/source/main.c @@ -41,8 +41,8 @@ int main(int argc, const char* argv[]) { sysSpuImage image; u32 group_id; - sysSpuThreadAttribute attr = { ptr2ea("mythread"), 8+1, SPU_THREAD_ATTR_NONE }; - sysSpuThreadGroupAttribute grpattr = { 7+1, ptr2ea("mygroup"), 0, 0 }; + sysSpuThreadAttribute attr = { "mythread", 8+1, SPU_THREAD_ATTR_NONE }; + sysSpuThreadGroupAttribute grpattr = { 7+1, "mygroup", 0, {0} }; sysSpuThreadArgument arg[6]; u32 cause, status; int i; diff --git a/samples/spu/spurs/Makefile b/samples/spu/spurs/Makefile index a7d93395..003195c1 100644 --- a/samples/spu/spurs/Makefile +++ b/samples/spu/spurs/Makefile @@ -30,7 +30,7 @@ CONTENTID := UP0001-$(APPID)_00-0000000000000000 # options for code generation #--------------------------------------------------------------------------------- -CFLAGS = -Os -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) +CFLAGS = -O2 -Wall -mcpu=cell $(MACHDEP) $(INCLUDE) CXXFLAGS = $(CFLAGS) LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map diff --git a/samples/spu/spurs/source/main.c b/samples/spu/spurs/source/main.c index 36f37042..e5266bd1 100644 --- a/samples/spu/spurs/source/main.c +++ b/samples/spu/spurs/source/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -27,7 +28,7 @@ int main(void) printf("sysSpuInitialize return %d\n",ret); ret= sysThreadGetId(&ppu_thread_id); - printf("sysThreadGetId return %d ppu_thread_id %x\n",ret,ppu_thread_id); + printf("sysThreadGetId return %d ppu_thread_id %lx\n",ret,ppu_thread_id); ret = sysThreadGetPriority(ppu_thread_id, &ppu_prio); printf("sysThreadGetPriority return %d ppu_prio %d\n",ret,ppu_prio); diff --git a/samples/sys/msgdialog/include/rsxutil.h b/samples/sys/msgdialog/include/rsxutil.h index cbf41557..5bc22475 100644 --- a/samples/sys/msgdialog/include/rsxutil.h +++ b/samples/sys/msgdialog/include/rsxutil.h @@ -1,28 +1,21 @@ #ifndef __RSXUTIL_H__ #define __RSXUTIL_H__ +#include + #include -#include #define CB_SIZE 0x100000 #define HOST_SIZE (32*1024*1024) -#ifdef __cplusplus -extern "C" { -#endif - extern gcmContextData *context; extern u32 display_width; extern u32 display_height; extern u32 curr_fb; -void set_render_target(u32 index); +void setRenderTarget(u32 index); void init_screen(void *host_addr,u32 size); void waitflip(); void flip(); -#ifdef __cplusplus - } -#endif - #endif diff --git a/samples/sys/msgdialog/source/main.c b/samples/sys/msgdialog/source/main.cpp similarity index 72% rename from samples/sys/msgdialog/source/main.c rename to samples/sys/msgdialog/source/main.cpp index 0722da5e..9acffda6 100644 --- a/samples/sys/msgdialog/source/main.c +++ b/samples/sys/msgdialog/source/main.cpp @@ -13,12 +13,7 @@ static vs32 dialog_action = 0; -static void do_flip() -{ - sysUtilCheckCallback(); - flip(); -} - +extern "C" { static void dialog_handler(msgButton button,void *usrData) { switch(button) { @@ -37,13 +32,13 @@ static void dialog_handler(msgButton button,void *usrData) } } -void program_exit_callback() +static void program_exit_callback() { gcmSetWaitFlip(context); rsxFinish(context,1); } -void sysutil_exit_callback(u64 status,u64 param,void *usrdata) +static void sysutil_exit_callback(u64 status,u64 param,void *usrdata) { switch(status) { case SYSUTIL_EXIT_GAME: @@ -55,20 +50,26 @@ void sysutil_exit_callback(u64 status,u64 param,void *usrdata) break; } } +} + +static void do_flip() +{ + sysUtilCheckCallback(); + flip(); +} int main(int argc,char *argv[]) { - s32 ret; - msgType dialogType; - void *host_addr = memalign(1024*1024,HOST_SIZE); + msgType dialogType; + void *host_addr = memalign(1024*1024,HOST_SIZE); - printf("msgdialog test...\n"); + printf("msgdialog test...\n"); init_screen(host_addr,HOST_SIZE); ioPadInit(7); - ret = atexit(program_exit_callback); - ret = sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0,sysutil_exit_callback,NULL); + atexit(program_exit_callback); + sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0,sysutil_exit_callback,NULL); msgDialogOpenErrorCode(0xBADC0FFE,dialog_handler,NULL,NULL); msgDialogClose(3000.0f); @@ -78,9 +79,9 @@ int main(int argc,char *argv[]) do_flip(); msgDialogAbort(); - + // yes/no dialog type - dialogType = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_YESNO | MSG_DIALOG_DISABLE_CANCEL_ON | MSG_DIALOG_DEFAULT_CURSOR_NO); + dialogType = (msgType)(MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_YESNO | MSG_DIALOG_DISABLE_CANCEL_ON | MSG_DIALOG_DEFAULT_CURSOR_NO); msgDialogOpen2(dialogType,"Do you want to continue?",dialog_handler,NULL,NULL); dialog_action = 0; @@ -90,7 +91,7 @@ int main(int argc,char *argv[]) msgDialogAbort(); // OK dialog type - dialogType = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_OK); + dialogType = (msgType)(MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_OK); if(dialog_action==1) msgDialogOpen2(dialogType,"Your answer was YES",dialog_handler,NULL,NULL); else @@ -102,5 +103,6 @@ int main(int argc,char *argv[]) msgDialogAbort(); - return 0; + printf("msgdialog test done...\n"); + return 0; } diff --git a/samples/sys/msgdialog/source/rsxutil.c b/samples/sys/msgdialog/source/rsxutil.cpp similarity index 85% rename from samples/sys/msgdialog/source/rsxutil.c rename to samples/sys/msgdialog/source/rsxutil.cpp index b7803e6f..01e6a667 100644 --- a/samples/sys/msgdialog/source/rsxutil.c +++ b/samples/sys/msgdialog/source/rsxutil.cpp @@ -3,6 +3,10 @@ #include #include #include +#include + +#include +#include #include "rsxutil.h" @@ -27,7 +31,7 @@ u32 *color_buffer[2]; static u32 sLabelVal = 1; -static void wait_finish() +static void waitFinish() { rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); @@ -39,22 +43,22 @@ static void wait_finish() ++sLabelVal; } -static void wait_rsx_idle() +static void waitRSXIdle() { rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); ++sLabelVal; - wait_finish(); + waitFinish(); } -void set_render_target(u32 index) +void setRenderTarget(u32 index) { gcmSurface sf; - sf.colorFormat = GCM_TF_COLOR_X8R8G8B8; - sf.colorTarget = GCM_TF_TARGET_0; + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; sf.colorLocation[0] = GCM_LOCATION_RSX; sf.colorOffset[0] = color_offset[index]; sf.colorPitch[0] = color_pitch; @@ -69,13 +73,13 @@ void set_render_target(u32 index) sf.colorPitch[2] = 64; sf.colorPitch[3] = 64; - sf.depthFormat = GCM_TF_ZETA_Z16; + sf.depthFormat = GCM_SURFACE_ZETA_Z16; sf.depthLocation = GCM_LOCATION_RSX; sf.depthOffset = depth_offset; sf.depthPitch = depth_pitch; - sf.type = GCM_TF_TYPE_LINEAR; - sf.antiAlias = GCM_TF_CENTER_1; + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; sf.width = display_width; sf.height = display_height; @@ -87,7 +91,7 @@ void set_render_target(u32 index) void init_screen(void *host_addr,u32 size) { - context = rsxInit(CB_SIZE,size,host_addr); + rsxInit(&context,CB_SIZE,size,host_addr); videoState state; videoGetState(0,0,&state); @@ -101,7 +105,7 @@ void init_screen(void *host_addr,u32 size) vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; vconfig.pitch = res.width*sizeof(u32); - wait_rsx_idle(); + waitRSXIdle(); videoConfigure(0,&vconfig,NULL,0); videoGetState(0,0,&state); @@ -144,7 +148,7 @@ void flip() gcmSetWaitFlip(context); curr_fb ^= 1; - set_render_target(curr_fb); + setRenderTarget(curr_fb); first_fb = 0; } diff --git a/samples/sys/osk/include/rsxutil.h b/samples/sys/osk/include/rsxutil.h index cbf41557..5bc22475 100644 --- a/samples/sys/osk/include/rsxutil.h +++ b/samples/sys/osk/include/rsxutil.h @@ -1,28 +1,21 @@ #ifndef __RSXUTIL_H__ #define __RSXUTIL_H__ +#include + #include -#include #define CB_SIZE 0x100000 #define HOST_SIZE (32*1024*1024) -#ifdef __cplusplus -extern "C" { -#endif - extern gcmContextData *context; extern u32 display_width; extern u32 display_height; extern u32 curr_fb; -void set_render_target(u32 index); +void setRenderTarget(u32 index); void init_screen(void *host_addr,u32 size); void waitflip(); void flip(); -#ifdef __cplusplus - } -#endif - #endif diff --git a/samples/sys/osk/source/main.c b/samples/sys/osk/source/main.cpp similarity index 94% rename from samples/sys/osk/source/main.c rename to samples/sys/osk/source/main.cpp index 7108bd83..1b65bee6 100644 --- a/samples/sys/osk/source/main.c +++ b/samples/sys/osk/source/main.cpp @@ -13,6 +13,8 @@ #include "rsxutil.h" +#define TEXT_BUFFER_LENGTH 256 + static vs32 dialog_action = 0; uint8_t isRunningOSK = 0; @@ -20,6 +22,55 @@ oskInputFieldInfo inputFieldInfo; oskParam parameters; oskCallbackReturnParam outputParam; +extern "C" { +static void program_exit_callback() +{ + gcmSetWaitFlip(context); + rsxFinish(context, 1); +} + +static void sysutil_exit_callback(u64 status, u64 param, void *usrdata) +{ + switch(status) { + case SYSUTIL_EXIT_GAME: + break; + case SYSUTIL_DRAW_BEGIN: + case SYSUTIL_DRAW_END: + break; + case SYSUTIL_OSK_LOADED: + printf("OSK loaded\n"); + break; + case SYSUTIL_OSK_INPUT_CANCELED: + printf("OSK input canceled\n"); + oskAbort(); + // fall-through + case SYSUTIL_OSK_DONE: + if (status == SYSUTIL_OSK_DONE) + { + printf("OSK done\n"); + } + oskUnloadAsync(&outputParam); + + if (outputParam.res == OSK_OK) + { + printf("OSK result OK\n"); + } + else + { + printf("OKS result: %d\n", outputParam.res); + } + + break; + case SYSUTIL_OSK_UNLOADED: + printf("OSK unloaded\n"); + isRunningOSK = 0; + break; + default: + break; + } +} +} + static void utf16_to_utf8(const uint16_t *src, uint8_t *dst) { int i; @@ -84,63 +135,15 @@ static void do_flip() flip(); } -void program_exit_callback() -{ - gcmSetWaitFlip(context); - rsxFinish(context, 1); -} - -void sysutil_exit_callback(u64 status, u64 param, void *usrdata) -{ - switch(status) { - case SYSUTIL_EXIT_GAME: - break; - case SYSUTIL_DRAW_BEGIN: - case SYSUTIL_DRAW_END: - break; - case SYSUTIL_OSK_LOADED: - printf("OSK loaded\n"); - break; - case SYSUTIL_OSK_INPUT_CANCELED: - printf("OSK input canceled\n"); - oskAbort(); - // fall-through - case SYSUTIL_OSK_DONE: - if (status == SYSUTIL_OSK_DONE) - { - printf("OSK done\n"); - } - oskUnloadAsync(&outputParam); - - if (outputParam.res == OSK_OK) - { - printf("OSK result OK\n"); - } - else - { - printf("OKS result: %d\n", outputParam.res); - } - - break; - case SYSUTIL_OSK_UNLOADED: - printf("OSK unloaded\n"); - isRunningOSK = 0; - break; - default: - break; - } -} - -#define TEXT_BUFFER_LENGTH 256 - int main(int argc,char *argv[]) { - void *host_addr = memalign(1024*1024, HOST_SIZE); static uint16_t title_utf16[TEXT_BUFFER_LENGTH]; static uint16_t input_text_utf16[TEXT_BUFFER_LENGTH]; static uint16_t initial_text_utf16[TEXT_BUFFER_LENGTH]; static uint8_t input_text_utf8[TEXT_BUFFER_LENGTH]; + void *host_addr = memalign(1024*1024, HOST_SIZE); + // Convert UTF8 to UTF16 memset(title_utf16, 0, sizeof(title_utf16)); memset(initial_text_utf16, 0, sizeof(initial_text_utf16)); @@ -169,9 +172,9 @@ int main(int argc,char *argv[]) outputParam.str = input_text_utf16; atexit(program_exit_callback); + sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, sysutil_exit_callback, NULL); s32 res = 0; - sys_mem_container_t containerid; res = sysMemContainerCreate(&containerid, 4 * 1024 * 1024); if (res != 0) @@ -180,14 +183,6 @@ int main(int argc,char *argv[]) return 0; } - res = sysUtilRegisterCallback(SYSUTIL_EVENT_SLOT0, sysutil_exit_callback, NULL); - if (res != 0) - { - printf("Error sysUtilRegisterCallback: %08x\n", res); - sysMemContainerDestroy(containerid); - return 0; - } - oskSetInitialInputDevice(OSK_DEVICE_PAD); oskSetKeyLayoutOption(OSK_FULLKEY_PANEL); oskSetLayoutMode(OSK_LAYOUTMODE_HORIZONTAL_ALIGN_CENTER | OSK_LAYOUTMODE_VERTICAL_ALIGN_CENTER); diff --git a/samples/sys/osk/source/rsxutil.cpp b/samples/sys/osk/source/rsxutil.cpp new file mode 100644 index 00000000..01e6a667 --- /dev/null +++ b/samples/sys/osk/source/rsxutil.cpp @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "rsxutil.h" + +#define GCM_LABEL_INDEX 255 + +videoResolution res; +gcmContextData *context = NULL; + +u32 curr_fb = 0; +u32 first_fb = 1; + +u32 display_width; +u32 display_height; + +u32 depth_pitch; +u32 depth_offset; +u32 *depth_buffer; + +u32 color_pitch; +u32 color_offset[2]; +u32 *color_buffer[2]; + +static u32 sLabelVal = 1; + +static void waitFinish() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + + rsxFlushBuffer(context); + + while(*(vu32*)gcmGetLabelAddress(GCM_LABEL_INDEX)!=sLabelVal) + usleep(30); + + ++sLabelVal; +} + +static void waitRSXIdle() +{ + rsxSetWriteBackendLabel(context,GCM_LABEL_INDEX,sLabelVal); + rsxSetWaitLabel(context,GCM_LABEL_INDEX,sLabelVal); + + ++sLabelVal; + + waitFinish(); +} + +void setRenderTarget(u32 index) +{ + gcmSurface sf; + + sf.colorFormat = GCM_SURFACE_X8R8G8B8; + sf.colorTarget = GCM_SURFACE_TARGET_0; + sf.colorLocation[0] = GCM_LOCATION_RSX; + sf.colorOffset[0] = color_offset[index]; + sf.colorPitch[0] = color_pitch; + + sf.colorLocation[1] = GCM_LOCATION_RSX; + sf.colorLocation[2] = GCM_LOCATION_RSX; + sf.colorLocation[3] = GCM_LOCATION_RSX; + sf.colorOffset[1] = 0; + sf.colorOffset[2] = 0; + sf.colorOffset[3] = 0; + sf.colorPitch[1] = 64; + sf.colorPitch[2] = 64; + sf.colorPitch[3] = 64; + + sf.depthFormat = GCM_SURFACE_ZETA_Z16; + sf.depthLocation = GCM_LOCATION_RSX; + sf.depthOffset = depth_offset; + sf.depthPitch = depth_pitch; + + sf.type = GCM_SURFACE_TYPE_LINEAR; + sf.antiAlias = GCM_SURFACE_CENTER_1; + + sf.width = display_width; + sf.height = display_height; + sf.x = 0; + sf.y = 0; + + rsxSetSurface(context,&sf); +} + +void init_screen(void *host_addr,u32 size) +{ + rsxInit(&context,CB_SIZE,size,host_addr); + + videoState state; + videoGetState(0,0,&state); + + videoGetResolution(state.displayMode.resolution,&res); + + videoConfiguration vconfig; + memset(&vconfig,0,sizeof(videoConfiguration)); + + vconfig.resolution = state.displayMode.resolution; + vconfig.format = VIDEO_BUFFER_FORMAT_XRGB; + vconfig.pitch = res.width*sizeof(u32); + + waitRSXIdle(); + + videoConfigure(0,&vconfig,NULL,0); + videoGetState(0,0,&state); + + gcmSetFlipMode(GCM_FLIP_VSYNC); + + display_width = res.width; + display_height = res.height; + + color_pitch = display_width*sizeof(u32); + color_buffer[0] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + color_buffer[1] = (u32*)rsxMemalign(64,(display_height*color_pitch)); + + rsxAddressToOffset(color_buffer[0],&color_offset[0]); + rsxAddressToOffset(color_buffer[1],&color_offset[1]); + + gcmSetDisplayBuffer(0,color_offset[0],color_pitch,display_width,display_height); + gcmSetDisplayBuffer(1,color_offset[1],color_pitch,display_width,display_height); + + depth_pitch = display_width*sizeof(u32); + depth_buffer = (u32*)rsxMemalign(64,(display_height*depth_pitch)*2); + rsxAddressToOffset(depth_buffer,&depth_offset); +} + +void waitflip() +{ + while(gcmGetFlipStatus()!=0) + usleep(200); + gcmResetFlipStatus(); +} + +void flip() +{ + if(!first_fb) waitflip(); + else gcmResetFlipStatus(); + + gcmSetFlip(context,curr_fb); + rsxFlushBuffer(context); + + gcmSetWaitFlip(context); + + curr_fb ^= 1; + setRenderTarget(curr_fb); + + first_fb = 0; +} diff --git a/spu/Makefile b/spu/Makefile index f5faecd4..3a9e5d35 100644 --- a/spu/Makefile +++ b/spu/Makefile @@ -6,6 +6,8 @@ all: @$(MAKE) -C libsputhread --no-print-directory + @$(MAKE) -C libspudma --no-print-directory + @$(MAKE) -C libspuatomic --no-print-directory install-headers: @[ -d $(PSL1GHT)/spu ] || mkdir -p $(PSL1GHT)/spu @@ -13,8 +15,12 @@ install-headers: install: install-headers @$(MAKE) -C libsputhread install --no-print-directory + @$(MAKE) -C libspudma install --no-print-directory + @$(MAKE) -C libspuatomic install --no-print-directory clean: @$(MAKE) -C libsputhread clean --no-print-directory + @$(MAKE) -C libspudma clean --no-print-directory + @$(MAKE) -C libspuatomic clean --no-print-directory .PHONY: all clean install diff --git a/spu/include/dma/spu_dma.h b/spu/include/dma/spu_dma.h new file mode 100644 index 00000000..99d0b9ad --- /dev/null +++ b/spu/include/dma/spu_dma.h @@ -0,0 +1,391 @@ +#ifndef __SPU_DMA_H__ +#define __SPU_DMA_H__ + +#include +#include +#include + +#define MAX_DMA_BLOCK_SIZE 16384 + +#define spu_dma_ea2ls(ea, ls) (void*)((uintptr_t)(ls)+((uint32_t)(ea)&15)) + +#ifdef NO_SPU_DMA_ASSERT +#define spu_dma_assert(cond, ...) +#else +#ifndef SPU_DMA_ASSERT_VERBOSE +#define spu_dma_assert(cond, ...) spu_hcmpeq((cond), 0) +#else +#include +#define spu_dma_assert(cond, fmt, ...) \ +do { \ + if(!(cond)) { \ + spu_printf("%s:%u %s" fmt, __FILE__,__LINE__,"[spu_dma_assert]",##__VA_ARGS__); \ + __asm__ volatile("stopd $0,$0,$0\n"); \ + } \ +} while(0) +#endif +#endif + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA assertion +//--------------------------------------------------------------------------------------------------------------------------------------------- +#define spu_dma_normal_assert(ls,ea,size,tag) \ + spu_dma_assert((((uintptr_t)(ls) & 0xf) == 0) & \ + (((uintptr_t)(ea) & 0xf) == 0) & \ + (((size) & 0xf) == 0) & \ + ((size) <= (16<<10)) & \ + ((tag) < 32), "ls=%#x,ea=%#llx,size=%#x,tag=%u\n", ls,ea,size,tag) + +#define spu_dma_small_assert(ls,ea,size,tag) \ + spu_dma_assert((((uintptr_t)(ls) & 0xf) == ((uintptr_t)(ea) & 0xf)) & \ + (((uintptr_t)(ls) & (size - 1)) == 0) & \ + (((size)==1)||((size)==2)||((size)==4)||((size)==8)) & \ + ((tag) < 32), "ls=%#x,ea=%#llx,size=%#x,tag=%u\n", ls,ea,size,tag) + +#define spu_dma_list_assert(ls,ea,la,lsize,tag) \ + spu_dma_assert((((uintptr_t)(ls) & 0xf) == 0) & \ + (((uintptr_t)(ea) & 0xf) == 0) & \ + (((uintptr_t)(la) & 7) == 0) & \ + (((lsize) & 7) == 0) & \ + ((lsize) <= (16<<10)) & \ + ((tag) < 32), "ls=%#x,ea=%#llx,la=%#x,lsize=%#x,tag=%u\n", ls,ea,(uintptr_t)(la),lsize,tag) + +#define spu_dma_atomic_assert(ls,ea) \ + spu_dma_assert((((uintptr_t)(ls) & 0x7f) == 0) & \ + (((uintptr_t)(ea) & 0x7f) == 0), "ls=%#x,ea=%#llx\n", ls,ea) + +#define spu_dma_putqlluc_assert(ls,ea,tag) \ + spu_dma_assert((((uintptr_t)(ls) & 0x7f) == 0) & \ + (((uintptr_t)(ea) & 0x7f) == 0) & \ + ((tag) < 32), "ls=%#x,ea=%#llx,tag=%u\n", ls,ea,tag) + +#define spu_dma_large_assert(ls,ea,tag) \ + spu_dma_assert((((uintptr_t)(ls) & 0xf) == 0) & \ + (((uintptr_t)(ea) & 0xf) == 0) & \ + ((tag) < 32), "ls=%#x,ea=%#llx,tag=%u\n", ls,ea,tag) + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef mfc_list_element_t spu_dma_list_element; + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA which transfer size is a multiple of 16Bytes +//--------------------------------------------------------------------------------------------------------------------------------------------- +__attribute__ ((__always_inline__)) +static inline void spu_dma_put(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_put((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_putb(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_putb((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_putf(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_putf((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_get(ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_getb(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_getb(ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_getf(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_normal_assert(ls, ea, size, tag); + mfc_getf(ls, ea, size, tag, tid, rid); +} + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA which transfer size is within 16Bytes +//--------------------------------------------------------------------------------------------------------------------------------------------- +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_put(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_put((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_putb(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_putb((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_putf(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_putf((volatile void*)(uintptr_t)ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_get(ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_getb(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_getb(ls, ea, size, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_small_getf(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_small_assert(ls, ea, size, tag); + mfc_getf(ls, ea, size, tag, tid, rid); +} + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// List DMA +//--------------------------------------------------------------------------------------------------------------------------------------------- +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_put(const void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_putl((volatile void*)(uintptr_t)ls, ea, list, lsize, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_putb(const void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_putlb((volatile void*)(uintptr_t)ls, ea, list, lsize, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_putf(const void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_putlf((volatile void*)(uintptr_t)ls, ea, list, lsize, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_get(void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_getl(ls, ea, list, lsize, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_getb(void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_getlb(ls, ea, list, lsize, tag, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_list_getf(void *ls, uint64_t ea, const spu_dma_list_element *list, uint32_t lsize, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_list_assert(ls, ea, list, lsize, tag); + mfc_getlf(ls, ea, list, lsize, tag, tid, rid); +} + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// Atomic DMA +//--------------------------------------------------------------------------------------------------------------------------------------------- +__attribute__ ((__always_inline__)) +static inline void spu_dma_getllar(void *ls, uint64_t ea, uint32_t tid, uint32_t rid) +{ + spu_dma_atomic_assert(ls, ea); + mfc_getllar(ls, ea, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_putllc(const void *ls, uint64_t ea, uint32_t tid, uint32_t rid) +{ + spu_dma_atomic_assert(ls, ea); + mfc_putllc((volatile void*)(uintptr_t)ls, ea, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_putlluc(const void *ls, uint64_t ea, uint32_t tid, uint32_t rid) +{ + spu_dma_atomic_assert(ls, ea); + mfc_putlluc((volatile void*)(uintptr_t)ls, ea, tid, rid); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_putqlluc(const void *ls, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_putqlluc_assert(ls, ea, tag); + mfc_putqlluc((volatile void*)(uintptr_t)ls, ea, tag, tid, rid); +} + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA utilities - data typed DMA +//--------------------------------------------------------------------------------------------------------------------------------------------- +void spu_dma_and_wait(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t cmd); + +static inline void spu_dma_put_uint8(uint8_t value, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline void spu_dma_put_uint16(uint16_t value, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline void spu_dma_put_uint32(uint32_t value, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline void spu_dma_put_uint64(uint64_t value, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); + +static inline uint8_t spu_dma_get_uint8(uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline uint16_t spu_dma_get_uint16(uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline uint32_t spu_dma_get_uint32(uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); +static inline uint64_t spu_dma_get_uint64(uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) __attribute__ ((__always_inline__)); + +#define spu_dma_put_uint_template(SIZE) \ +__attribute__ ((__always_inline__)) \ +static inline void \ +spu_dma_put_uint##SIZE(uint##SIZE##_t value, uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) \ +{ \ + qword buf = (qword)spu_splats(value); \ + spu_dma_small_assert(ea, ea, sizeof(uint##SIZE##_t), tag); \ + spu_dma_and_wait(spu_dma_ea2ls(ea,&buf), ea, sizeof(uint##SIZE##_t), tag, MFC_CMD_WORD(tid,rid,MFC_PUT_CMD)); \ +} +spu_dma_put_uint_template(8) +spu_dma_put_uint_template(16) +spu_dma_put_uint_template(32) +spu_dma_put_uint_template(64) + +#define spu_dma_get_uint_template(SIZE) \ +__attribute__ ((__always_inline__)) \ +static inline uint##SIZE##_t \ +spu_dma_get_uint##SIZE(uint64_t ea, uint32_t tag, uint32_t tid, uint32_t rid) \ +{ \ + qword buf; \ + spu_dma_small_assert(ea, ea, sizeof(uint##SIZE##_t), tag); \ + spu_dma_and_wait(spu_dma_ea2ls(ea,&buf), ea, sizeof(uint##SIZE##_t), tag, MFC_CMD_WORD(tid,rid,MFC_GET_CMD)); \ + return *(uint##SIZE##_t*)((uintptr_t)&buf + ((uintptr_t)ea&15)); \ +} +spu_dma_get_uint_template(8) +spu_dma_get_uint_template(16) +spu_dma_get_uint_template(32) +spu_dma_get_uint_template(64) + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA utilities - any size DMA +//--------------------------------------------------------------------------------------------------------------------------------------------- +void spu_dma_large_cmd(uintptr_t ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t cmd); + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_put(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_PUT_CMD)); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_putb(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_PUTB_CMD)); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_putf(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_PUTF_CMD)); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_get(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_GET_CMD)); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_getb(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_GETB_CMD)); +} + +__attribute__ ((__always_inline__)) +static inline void spu_dma_large_getf(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) +{ + spu_dma_large_assert(ls, ea, tag); + spu_dma_large_cmd((uintptr_t)ls,ea,size,tag,MFC_CMD_WORD(tid,rid,MFC_GETF_CMD)); +} + + +//--------------------------------------------------------------------------------------------------------------------------------------------- +// DMA utilities - tag wait +//--------------------------------------------------------------------------------------------------------------------------------------------- +__attribute__ ((__always_inline__)) +static inline void spu_dma_cancel_tag_status_update() +{ + mfc_write_tag_update_immediate(); + do {} while(__builtin_expect(mfc_stat_tag_update() == 0,0)); + mfc_read_tag_status(); +} + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_dma_cancel_and_wait_tag_status_any(uint32_t tagmask) +{ + spu_dma_cancel_tag_status_update(); + mfc_write_tag_mask(tagmask); + return mfc_read_tag_status_any(); +} + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_dma_cancel_and_wait_tag_status_all(uint32_t tagmask) +{ + spu_dma_cancel_tag_status_update(); + mfc_write_tag_mask(tagmask); + return mfc_read_tag_status_all(); +} + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_dma_wait_tag_status_immediate(uint32_t tagmask) +{ + mfc_write_tag_mask(tagmask); + return mfc_read_tag_status_immediate(); +} + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_cma_wait_tag_status_any(uint32_t tagmask) +{ + mfc_write_tag_mask(tagmask); + return mfc_read_tag_status_any(); +} + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_dma_wait_tag_status_all(uint32_t tagmask) +{ + mfc_write_tag_mask(tagmask); + return mfc_read_tag_status_all(); +} + +#define spu_dma_wait_atomic_status() mfc_read_atomic_status() + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/spu/include/sys/spu_atomic.h b/spu/include/sys/spu_atomic.h new file mode 100644 index 00000000..3c0cf072 --- /dev/null +++ b/spu/include/sys/spu_atomic.h @@ -0,0 +1,85 @@ +#ifndef __SPU_ATOMIC_H__ +#define __SPU_ATOMIC_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t spu_atomic_nop32(uint32_t *ls, uint64_t ea); +uint64_t spu_atomic_nop64(uint64_t *ls, uint64_t ea); +uint32_t spu_atomic_incr32(uint32_t *ls, uint64_t ea); +uint64_t spu_atomic_incr64(uint64_t *ls, uint64_t ea); +uint32_t spu_atomic_decr32(uint32_t *ls, uint64_t ea); +uint64_t spu_atomic_decr64(uint64_t *ls, uint64_t ea); +uint32_t spu_atomic_test_and_decr32(uint32_t *ls, uint64_t ea); +uint64_t spu_atomic_test_and_decr64(uint64_t *ls, uint64_t ea); +uint32_t spu_atomic_or32(uint32_t *ls, uint64_t ea, uint32_t value); +uint64_t spu_atomic_or64(uint64_t *ls, uint64_t ea, uint64_t value); +uint32_t spu_atomic_add32(uint32_t *ls, uint64_t ea, uint32_t value); +uint64_t spu_atomic_add64(uint64_t *ls, uint64_t ea, uint64_t value); +uint32_t spu_atomic_and32(uint32_t *ls, uint64_t ea, uint32_t value); +uint64_t spu_atomic_and64(uint64_t *ls, uint64_t ea, uint64_t value); +uint32_t spu_atomic_sub32(uint32_t *ls, uint64_t ea, uint32_t value); +uint64_t spu_atomic_sub64(uint64_t *ls, uint64_t ea, uint64_t value); +uint32_t spu_atomic_store32(uint32_t *ls, uint64_t ea, uint32_t value); +uint64_t spu_atomic_store64(uint64_t *ls, uint64_t ea, uint64_t value); +uint32_t spu_atomic_compare_and_swap32(uint32_t *ls, uint64_t ea, uint32_t compare, uint32_t value); +uint64_t spu_atomic_compare_and_swap64(uint64_t *ls, uint64_t ea, uint64_t compare, uint64_t value); + +__attribute__ ((__always_inline__)) +static inline uint32_t spu_atomic_lock_line32(uint32_t *ls, uint64_t ea) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + mfc_getllar(ls, ea, 0, 0); + mfc_read_atomic_status(); + spu_dsync(); + return ls[i]; +} + +__attribute__ ((__always_inline__)) +static inline uint64_t spu_atomic_lock_line64(uint64_t *ls, uint64_t ea) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + mfc_getllar(ls, ea, 0, 0); + mfc_read_atomic_status(); + spu_dsync(); + return ls[i]; +} + +__attribute__ ((__always_inline__)) +static inline int spu_atomic_store_conditional32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ls[i] = value; + ea &= ~0x7f; + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + return mfc_read_atomic_status(); +} + +__attribute__ ((__always_inline__)) +static inline int spu_atomic_store_conditional64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ls[i] = value; + ea &= ~0x7f; + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + return mfc_read_atomic_status(); +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/spu/include/sys/spu_event.h b/spu/include/sys/spu_event.h index 88bbe7df..832ab799 100644 --- a/spu/include/sys/spu_event.h +++ b/spu/include/sys/spu_event.h @@ -14,7 +14,9 @@ #define EVENT_DATA0_MASK 0x00FFFFFF #define EVENT_PORT_SHIFT 24 -#define EVENT_PORT_MAX_NUM 63 +#define EVENT_PORT_MAX_NUM 63 + +#define EVENT_PRINTF_PORT 1U #ifdef __cplusplus extern "C" { diff --git a/spu/include/sys/spu_printf.h b/spu/include/sys/spu_printf.h new file mode 100644 index 00000000..44d0ff8d --- /dev/null +++ b/spu/include/sys/spu_printf.h @@ -0,0 +1,19 @@ +#ifndef __SPU_PRINTF_H__ +#define __SPU_PRINTF_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int _spu_call_event_va_arg(uint32_t _spup, const char *fmt, ...); + +#define spu_printf(fmt, args...) \ + _spu_call_event_va_arg(EVENT_PRINTF_PORT<") +endif + +include $(PSL1GHT)/spu_rules + +BUILD := build + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPS := $(BASEDIR)/deps +export LIBS := $(BASEDIR)/lib + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBS)/$(PLATFORM) +export DEPSDIR := $(DEPS)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +LIBRARY := $(LIBDIR)/libspuatomic + +#--------------------------------------------------------------------------------- +INCLUDES := -I$(BASEDIR) -I$(BASEDIR)/../include -I$(BASEDIR)/../include/sys + +CFLAGS := -O2 -Wall $(MACHDEP) -DLIBRT_INTERNAL $(INCLUDES) +ASFLAGS := $(MACHDEP) -D__ASSEMBLY__ $(INCLUDES) + +#--------------------------------------------------------------------------------- +VPATH := $(BASEDIR) + +#--------------------------------------------------------------------------------- +OBJS := spu_atomic.o + +all: spu + +#--------------------------------------------------------------------------------- +spu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBS)/spu ] || mkdir -p $(LIBS)/spu + @[ -d $(DEPS)/spu ] || mkdir -p $(DEPS)/spu + @[ -d spu ] || mkdir -p spu + @$(MAKE) PLATFORM=spu lib -C spu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install: all +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/spu/lib ] || mkdir -p $(PSL1GHT)/spu/lib + @cp -frv $(CURDIR)/lib/spu/*.a $(PSL1GHT)/spu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: $(OBJS) +#--------------------------------------------------------------------------------- + +.PHONY: lib spu install + +#--------------------------------------------------------------------------------- +lib: $(LIBRARY).a +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf spu + @rm -rf $(DEPS) + @rm -rf $(LIBS) + +-include $(DEPSDIR)/*.d diff --git a/spu/libspuatomic/spu_atomic.c b/spu/libspuatomic/spu_atomic.c new file mode 100755 index 00000000..f7b5efa4 --- /dev/null +++ b/spu/libspuatomic/spu_atomic.c @@ -0,0 +1,409 @@ +#include "spu_atomic.h" + +uint32_t spu_atomic_add32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value + value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_add64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value + value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_and32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value&value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_and64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value&value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_compare_and_swap32(uint32_t *ls, uint64_t ea, uint32_t compare, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + if(old_value != compare) return old_value; + + ls[i] = value; + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return value; +} + +uint64_t spu_atomic_compare_and_swap64(uint64_t *ls, uint64_t ea, uint64_t compare, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + if(old_value != compare) return old_value; + + ls[i] = value; + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return value; +} + +uint32_t spu_atomic_decr32(uint32_t *ls, uint64_t ea) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value - 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_decr64(uint64_t *ls, uint64_t ea) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value - 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_incr32(uint32_t *ls, uint64_t ea) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value + 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_incr64(uint64_t *ls, uint64_t ea) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value + 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_nop32(uint32_t *ls, uint64_t ea) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + mfc_getllar(ls, ea, 0, 0); + mfc_read_atomic_status(); + spu_dsync(); + return ls[i]; +} + +uint64_t spu_atomic_nop64(uint64_t *ls, uint64_t ea) +{ + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + mfc_getllar(ls, ea, 0, 0); + mfc_read_atomic_status(); + spu_dsync(); + return ls[i]; +} + +uint32_t spu_atomic_or32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value|value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_or64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value|value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_store32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = value; + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_store64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = value; + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_sub32(uint32_t *ls, uint64_t ea, uint32_t value) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value - value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_sub64(uint64_t *ls, uint64_t ea, uint64_t value) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + ls[i] = (old_value - value); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint32_t spu_atomic_test_and_decr32(uint32_t *ls, uint64_t ea) +{ + uint32_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 2; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + if(old_value == 0) break; + + ls[i] = (old_value - 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} + +uint64_t spu_atomic_test_and_decr64(uint64_t *ls, uint64_t ea) +{ + uint64_t old_value = 0; + unsigned int i = ((uint32_t)ea & 0x7f) >> 3; + + ea &= ~0x7f; + do { + mfc_getllar(ls, ea, 0, 0); + (void)mfc_read_atomic_status(); + spu_dsync(); + + old_value = ls[i]; + if(old_value == 0) break; + + ls[i] = (old_value - 1); + + spu_dsync(); + mfc_putllc(ls, ea, 0, 0); + } while(__builtin_expect(mfc_read_atomic_status(), 0)); + + return old_value; +} diff --git a/spu/libspudma/Makefile b/spu/libspudma/Makefile new file mode 100644 index 00000000..682e7fdc --- /dev/null +++ b/spu/libspudma/Makefile @@ -0,0 +1,81 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(PSL1GHT)),) +$(error "Please set PSL1GHT in your environment. export PSL1GHT=") +endif + +include $(PSL1GHT)/spu_rules + +BUILD := build + +#--------------------------------------------------------------------------------- +ifeq ($(strip $(PLATFORM)),) +#--------------------------------------------------------------------------------- +export BASEDIR := $(CURDIR) +export DEPS := $(BASEDIR)/deps +export LIBS := $(BASEDIR)/lib + +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + +export LIBDIR := $(LIBS)/$(PLATFORM) +export DEPSDIR := $(DEPS)/$(PLATFORM) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +LIBRARY := $(LIBDIR)/libspudma + +#--------------------------------------------------------------------------------- +INCLUDES := -I$(BASEDIR) -I$(BASEDIR)/../include -I$(BASEDIR)/../include/dma + +CFLAGS := -O2 -Wall $(MACHDEP) -DLIBRT_INTERNAL $(INCLUDES) +ASFLAGS := $(MACHDEP) -D__ASSEMBLY__ $(INCLUDES) + +#--------------------------------------------------------------------------------- +VPATH := $(BASEDIR) + +#--------------------------------------------------------------------------------- +OBJS := spu_dma.o + +all: spu + +#--------------------------------------------------------------------------------- +spu: +#--------------------------------------------------------------------------------- + @[ -d $(LIBS)/spu ] || mkdir -p $(LIBS)/spu + @[ -d $(DEPS)/spu ] || mkdir -p $(DEPS)/spu + @[ -d spu ] || mkdir -p spu + @$(MAKE) PLATFORM=spu lib -C spu -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +install: all +#--------------------------------------------------------------------------------- + @[ -d $(PSL1GHT)/spu/lib ] || mkdir -p $(PSL1GHT)/spu/lib + @cp -frv $(CURDIR)/lib/spu/*.a $(PSL1GHT)/spu/lib + +#--------------------------------------------------------------------------------- +$(LIBRARY).a: $(OBJS) +#--------------------------------------------------------------------------------- + +.PHONY: lib spu install + +#--------------------------------------------------------------------------------- +lib: $(LIBRARY).a +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +clean: +#--------------------------------------------------------------------------------- + @echo clean ... + @rm -rf spu + @rm -rf $(DEPS) + @rm -rf $(LIBS) + +-include $(DEPSDIR)/*.d diff --git a/spu/libspudma/spu_dma.c b/spu/libspudma/spu_dma.c new file mode 100755 index 00000000..8cd3c55d --- /dev/null +++ b/spu/libspudma/spu_dma.c @@ -0,0 +1,28 @@ +#include "spu_dma.h" + +void spu_dma_large_cmd(uintptr_t ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t cmd) +{ + vec_uint4 tmp; + while(size) { + tmp = spu_sel((vec_uint4)si_from_uint(1), (vec_uint4)si_from_uint(2), spu_cmpgt((vec_uint4)si_from_uint(size), 1)); + tmp = spu_sel((vec_uint4)si_from_uint(4), tmp, spu_cmpeq(spu_cmpgt((vec_uint4)si_from_uint(size), 3), 0)); + tmp = spu_sel((vec_uint4)si_from_uint(8), tmp, spu_cmpeq(spu_cmpgt((vec_uint4)si_from_uint(size), 7), 0)); + tmp = spu_sel(spu_and((vec_uint4)si_from_uint(size), -16), tmp, spu_cmpeq(spu_cmpgt((vec_uint4)si_from_uint(size), 15), 0)); + tmp = spu_sel((vec_uint4)si_from_uint(MAX_DMA_BLOCK_SIZE), tmp, spu_cmpeq(spu_cmpgt((vec_uint4)si_from_uint(size), 16383), 0)); + + uint32_t chunk = spu_extract(tmp, 0); + spu_mfcdma64((volatile void*)ls,mfc_ea2h(ea),mfc_ea2l(ea),chunk,tag,cmd); + + size -= chunk; + ls = (uintptr_t)((uint32_t)ls + chunk); + ea += chunk; + } +} + +void spu_dma_and_wait(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t cmd) +{ + spu_mfcdma64((volatile void*)ls,mfc_ea2h(ea),mfc_ea2l(ea),size,tag,cmd); + mfc_write_tag_mask(1< m_lParameters; std::list m_lConstData; std::stack m_repStack; std::stack m_ifStack; + std::stack m_loopStack; }; #endif diff --git a/tools/cgcomp/include/compiler.h b/tools/cgcomp/include/compilervp.h similarity index 60% rename from tools/cgcomp/include/compiler.h rename to tools/cgcomp/include/compilervp.h index a590be9f..3b7f291d 100644 --- a/tools/cgcomp/include/compiler.h +++ b/tools/cgcomp/include/compilervp.h @@ -14,11 +14,11 @@ struct vertex_program_data class CParser; -class CCompiler +class CCompilerVP { public: - CCompiler(); - virtual ~CCompiler(); + CCompilerVP(); + virtual ~CCompilerVP(); void Compile(CParser *pParser); @@ -33,15 +33,38 @@ class CCompiler private: void Prepare(CParser *pParser); - void emit_insn(u8 opcode,struct nvfx_insn *insn); - void emit_dst(u32 *hw,u8 slot,struct nvfx_insn *insn); - void emit_src(u32 *hw,u8 pos,struct nvfx_src *src); + void emit_insn(struct nvfx_insn *insn,u8 opcode); + void emit_dst(struct nvfx_insn *insn,u8 slot); + void emit_src(struct nvfx_insn *insn,u8 pos); + void emit_pow(struct nvfx_insn *insn); + void emit_abs(struct nvfx_insn *insn); + void emit_sub(struct nvfx_insn *insn); + void emit_tex(struct nvfx_insn *insn); + void emit_lrp(struct nvfx_insn *insn); + void emit_nop(); + + int grow_insns(int count); struct nvfx_reg temp(); struct nvfx_reg constant(s32 pipe,f32 x,f32 y,f32 z,f32 w); void release_temps(); + inline param GetInputAttrib(int index) + { + s32 i; + std::list::iterator it = m_lParameters.begin(); + for(;it!=m_lParameters.end();it++) { + for(i=0;icount;i++) { + if((int)(it->index + i)==index) { + if(!it->is_const && !it->is_internal) + return *it; + } + } + } + return param(); + } + int m_nNumRegs; int m_nInputMask; int m_nOutputMask; @@ -56,9 +79,9 @@ class CCompiler int m_rTemps; int m_rTempsDiscard; - struct nvfx_reg *m_rTemp; struct nvfx_reg *m_rConst; + std::list m_lParameters; std::list m_lConstRelocation; std::list m_lBranchRelocation; }; diff --git a/tools/cgcomp/include/fpparser.h b/tools/cgcomp/include/fpparser.h index 1c0cf8ab..b15cc37e 100644 --- a/tools/cgcomp/include/fpparser.h +++ b/tools/cgcomp/include/fpparser.h @@ -7,39 +7,13 @@ #define NV_OPTION_FP2 0x02 #define NV_OPTION_FP3 0x04 -/** - * Bit flags for each type of texture object - * Used for Texture.Unit[]._ReallyEnabled flags. - */ -/*@{*/ -#define TEXTURE_2D_ARRAY_BIT (1 << TEXTURE_2D_ARRAY_INDEX) -#define TEXTURE_1D_ARRAY_BIT (1 << TEXTURE_1D_ARRAY_INDEX) -#define TEXTURE_CUBE_BIT (1 << TEXTURE_CUBE_INDEX) -#define TEXTURE_3D_BIT (1 << TEXTURE_3D_INDEX) -#define TEXTURE_RECT_BIT (1 << TEXTURE_RECT_INDEX) -#define TEXTURE_2D_BIT (1 << TEXTURE_2D_INDEX) -#define TEXTURE_1D_BIT (1 << TEXTURE_1D_INDEX) -/*@}*/ - typedef struct _oparam { std::string alias; s32 index; + u8 is_fp16; } oparam; -typedef enum -{ - TEXTURE_2D_ARRAY_INDEX, - TEXTURE_1D_ARRAY_INDEX, - TEXTURE_CUBE_INDEX, - TEXTURE_3D_INDEX, - TEXTURE_RECT_INDEX, - TEXTURE_2D_INDEX, - TEXTURE_1D_INDEX, - NUM_TEXTURE_TARGETS -} texture_index; - - class CFPParser : public CParser { public: @@ -53,14 +27,16 @@ class CFPParser : public CParser void ParseMaskedDstReg(const char *token,struct nvfx_insn *insn); void ParseVectorSrc(const char *token,struct nvfx_src *reg); void ParseScalarSrc(const char *token,struct nvfx_src *reg); - void ParseTextureUnit(const char *token,u8 *texUnit); - void ParseTextureTarget(const char *token,u8 *texTarget); void ParseOutput(const char *param_str); - const char* ParseOutputReg(const char *token,s32 *reg); + const char* ParseOutputReg(const char *token,s32 *reg,u8 *is_fp16); const char* ParseInputReg(const char *token,s32 *reg); - const char* ParseOutputRegAlias(const char *token,s32 *reg); + const char* ParseOutputRegAlias(const char *token,s32 *reg,u8 *is_fp16); + + void SetNoneDestReg(struct nvfx_insn *insn); + + u8 IsPCDisablingInstruction(struct nvfx_insn *insn); opcode FindOpcode(const char *mnemonic); diff --git a/tools/cgcomp/include/nvfx_shader.h b/tools/cgcomp/include/nvfx_shader.h index 540aace6..0dc0f855 100644 --- a/tools/cgcomp/include/nvfx_shader.h +++ b/tools/cgcomp/include/nvfx_shader.h @@ -237,6 +237,7 @@ #define NVFX_FP_OP_OPCODE_TXP 0x18 #define NVFX_FP_OP_OPCODE_TXD 0x19 #define NVFX_FP_OP_OPCODE_RCP 0x1A +#define NVFX_FP_OP_OPCODE_RSQ 0x1B #define NVFX_FP_OP_OPCODE_EX2 0x1C #define NVFX_FP_OP_OPCODE_LG2 0x1D #define NVFX_FP_OP_OPCODE_STR 0x20 @@ -251,10 +252,11 @@ #define NVFX_FP_OP_OPCODE_UP2US 0x2A #define NVFX_FP_OP_OPCODE_DP2A 0x2E #define NVFX_FP_OP_OPCODE_TXB 0x31 +#define NVFX_FP_OP_OPCODE_DP2 0x38 +#define NVFX_FP_OP_OPCODE_NRM 0x39 #define NVFX_FP_OP_OPCODE_DIV 0x3A /* NV30 only fragment program opcodes */ -#define NVFX_FP_OP_OPCODE_RSQ_NV30 0x1B #define NVFX_FP_OP_OPCODE_LIT_NV30 0x1E #define NVFX_FP_OP_OPCODE_LRP_NV30 0x1F #define NVFX_FP_OP_OPCODE_POW_NV30 0x26 @@ -264,6 +266,9 @@ #define NVFX_FP_OP_OPCODE_TXL_NV40 0x2F #define NVFX_FP_OP_OPCODE_LITEX2_NV40 0x3C +/* NV40 (RSX) only fragment program opcodes */ +#define NVFX_FP_OP_OPCODE_DIVRSQ_NV40RSX 0x3B + /* The use of these instructions appears to be indicated by bit 31 of DWORD 2.*/ #define NV40_FP_OP_BRA_OPCODE_BRK 0x0 #define NV40_FP_OP_BRA_OPCODE_CAL 0x1 @@ -347,6 +352,9 @@ #define NVFX_FP_OP_INDEX_INPUT (1 << 30) #define NV40_FP_OP_ADDR_INDEX_SHIFT 19 #define NV40_FP_OP_ADDR_INDEX_MASK (0xF << 19) +#define NVFX_FP_OP_SRC2_ABS (1 << 18) + +#define NV40_FP_OP_DISABLE_PC_SHIFT 31 //== Register selection == #define NVFX_FP_REG_TYPE_SHIFT 0 @@ -381,6 +389,8 @@ #define NVFXSR_CONST 5 #define NVFXSR_IMM 6 #define NVFXSR_RELOCATED 7 +#define NVFXSR_SAMPLER 8 +#define NVFXSR_ADDRESS 9 #define NVFX_COND_FL 0 #define NVFX_COND_LT 1 @@ -545,7 +555,8 @@ struct nvfx_insn { u8 op; s8 scale; - s32 unit; + s32 tex_unit; + s32 tex_target; u8 mask; u8 precision; u8 cc_swz[4]; @@ -557,17 +568,20 @@ struct nvfx_insn u8 cc_test : 1; u8 cc_test_reg : 1; + u8 disable_pc : 1; + struct nvfx_reg dst; struct nvfx_src src[3]; }; -static INLINE struct nvfx_insn nvfx_insn(boolean sat,u32 op,s32 unit,struct nvfx_reg dst,u32 mask,struct nvfx_src s0,struct nvfx_src s1,struct nvfx_src s2) +static INLINE struct nvfx_insn nvfx_insn(boolean sat,u32 op,s32 unit,s32 target,struct nvfx_reg dst,u32 mask,struct nvfx_src s0,struct nvfx_src s1,struct nvfx_src s2) { struct nvfx_insn insn; insn.op = op; insn.scale = 0; - insn.unit = unit; + insn.tex_unit = unit; + insn.tex_target = target; insn.mask = mask; insn.precision = FLOAT32; insn.cc_swz[0] = 0; insn.cc_swz[1] = 1; insn.cc_swz[2] = 2; insn.cc_swz[3] = 3; @@ -577,6 +591,7 @@ static INLINE struct nvfx_insn nvfx_insn(boolean sat,u32 op,s32 unit,struct nvfx insn.cc_cond = NVFX_COND_TR; insn.cc_test = 0; insn.cc_test_reg = 0; + insn.disable_pc = 0; insn.dst = dst; insn.src[0] = s0; insn.src[1] = s1; insn.src[2] = s2; @@ -589,7 +604,8 @@ static INLINE struct nvfx_insn nvfx_insn_ctor(struct nvfx_insn *insn,struct nvfx dest_insn.op = insn->op; dest_insn.scale = insn->scale; - dest_insn.unit = insn->unit; + dest_insn.tex_unit = insn->tex_unit; + dest_insn.tex_target = insn->tex_target; dest_insn.mask = insn->mask; dest_insn.precision = insn->precision; dest_insn.cc_swz[0] = insn->cc_swz[0]; dest_insn.cc_swz[1] = insn->cc_swz[1]; dest_insn.cc_swz[2] = insn->cc_swz[2]; dest_insn.cc_swz[3] = insn->cc_swz[3]; @@ -599,6 +615,7 @@ static INLINE struct nvfx_insn nvfx_insn_ctor(struct nvfx_insn *insn,struct nvfx dest_insn.cc_cond = insn->cc_cond; dest_insn.cc_test = insn->cc_test; dest_insn.cc_test_reg = insn->cc_test_reg; + dest_insn.disable_pc = insn->disable_pc; dest_insn.dst = dst; dest_insn.src[0] = s0; dest_insn.src[1] = s1; dest_insn.src[2] = s2; diff --git a/tools/cgcomp/include/parser.h b/tools/cgcomp/include/parser.h index 7df5ee03..c3bf0ef5 100644 --- a/tools/cgcomp/include/parser.h +++ b/tools/cgcomp/include/parser.h @@ -30,17 +30,19 @@ #define MAX_NV_FRAGMENT_PROGRAM_WRITE_ONLYS 2 /*@}*/ -enum eparams { PARAM_FLOAT = 0,PARAM_FLOAT2,PARAM_FLOAT3,PARAM_FLOAT4,PARAM_FLOAT4x4,PARAM_SAMPLER1D,PARAM_SAMPLER2D,PARAM_SAMPLER3D,PARAM_SAMPLERCUBE,PARAM_SAMPLERRECT, PARAM_NULL = 0xff }; +enum eparams { PARAM_FLOAT = 0,PARAM_FLOAT1,PARAM_FLOAT2,PARAM_FLOAT3,PARAM_FLOAT4,PARAM_FLOAT3x4,PARAM_FLOAT4x4,PARAM_FLOAT3x3,PARAM_FLOAT4x3, + PARAM_SAMPLER1D,PARAM_SAMPLER2D,PARAM_SAMPLER3D,PARAM_SAMPLERCUBE,PARAM_SAMPLERRECT, PARAM_SAMPLERSHADOW1D, PARAM_SAMPLERSHADOW2D, + PARAM_SAMPLERSHADOWRECT, PARAM_NULL = 0xff }; typedef struct _jmpdst { - char ident[64]; + std::string ident; u32 location; } jmpdst; typedef struct _paramtype { - const char *ident; + std::string ident; enum eparams type; } paramtype; @@ -69,7 +71,7 @@ typedef struct _param typedef struct _ioset { - const char *name; + std::string name; int index; } ioset; @@ -88,6 +90,8 @@ class CParser std::list GetParameters() const {return m_lParameters;} + static void InitParameter(param *p); + protected: void ParseComment(const char *line); @@ -96,19 +100,20 @@ class CParser const char* ParseMaskedDstRegExt(const char *token,struct nvfx_insn *insn); const char* ParseCond(const char *token,struct nvfx_insn *insn); const char* ParseRegSwizzle(const char *token,struct nvfx_src *reg); + void ParseTextureUnit(const char *token,s32 *texUnit); + void ParseTextureTarget(const char *token,s32 *texTarget); s32 GetParamType(const char *param_str); virtual s32 ConvertInputReg(const char *token) = 0; virtual const char* ParseOutputMask(const char *token,u8 *mask) = 0; void InitInstruction(struct nvfx_insn *insn,u8 op); - void InitParameter(param *p); bool isLetter(int c); bool isDigit(int c); bool isWhitespace(int c); - inline char* SkipSpaces(char *ptr) + inline const char* SkipSpaces(const char *ptr) { while(ptr && *ptr==' ') { ptr++; diff --git a/tools/cgcomp/include/types.h b/tools/cgcomp/include/types.h index f9012429..eab5e58c 100644 --- a/tools/cgcomp/include/types.h +++ b/tools/cgcomp/include/types.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef WIN32 #include @@ -77,41 +78,44 @@ typedef double f64; typedef struct rsx_vp { u16 magic; - u16 num_attrib; - u32 attrib_off; + u16 _pad0; + + u16 num_regs; + u16 num_attr; + u16 num_const; + u16 num_insn; + + u32 attr_off; + u32 const_off; + u32 ucode_off; u32 input_mask; u32 output_mask; u16 const_start; - u16 num_const; - u32 const_off; - - u16 start_insn; - u16 num_insn; - u32 ucode_off; + u16 insn_start; } rsxVertexProgram; typedef struct rsx_fp { u16 magic; - u16 num_attrib; - u32 attrib_off; + u16 _pad0; + + u16 num_regs; + u16 num_attr; + u16 num_const; + u16 num_insn; + + u32 attr_off; + u32 const_off; + u32 ucode_off; - u32 num_regs; u32 fp_control; u16 texcoords; u16 texcoord2D; u16 texcoord3D; - - u16 _pad0; - - u16 num_const; - u32 const_off; - - u16 num_insn; - u32 ucode_off; + u16 _pad1; } rsxFragmentProgram; typedef struct rsx_const diff --git a/tools/cgcomp/include/vpparser.h b/tools/cgcomp/include/vpparser.h index 06df6190..5ac94114 100644 --- a/tools/cgcomp/include/vpparser.h +++ b/tools/cgcomp/include/vpparser.h @@ -20,7 +20,7 @@ class CVPParser : public CParser void ParseMaskedDstReg(const char *token,struct nvfx_insn *insn); void ParseMaskedDstAddr(const char *token,struct nvfx_insn *insn); - void ParseSwizzledSrcReg(const char *token,struct nvfx_src *reg); + void ParseSwizzledSrcReg(const char *token,struct nvfx_insn *insn,s32 slot); const char* ParseOutputReg(const char *token,s32 *reg); const char* ParseInputReg(const char *token,s32 *reg); diff --git a/tools/cgcomp/source/compilerfp.cpp b/tools/cgcomp/source/compilerfp.cpp index 9a1d8f7b..64c78fcb 100644 --- a/tools/cgcomp/source/compilerfp.cpp +++ b/tools/cgcomp/source/compilerfp.cpp @@ -4,21 +4,13 @@ #include "compilerfp.h" #define arith(s,d,m,s0,s1,s2) \ - nvfx_insn((s),0,-1,(d),(m),(s0),(s1),(s2)) + nvfx_insn((s),0,-1,-1,(d),(m),(s0),(s1),(s2)) #define arith_ctor(ins,d,s0,s1,s2) \ nvfx_insn_ctor((ins),(d),(s0),(s1),(s2)) -static INLINE s32 ffs(u32 u) -{ - u32 i = 0; - if(!(u&0xffffffff)) return 0; - while(!(u&0x1)) { - u >>= 1; - i++; - } - return i + 1; -} +#define src_abs_flag(pos) \ + ((pos) == 2 ? NVFX_FP_OP_SRC2_ABS : ((pos) == 1 ? NVFX_FP_OP_SRC1_ABS : NVFX_FP_OP_SRC0_ABS)) CCompilerFP::CCompilerFP() { @@ -33,7 +25,6 @@ CCompilerFP::CCompilerFP() m_rTempsDiscard = 0; m_nCurInstruction = 0; m_pInstructions = NULL; - m_rTemp = NULL; } CCompilerFP::~CCompilerFP() @@ -42,10 +33,10 @@ CCompilerFP::~CCompilerFP() void CCompilerFP::Prepare(CParser *pParser) { - int high_temp = -1; int i,j,nCount = pParser->GetInstructionCount(); struct nvfx_insn *insns = pParser->GetInstructions(); + memset(m_HWRegs, 0, NUM_HW_REGS); m_lParameters = pParser->GetParameters(); for(i=0;ireg.index>high_temp) high_temp = src->reg.index; + reserveReg(src->reg); break; } } switch(insn->dst.type) { case NVFXSR_TEMP: - if((s32)insn->dst.index>high_temp) high_temp = insn->dst.index; + reserveReg(insn->dst); break; } } - - if(++high_temp) { - m_rTemp = (struct nvfx_reg*)calloc(high_temp,sizeof(struct nvfx_reg)); - for(i=0;iGetInstructionCount(); - struct nvfx_insn tmp_insn,*insns = pParser->GetInstructions(); - struct nvfx_src tmp,none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + struct nvfx_insn *insns = pParser->GetInstructions(); Prepare(pParser); @@ -90,108 +74,127 @@ void CCompilerFP::Compile(CParser *pParser) switch(insn->op) { case OPCODE_ADD: - emit_insn(NVFX_FP_OP_OPCODE_ADD,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_ADD); break; case OPCODE_BRK: emit_brk(insn); break; case OPCODE_COS: - emit_insn(NVFX_FP_OP_OPCODE_COS,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_COS); + break; + case OPCODE_DDX: + emit_ddx(insn); + break; + case OPCODE_DDY: + emit_ddy(insn); + break; + case OPCODE_DP2: + emit_insn(insn,NVFX_FP_OP_OPCODE_DP2); break; case OPCODE_DP3: - emit_insn(NVFX_FP_OP_OPCODE_DP3,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_DP3); break; case OPCODE_DP4: - emit_insn(NVFX_FP_OP_OPCODE_DP4,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_DP4); + break; + case OPCODE_DST: + emit_insn(insn,NVFX_FP_OP_OPCODE_DST); break; case OPCODE_EX2: - emit_insn(NVFX_FP_OP_OPCODE_EX2,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_EX2); + break; + case OPCODE_FLR: + emit_insn(insn,NVFX_FP_OP_OPCODE_FLR); + break; + case OPCODE_FRC: + emit_insn(insn,NVFX_FP_OP_OPCODE_FRC); + break; + case OPCODE_KIL_NV: + emit_insn(insn,NVFX_FP_OP_OPCODE_KIL); break; case OPCODE_LG2: - emit_insn(NVFX_FP_OP_OPCODE_LG2,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_LG2); + break; + case OPCODE_LIT: + emit_lit(insn); break; case OPCODE_LRP: - tmp = nvfx_src(temp()); - tmp_insn = arith(0,tmp.reg,insn->mask,neg(insn->src[0]),insn->src[2],insn->src[2]); - emit_insn(NVFX_FP_OP_OPCODE_MAD,&tmp_insn); - - tmp_insn = arith(insn->sat,insn->dst,insn->mask,insn->src[0],insn->src[1],tmp); - emit_insn(NVFX_FP_OP_OPCODE_MAD,&tmp_insn); + emit_lrp(insn); break; case OPCODE_MAX: - emit_insn(NVFX_FP_OP_OPCODE_MAX,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_MAX); break; case OPCODE_MIN: - emit_insn(NVFX_FP_OP_OPCODE_MIN,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_MIN); break; case OPCODE_MAD: - emit_insn(NVFX_FP_OP_OPCODE_MAD,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_MAD); break; case OPCODE_MOV: - emit_insn(NVFX_FP_OP_OPCODE_MOV,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_MOV); break; case OPCODE_MUL: - emit_insn(NVFX_FP_OP_OPCODE_MUL,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_MUL); + break; + case OPCODE_NRM3: + emit_insn(insn,NVFX_FP_OP_OPCODE_NRM); + break; + case OPCODE_PK2H: + emit_insn(insn,NVFX_FP_OP_OPCODE_PK2H); break; case OPCODE_POW: - tmp = nvfx_src(temp()); - - tmp_insn = arith(0,tmp.reg, NVFX_FP_MASK_X, insn->src[0], none, none); - emit_insn(NVFX_FP_OP_OPCODE_LG2,&tmp_insn); - - tmp_insn = arith(0,tmp.reg, NVFX_FP_MASK_X, swz(tmp, X, X, X, X),insn->src[1], none); - emit_insn(NVFX_FP_OP_OPCODE_MUL,&tmp_insn); - - tmp_insn = arith_ctor(insn,insn->dst,swz(tmp, X, X, X, X), none, none); - emit_insn(NVFX_FP_OP_OPCODE_EX2,&tmp_insn); + emit_pow(insn); break; case OPCODE_RCP: - emit_insn(NVFX_FP_OP_OPCODE_RCP,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_RCP); break; case OPCODE_RSQ: - tmp = nvfx_src(temp()); - tmp_insn = arith(0,tmp.reg,NVFX_FP_MASK_X,abs(insn->src[0]),none,none); - tmp_insn.scale = NVFX_FP_OP_DST_SCALE_INV_2X; - emit_insn(NVFX_FP_OP_OPCODE_LG2,&tmp_insn); - - tmp_insn = arith_ctor(insn,insn->dst,neg(swz(tmp,X,X,X,X)),none,none); - emit_insn(NVFX_FP_OP_OPCODE_EX2,&tmp_insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_RSQ); break; case OPCODE_SEQ: - emit_insn(NVFX_FP_OP_OPCODE_SEQ,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SEQ); break; case OPCODE_SFL: - emit_insn(NVFX_FP_OP_OPCODE_SFL,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SFL); break; case OPCODE_SGE: - emit_insn(NVFX_FP_OP_OPCODE_SGE,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SGE); break; case OPCODE_SGT: - emit_insn(NVFX_FP_OP_OPCODE_SGT,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SGT); break; case OPCODE_SIN: - emit_insn(NVFX_FP_OP_OPCODE_SIN,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SIN); break; case OPCODE_SLE: - emit_insn(NVFX_FP_OP_OPCODE_SLE,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SLE); break; case OPCODE_SLT: - emit_insn(NVFX_FP_OP_OPCODE_SLT,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SLT); break; case OPCODE_SNE: - emit_insn(NVFX_FP_OP_OPCODE_SNE,insn); + emit_insn(insn,NVFX_FP_OP_OPCODE_SNE); break; case OPCODE_TEX: - emit_insn(NVFX_FP_OP_OPCODE_TEX,insn); + emit_tex(insn,NVFX_FP_OP_OPCODE_TEX); break; case OPCODE_TXB: - emit_insn(NVFX_FP_OP_OPCODE_TXB,insn); + emit_tex(insn,NVFX_FP_OP_OPCODE_TXB); break; case OPCODE_TXL: - emit_insn(NVFX_FP_OP_OPCODE_TXL_NV40,insn); + emit_txl(insn); break; case OPCODE_TXP: - emit_insn(NVFX_FP_OP_OPCODE_TXP,insn); + emit_tex(insn,NVFX_FP_OP_OPCODE_TXP); + break; + case OPCODE_UP4UB: + emit_insn(insn,NVFX_FP_OP_OPCODE_UP4UB); + break; + case OPCODE_BGNLOOP: + emit_loop(insn); + break; + case OPCODE_ENDLOOP: + fixup_loop(); break; case OPCODE_BGNREP: emit_rep(insn); @@ -211,8 +214,7 @@ void CCompilerFP::Compile(CParser *pParser) case OPCODE_END: if(m_nInstructions) m_pInstructions[m_nCurInstruction].data[0] |= NVFX_FP_OP_PROGRAM_END; else { - m_nCurInstruction = m_nInstructions; - grow_insns(1); + m_nCurInstruction = grow_insns(1); m_pInstructions[m_nCurInstruction].data[0] = 0x00000001; m_pInstructions[m_nCurInstruction].data[1] = 0x00000000; m_pInstructions[m_nCurInstruction].data[2] = 0x00000000; @@ -223,13 +225,12 @@ void CCompilerFP::Compile(CParser *pParser) } } -void CCompilerFP::emit_insn(u8 op,struct nvfx_insn *insn) +void CCompilerFP::emit_insn(struct nvfx_insn *insn,u8 op) { u32 *hw; bool have_const = false; - m_nCurInstruction = m_nInstructions; - grow_insns(1); + m_nCurInstruction = grow_insns(1); memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct fragment_program_exec)); hw = m_pInstructions[m_nCurInstruction].data; @@ -254,33 +255,32 @@ void CCompilerFP::emit_insn(u8 op,struct nvfx_insn *insn) (insn->cc_swz[2] << NVFX_FP_OP_COND_SWZ_Z_SHIFT) | (insn->cc_swz[3] << NVFX_FP_OP_COND_SWZ_W_SHIFT)); - if(insn->unit >= 0) { - hw[0] |= (insn->unit << NVFX_FP_OP_TEX_UNIT_SHIFT); - m_nSamplers |= (1<unit); - } - - emit_dst(&insn->dst,&have_const); - emit_src(0,&insn->src[0],&have_const); - emit_src(1,&insn->src[1],&have_const); - emit_src(2,&insn->src[2],&have_const); + emit_dst(insn,&have_const); + emit_src(insn,0,&have_const); + emit_src(insn,1,&have_const); + emit_src(insn,2,&have_const); } -void CCompilerFP::emit_dst(struct nvfx_reg *dst,bool *have_const) +void CCompilerFP::emit_dst(struct nvfx_insn *insn,bool *have_const) { - s32 index; + struct nvfx_reg *dst = &insn->dst; u32 *hw = m_pInstructions[m_nCurInstruction].data; - index = dst->index; + s32 index = dst->index; switch(dst->type) { case NVFXSR_TEMP: - if(m_nNumRegs<(s32)(index + 1)) - m_nNumRegs = (index + 1); - break; + { + u32 hwReg = dst->is_fp16 ? (index >> 1) : index; + if(m_nNumRegs<(s32)(hwReg + 1)) + m_nNumRegs = (hwReg + 1); + } + break; + case NVFXSR_OUTPUT: - if(dst->index==1) + if(dst->index==0 && !dst->is_fp16) + m_nFPControl |= 0x40; + else if(dst->index==1) m_nFPControl |= 0xe; - else - hw[0] |= NVFX_FP_OP_OUT_REG_HALF; break; case NVFXSR_NONE: hw[0] |= NV40_FP_OP_OUT_NONE; @@ -292,9 +292,10 @@ void CCompilerFP::emit_dst(struct nvfx_reg *dst,bool *have_const) hw[0] |= (index << NVFX_FP_OP_OUT_REG_SHIFT); } -void CCompilerFP::emit_src(s32 pos,struct nvfx_src *src,bool *have_const) +void CCompilerFP::emit_src(struct nvfx_insn *insn,s32 pos,bool *have_const) { u32 sr = 0; + struct nvfx_src *src = &insn->src[pos]; u32 *hw = m_pInstructions[m_nCurInstruction].data; switch(src->reg.type) { @@ -302,9 +303,11 @@ void CCompilerFP::emit_src(s32 pos,struct nvfx_src *src,bool *have_const) sr |= (NVFX_FP_REG_TYPE_INPUT << NVFX_FP_REG_TYPE_SHIFT); hw[0] |= (src->reg.index << NVFX_FP_OP_INPUT_SRC_SHIFT); - if(src->reg.index>=NVFX_FP_OP_INPUT_SRC_TC(0) && src->reg.index<=NVFX_FP_OP_INPUT_SRC_TC(8)) { + if(src->reg.index>=NVFX_FP_OP_INPUT_SRC_TC(0) && src->reg.index<=NVFX_FP_OP_INPUT_SRC_TC(7)) { param fpi = GetInputAttrib(src->reg.index); + hw[3] |= ((insn->disable_pc << NV40_FP_OP_DISABLE_PC_SHIFT) | (0x7fc << NV40_FP_OP_ADDR_INDEX_SHIFT)); + if((int)fpi.index!=-1) { if(fpi.type>PARAM_FLOAT2) m_nTexcoord3D |= (1 << (src->reg.index - NVFX_FP_OP_INPUT_SRC_TC0)); @@ -321,13 +324,13 @@ void CCompilerFP::emit_src(s32 pos,struct nvfx_src *src,bool *have_const) case NVFXSR_IMM: if(!*have_const) { grow_insns(1); + memset(&m_pInstructions[m_nCurInstruction + 1], 0,4*sizeof(f32)); hw = m_pInstructions[m_nCurInstruction].data; *have_const = true; } { param fpd = GetImmData(src->reg.index); if(fpd.values!=NULL) memcpy(&m_pInstructions[m_nCurInstruction + 1],fpd.values,4*sizeof(f32)); - sr |= (NVFX_FP_REG_TYPE_CONST << NVFX_FP_REG_TYPE_SHIFT); } break; @@ -364,7 +367,7 @@ void CCompilerFP::emit_src(s32 pos,struct nvfx_src *src,bool *have_const) sr |= NVFX_FP_REG_NEGATE; if(src->abs) - hw[1] |= (1 << (29 + pos)); + hw[1] |= src_abs_flag(pos); sr |= ((src->swz[0] << NVFX_FP_REG_SWZ_X_SHIFT) | (src->swz[1] << NVFX_FP_REG_SWZ_Y_SHIFT) | @@ -379,8 +382,7 @@ void CCompilerFP::emit_rep(struct nvfx_insn *insn) u32 *hw; int count; - m_nCurInstruction = m_nInstructions; - grow_insns(1); + m_nCurInstruction = grow_insns(1); memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct fragment_program_exec)); hw = m_pInstructions[m_nCurInstruction].data; @@ -421,6 +423,17 @@ void CCompilerFP::fixup_rep() m_repStack.pop(); } +void CCompilerFP::fixup_loop() +{ + u32 *hw; + + hw = m_pInstructions[m_loopStack.top()].data; + + hw[3] |= m_nInstructions * 4; + + m_loopStack.pop(); +} + void CCompilerFP::fixup_if() { u32 *hw; @@ -445,8 +458,7 @@ void CCompilerFP::emit_brk(struct nvfx_insn *insn) { u32 *hw; - m_nCurInstruction = m_nInstructions; - grow_insns(1); + m_nCurInstruction = grow_insns(1); memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct fragment_program_exec)); hw = m_pInstructions[m_nCurInstruction].data; @@ -466,8 +478,7 @@ void CCompilerFP::emit_if(struct nvfx_insn *insn) { u32 *hw; - m_nCurInstruction = m_nInstructions; - grow_insns(1); + m_nCurInstruction = grow_insns(1); memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct fragment_program_exec)); hw = m_pInstructions[m_nCurInstruction].data; @@ -485,9 +496,195 @@ void CCompilerFP::emit_if(struct nvfx_insn *insn) m_ifStack.push(m_nCurInstruction); } +void CCompilerFP::emit_loop(struct nvfx_insn *insn) +{ + u32 *hw; + int count1,count2,count3; + + m_nCurInstruction = grow_insns(1); + memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct fragment_program_exec)); + + hw = m_pInstructions[m_nCurInstruction].data; + + param fpd = GetImmData(insn->src[0].reg.index); + + if (insn->src[0].reg.type != NVFXSR_IMM || + (*fpd.values)[0] < 0.0 || (*fpd.values)[0] > 255.0) { + fprintf(stderr,"Input to LOOP must be immediate number 0-255\n"); + exit(EXIT_FAILURE); + } + + count1 = (int)(*fpd.values)[0]; + count2 = (int)(*fpd.values)[1]; + count3 = (int)(*fpd.values)[2]; + hw[0] |= (NV40_FP_OP_BRA_OPCODE_LOOP << NVFX_FP_OP_OPCODE_SHIFT); + hw[0] |= NV40_FP_OP_OUT_NONE; + hw[0] |= NVFX_FP_PRECISION_FP16 << NVFX_FP_OP_PRECISION_SHIFT; + hw[2] |= NV40_FP_OP_OPCODE_IS_BRANCH; + hw[2] |= (count1<cc_cond << NVFX_FP_OP_COND_SHIFT); + hw[1] |= ((insn->cc_swz[0] << NVFX_FP_OP_COND_SWZ_X_SHIFT) | + (insn->cc_swz[1] << NVFX_FP_OP_COND_SWZ_Y_SHIFT) | + (insn->cc_swz[2] << NVFX_FP_OP_COND_SWZ_Z_SHIFT) | + (insn->cc_swz[3] << NVFX_FP_OP_COND_SWZ_W_SHIFT)); + + m_loopStack.push(m_nCurInstruction); +} + +void CCompilerFP::emit_lrp(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + + tmp_insn = arith(0,tmp.reg,insn->mask,neg(insn->src[0]),insn->src[2],insn->src[2]); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MAD); + + tmp_insn = arith(insn->sat,insn->dst,insn->mask,insn->src[0],insn->src[1],tmp); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MAD); +} + +void CCompilerFP::emit_pow(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src src = nvfx_src(insn->dst); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + tmp_insn = arith(0,insn->dst, NVFX_FP_MASK_X, insn->src[0], none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_LG2); + + tmp_insn = arith(0,insn->dst, NVFX_FP_MASK_X, swz(src, X, X, X, X),insn->src[1], none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MUL); + + tmp_insn = arith_ctor(insn,insn->dst,swz(src, X, X, X, X), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_EX2); +} + +void CCompilerFP::emit_lit(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + struct nvfx_src maxs = nvfx_src(imm(0.0f, FLT_MIN, 0.0f, 0.0f)); + + tmp_insn = arith(0, tmp.reg, (NVFX_FP_MASK_Y | NVFX_FP_MASK_W), swz(insn->src[0], X, X, X, Y), swz(maxs, X, X, Y, Y), none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MAX); + + tmp_insn = arith(0, tmp.reg, NVFX_FP_MASK_W, swz(tmp, W, W, W, W), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_LG2); + + tmp_insn = arith(0, tmp.reg, NVFX_FP_MASK_W, swz(tmp, W, W, W, W), swz(insn->src[0], W, W, W, W), none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MUL); + + tmp_insn = arith_ctor(insn, insn->dst, swz(tmp, Y, Y, W, W), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_LITEX2_NV40); +} + +void CCompilerFP::emit_ddx(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + if(insn->mask&(NVFX_FP_MASK_Z | NVFX_FP_MASK_W)) { + tmp_insn = arith(insn->sat, tmp.reg, (NVFX_FP_MASK_X | NVFX_FP_MASK_Y), swz(insn->src[0], Z, W, Z, W), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_DDX); + + tmp_insn = arith(0, tmp.reg, (NVFX_FP_MASK_Z | NVFX_FP_MASK_W), swz(tmp, X, Y, X, Y), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MOV); + + tmp_insn = arith(insn->sat, tmp.reg, (NVFX_FP_MASK_X | NVFX_FP_MASK_Y), insn->src[0], none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_DDX); + + tmp_insn = arith(0, insn->dst, insn->mask, tmp, none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MOV); + } else + emit_insn(insn,NVFX_FP_OP_OPCODE_DDX); +} + +void CCompilerFP::emit_ddy(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + if(insn->mask&(NVFX_FP_MASK_Z | NVFX_FP_MASK_W)) { + tmp_insn = arith(insn->sat, tmp.reg, (NVFX_FP_MASK_X | NVFX_FP_MASK_Y), swz(insn->src[0], Z, W, Z, W), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_DDY); + + tmp_insn = arith(0, tmp.reg, (NVFX_FP_MASK_Z | NVFX_FP_MASK_W), swz(tmp, X, Y, X, Y), none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MOV); + + tmp_insn = arith(insn->sat, tmp.reg, (NVFX_FP_MASK_X | NVFX_FP_MASK_Y), insn->src[0], none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_DDY); + + tmp_insn = arith(0, insn->dst, insn->mask, tmp, none, none); + emit_insn(&tmp_insn,NVFX_FP_OP_OPCODE_MOV); + } else + emit_insn(insn,NVFX_FP_OP_OPCODE_DDY); +} + +void CCompilerFP::emit_txl(struct nvfx_insn *insn) +{ + u32 *hw; + struct nvfx_insn tmp_insn; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + if(insn->tex_unit<0 || insn->tex_unit>15) return; + + tmp_insn = arith_ctor(insn, insn->dst, insn->src[0], swz(insn->src[0], W, W, W, W), none); + emit_insn(&tmp_insn, NVFX_FP_OP_OPCODE_TXL_NV40); + + hw = m_pInstructions[m_nCurInstruction].data; + hw[0] |= (insn->tex_unit << NVFX_FP_OP_TEX_UNIT_SHIFT); + + m_nSamplers |= (1<tex_unit); +} + +void CCompilerFP::emit_tex(struct nvfx_insn *insn,u8 op) +{ + u32 *hw; + + if(insn->tex_unit<0 || insn->tex_unit>15) return; + + emit_insn(insn,op); + + hw = m_pInstructions[m_nCurInstruction].data; + hw[0] |= (insn->tex_unit << NVFX_FP_OP_TEX_UNIT_SHIFT); + + m_nSamplers |= (1<tex_unit); +} + +struct nvfx_reg CCompilerFP::imm(f32 x, f32 y, f32 z, f32 w) +{ + param p; + f32 v[4] = { x, y, z, w }; + s32 idx = m_lParameters.size(); + + p.count = 1; + p.is_const = 1; + p.is_internal = 1; + p.type = PARAM_FLOAT4; + + CParser::InitParameter(&p); + memcpy(p.values, v, sizeof(f32)*4); + + m_lParameters.push_back(p); + + return nvfx_reg(NVFXSR_IMM, idx); +} + +void CCompilerFP::reserveReg(const struct nvfx_reg& reg) +{ + u32 index = reg.is_fp16 ? (reg.index >> 1) : reg.index; + m_HWRegs[index] |= reg.is_fp16 ? (1 << (reg.index&0x01)) : 0x03; + m_rTemps |= (1 << index); +} + struct nvfx_reg CCompilerFP::temp() { - s32 idx = ffs(~m_rTemps) - 1; + s32 idx = __builtin_ctzll(~m_rTemps); if(idx<0) return nvfx_reg(NVFXSR_TEMP,0); @@ -503,8 +700,12 @@ void CCompilerFP::release_temps() m_rTempsDiscard = 0; } -void CCompilerFP::grow_insns(int count) +int CCompilerFP::grow_insns(int count) { + int pos = m_nInstructions; + m_nInstructions += count; m_pInstructions = (struct fragment_program_exec*)realloc(m_pInstructions,m_nInstructions*sizeof(struct fragment_program_exec)); + + return pos; } diff --git a/tools/cgcomp/source/compiler.cpp b/tools/cgcomp/source/compilervp.cpp similarity index 56% rename from tools/cgcomp/source/compiler.cpp rename to tools/cgcomp/source/compilervp.cpp index 2ef2ebe7..b8173cbb 100644 --- a/tools/cgcomp/source/compiler.cpp +++ b/tools/cgcomp/source/compilervp.cpp @@ -1,54 +1,46 @@ #include "types.h" #include "parser.h" -#include "compiler.h" +#include "compilervp.h" #define gen_op(o,t) \ ((NVFX_VP_INST_SLOT_##t<<7)|NVFX_VP_INST_##t##_OP_##o) +#define gen_op_nv40(o,t) \ + ((NVFX_VP_INST_SLOT_##t<<7)|NV40_VP_INST_##t##_OP_##o) + #define arith(s,d,m,s0,s1,s2) \ - nvfx_insn((s), 0, -1, (d), (m), (s0), (s1), (s2)) + nvfx_insn((s), 0, -1, -1, (d), (m), (s0), (s1), (s2)) #define arith_ctor(ins,d,s0,s1,s2) \ nvfx_insn_ctor((ins), (d), (s0), (s1), (s2)) -static INLINE s32 ffs(u32 u) -{ - u32 i = 0; - if(!(u&0xffffffff)) return 0; - while(!(u&0x1)) { - u >>= 1; - i++; - } - return i + 1; -} - -CCompiler::CCompiler() +CCompilerVP::CCompilerVP() { m_nInputMask = 0; m_nOutputMask = 0; m_nInstructions = 0; m_nConsts = 0; m_rTemps = 0; - m_nNumRegs = 1; + m_nNumRegs = 0; m_rTempsDiscard = 0; m_nCurInstruction = 0; m_pInstructions = NULL; m_pConstData = NULL; - m_rTemp = NULL; - m_rConst = NULL; } -CCompiler::~CCompiler() +CCompilerVP::~CCompilerVP() { } -void CCompiler::Prepare(CParser *pParser) +void CCompilerVP::Prepare(CParser *pParser) { s32 high_const = -1,high_temp = -1; u32 i,j,nICount = pParser->GetInstructionCount(); struct nvfx_insn *insns = pParser->GetInstructions(); + m_lParameters = pParser->GetParameters(); + for(i=0;i insns_pos; std::list label_reloc; @@ -101,25 +89,23 @@ void CCompiler::Compile(CParser *pParser) Prepare(pParser); for(i=0;iop) { case OPCODE_NOP: - tmp_insn = arith(0,none.reg,0,none,none,none); - emit_insn(gen_op(NOP,VEC),&tmp_insn); + emit_nop(); break; case OPCODE_ABS: - tmp_insn = arith_ctor(insn,insn->dst,abs(insn->src[0]),none,none); - emit_insn(gen_op(MOV,VEC),&tmp_insn); + emit_abs(insn); break; case OPCODE_ADD: - emit_insn(gen_op(ADD,VEC),insn); + emit_insn(insn,gen_op(ADD,VEC)); break; case OPCODE_ARA: break; case OPCODE_ARL: + emit_insn(insn,gen_op(ARL,VEC)); break; case OPCODE_ARR: break; @@ -128,131 +114,128 @@ void CCompiler::Compile(CParser *pParser) reloc.target = insn->dst.index; label_reloc.push_back(reloc); - tmp_insn = arith(0,none.reg,0,none,none,none); - emit_insn(gen_op(BRA,SCA),&tmp_insn); + tmp_insn = arith_ctor(insn, none.reg, none, none, none); + emit_insn(&tmp_insn,gen_op(BRA,SCA)); break; case OPCODE_CAL: reloc.location = m_nInstructions; reloc.target = insn->dst.index; label_reloc.push_back(reloc); - tmp_insn = arith(0,none.reg,0,none,none,none); - emit_insn(gen_op(CAL,SCA),&tmp_insn); + tmp_insn = arith_ctor(insn, none.reg, none, none, none); + emit_insn(&tmp_insn,gen_op(CAL,SCA)); break; case OPCODE_COS: - emit_insn(gen_op(COS,SCA),insn); + emit_insn(insn,gen_op(COS,SCA)); break; case OPCODE_DP3: - emit_insn(gen_op(DP3,VEC),insn); + emit_insn(insn,gen_op(DP3,VEC)); break; case OPCODE_DP4: - emit_insn(gen_op(DP4,VEC),insn); + emit_insn(insn,gen_op(DP4,VEC)); break; case OPCODE_DPH: - emit_insn(gen_op(DPH,VEC),insn); + emit_insn(insn,gen_op(DPH,VEC)); break; case OPCODE_DST: - emit_insn(gen_op(DST,VEC),insn); + emit_insn(insn,gen_op(DST,VEC)); break; case OPCODE_EX2: - emit_insn(gen_op(EX2,SCA),insn); + emit_insn(insn,gen_op(EX2,SCA)); break; case OPCODE_EXP: - emit_insn(gen_op(EXP,SCA),insn); + emit_insn(insn,gen_op(EXP,SCA)); break; case OPCODE_FLR: - emit_insn(gen_op(FLR,VEC),insn); + emit_insn(insn,gen_op(FLR,VEC)); break; case OPCODE_FRC: - emit_insn(gen_op(FRC,VEC),insn); + emit_insn(insn,gen_op(FRC,VEC)); break; case OPCODE_LG2: - emit_insn(gen_op(LG2,SCA),insn); + emit_insn(insn,gen_op(LG2,SCA)); break; case OPCODE_LIT: - emit_insn(gen_op(LIT,SCA),insn); + emit_insn(insn,gen_op(LIT,SCA)); break; case OPCODE_LOG: - emit_insn(gen_op(LOG,SCA),insn); + emit_insn(insn,gen_op(LOG,SCA)); + break; + case OPCODE_LRP: + emit_lrp(insn); break; case OPCODE_MAD: - emit_insn(gen_op(MAD,VEC),insn); + emit_insn(insn,gen_op(MAD,VEC)); break; case OPCODE_MAX: - emit_insn(gen_op(MAX,VEC),insn); + emit_insn(insn,gen_op(MAX,VEC)); break; case OPCODE_MIN: - emit_insn(gen_op(MIN,VEC),insn); + emit_insn(insn,gen_op(MIN,VEC)); break; case OPCODE_MOV: - emit_insn(gen_op(MOV,VEC),insn); + emit_insn(insn,gen_op(MOV,VEC)); break; case OPCODE_MUL: - emit_insn(gen_op(MUL,VEC),insn); + emit_insn(insn,gen_op(MUL,VEC)); break; case OPCODE_POW: - tmp = nvfx_src(temp()); - - tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_X, none, none, insn->src[0]); - emit_insn(gen_op(LG2,SCA),&tmp_insn); - - tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_X, swz(tmp, X, X, X, X), insn->src[1], none); - emit_insn(gen_op(MUL,VEC),&tmp_insn); - - tmp_insn = arith_ctor(insn, insn->dst, none, none, swz(tmp, X, X, X, X)); - emit_insn(gen_op(EX2,SCA),&tmp_insn); + emit_pow(insn); break; case OPCODE_RCC: - emit_insn(gen_op(RCC,SCA),insn); + emit_insn(insn,gen_op(RCC,SCA)); break; case OPCODE_RCP: - emit_insn(gen_op(RCP,SCA),insn); + emit_insn(insn,gen_op(RCP,SCA)); break; case OPCODE_RSQ: - emit_insn(gen_op(RSQ,SCA),insn); + emit_insn(insn,gen_op(RSQ,SCA)); break; case OPCODE_SEQ: - emit_insn(gen_op(SEQ,VEC),insn); + emit_insn(insn,gen_op(SEQ,VEC)); break; case OPCODE_SFL: - emit_insn(gen_op(SFL,VEC),insn); + emit_insn(insn,gen_op(SFL,VEC)); break; case OPCODE_SGE: - emit_insn(gen_op(SGE,VEC),insn); + emit_insn(insn,gen_op(SGE,VEC)); break; case OPCODE_SGT: - emit_insn(gen_op(SGT,VEC),insn); + emit_insn(insn,gen_op(SGT,VEC)); break; case OPCODE_SIN: - emit_insn(gen_op(SIN,SCA),insn); + emit_insn(insn,gen_op(SIN,SCA)); break; case OPCODE_SLE: - emit_insn(gen_op(SLE,VEC),insn); + emit_insn(insn,gen_op(SLE,VEC)); break; case OPCODE_SLT: - emit_insn(gen_op(SLT,VEC),insn); + emit_insn(insn,gen_op(SLT,VEC)); break; case OPCODE_SNE: - emit_insn(gen_op(SNE,VEC),insn); + emit_insn(insn,gen_op(SNE,VEC)); break; case OPCODE_SSG: - emit_insn(gen_op(SSG,VEC),insn); + emit_insn(insn,gen_op(SSG,VEC)); break; case OPCODE_STR: - emit_insn(gen_op(STR,VEC),insn); + emit_insn(insn,gen_op(STR,VEC)); break; case OPCODE_SUB: - tmp_insn = arith_ctor(insn,insn->dst,insn->src[0],none,neg(insn->src[2])); - emit_insn(gen_op(ADD,VEC),&tmp_insn); + emit_sub(insn); + break; + case OPCODE_TEX: + emit_tex(insn); break; case OPCODE_END: - if(m_nInstructions) m_pInstructions[m_nCurInstruction].data[3] |= NVFX_VP_INST_LAST; - else { - tmp_insn = arith(0,none.reg,0,none,none,none); - emit_insn(gen_op(NOP,VEC),&tmp_insn); - m_pInstructions[m_nCurInstruction].data[3] |= NVFX_VP_INST_LAST; + if(!m_nInstructions) { + emit_nop(); } + m_pInstructions[m_nCurInstruction].data[3] |= NVFX_VP_INST_LAST; break; + default: + fprintf(stderr, "Unknown instruction \"%d\"\n", insn->op); + exit(EXIT_FAILURE); } release_temps(); } @@ -267,23 +250,21 @@ void CCompiler::Compile(CParser *pParser) } } -void CCompiler::emit_insn(u8 opcode,struct nvfx_insn *insn) +void CCompilerVP::emit_insn(struct nvfx_insn *insn,u8 opcode) { u32 *hw; u32 slot = opcode>>7; u32 op = opcode&0x7f; - m_nCurInstruction = m_nInstructions++; - m_pInstructions = (struct vertex_program_exec*)realloc(m_pInstructions,m_nInstructions*sizeof(struct vertex_program_exec)); - + m_nCurInstruction = grow_insns(1); memset(&m_pInstructions[m_nCurInstruction],0,sizeof(struct vertex_program_exec)); hw = m_pInstructions[m_nCurInstruction].data; - emit_dst(hw,slot,insn); - emit_src(hw,0,&insn->src[0]); - emit_src(hw,1,&insn->src[1]); - emit_src(hw,2,&insn->src[2]); + emit_dst(insn,slot); + emit_src(insn,0); + emit_src(insn,1); + emit_src(insn,2); hw[0] |= (insn->cc_cond << NVFX_VP(INST_COND_SHIFT)); hw[0] |= (insn->cc_test << NVFX_VP(INST_COND_TEST_SHIFT)); @@ -295,10 +276,11 @@ void CCompiler::emit_insn(u8 opcode,struct nvfx_insn *insn) if(insn->cc_update) hw[0] |= NVFX_VP(INST_COND_UPDATE_ENABLE); + if(insn->cc_update_reg) + hw[0] |= NVFX_VP(INST_COND_REG_SELECT_1); + if(insn->sat) - { hw[0] |= NV40_VP_INST_SATURATE; - } if (slot == 0) { hw[1] |= (op << NV40_VP_INST_VEC_OPCODE_SHIFT); @@ -311,9 +293,10 @@ void CCompiler::emit_insn(u8 opcode,struct nvfx_insn *insn) } } -void CCompiler::emit_dst(u32 *hw,u8 slot,struct nvfx_insn *insn) +void CCompilerVP::emit_dst(struct nvfx_insn *insn,u8 slot) { struct nvfx_reg *dst = &insn->dst; + u32 *hw = m_pInstructions[m_nCurInstruction].data; switch(dst->type) { case NVFXSR_NONE: @@ -324,6 +307,9 @@ void CCompiler::emit_dst(u32 *hw,u8 slot,struct nvfx_insn *insn) hw[3] |= NV40_VP_INST_SCA_DEST_TEMP_MASK; break; case NVFXSR_TEMP: + if(m_nNumRegs<(s32)(dst->index + 1)) + m_nNumRegs = (dst->index + 1); + case NVFXSR_ADDRESS: hw[3] |= NV40_VP_INST_DEST_MASK; if (slot == 0) hw[0] |= (dst->index << NV40_VP_INST_VEC_DEST_TEMP_SHIFT); @@ -362,14 +348,21 @@ void CCompiler::emit_dst(u32 *hw,u8 slot,struct nvfx_insn *insn) insn->mask = NVFX_VP_MASK_W; m_nOutputMask |= (1 << 11); break; - case NV40_VP_INST_DEST_COL0 : m_nOutputMask |= (1 << 0); break; - case NV40_VP_INST_DEST_COL1 : m_nOutputMask |= (1 << 1); break; - case NV40_VP_INST_DEST_BFC0 : m_nOutputMask |= (1 << 2); break; - case NV40_VP_INST_DEST_BFC1 : m_nOutputMask |= (1 << 3); break; + case NV40_VP_INST_DEST_COL0 : + case NV40_VP_INST_DEST_COL1 : + m_nOutputMask |= (1 << (dst->index - NV40_VP_INST_DEST_COL0)); + m_nOutputMask |= (4 << (dst->index - NV40_VP_INST_DEST_COL0)); + break; + case NV40_VP_INST_DEST_BFC0 : + case NV40_VP_INST_DEST_BFC1 : + m_nOutputMask |= (1 << (dst->index - NV40_VP_INST_DEST_BFC0)); + m_nOutputMask |= (4 << (dst->index - NV40_VP_INST_DEST_BFC0)); + break; case NV40_VP_INST_DEST_FOGC : m_nOutputMask |= (1 << 4); break; case NV40_VP_INST_DEST_PSZ : m_nOutputMask |= (1 << 5); break; default: - if(dst->index>=NV40_VP_INST_DEST_TC(0) && dst->index<=NV40_VP_INST_DEST_TC(7)) m_nOutputMask |= (1<<(dst->index - NV40_VP_INST_DEST_TC0 + 14)); + if(dst->index>=NV40_VP_INST_DEST_TC(0) && dst->index<=NV40_VP_INST_DEST_TC(7)) + m_nOutputMask |= (0x4000 << (dst->index - NV40_VP_INST_DEST_TC0)); break; } hw[3] |= (dst->index << NV40_VP_INST_DEST_SHIFT); @@ -384,10 +377,12 @@ void CCompiler::emit_dst(u32 *hw,u8 slot,struct nvfx_insn *insn) } } -void CCompiler::emit_src(u32 *hw, u8 pos, struct nvfx_src *src) +void CCompilerVP::emit_src(struct nvfx_insn *insn,u8 pos) { u32 sr = 0; struct nvfx_relocation reloc; + struct nvfx_src *src = &insn->src[pos]; + u32 *hw = m_pInstructions[m_nCurInstruction].data; switch(src->reg.type) { case NVFXSR_TEMP: @@ -407,6 +402,10 @@ void CCompiler::emit_src(u32 *hw, u8 pos, struct nvfx_src *src) reloc.target = src->reg.index; m_lConstRelocation.push_back(reloc); break; + case NVFXSR_SAMPLER: + sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) << NVFX_VP(SRC_REG_TYPE_SHIFT)); + sr |= (src->reg.index << NVFX_VP(SRC_TEMP_SRC_SHIFT)); + break; case NVFXSR_NONE: sr |= (NVFX_VP(SRC_REG_TYPE_INPUT) << NVFX_VP(SRC_REG_TYPE_SHIFT)); @@ -449,27 +448,119 @@ void CCompiler::emit_src(u32 *hw, u8 pos, struct nvfx_src *src) } } -struct nvfx_reg CCompiler::temp() +void CCompilerVP::emit_pow(struct nvfx_insn *insn) +{ + struct nvfx_src tmp; + struct nvfx_insn tmp_insn; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + tmp = nvfx_src(temp()); + + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_X, none, none, insn->src[0]); + emit_insn(&tmp_insn,gen_op(LG2,SCA)); + + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_X, swz(tmp, X, X, X, X), insn->src[1], none); + emit_insn(&tmp_insn,gen_op(MUL,VEC)); + + tmp_insn = arith_ctor(insn, insn->dst, none, none, swz(tmp, X, X, X, X)); + emit_insn(&tmp_insn,gen_op(EX2,SCA)); +} + +void CCompilerVP::emit_abs(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + tmp_insn = arith_ctor(insn,insn->dst,abs(insn->src[0]),none,none); + emit_insn(&tmp_insn,gen_op(MOV,VEC)); +} + +void CCompilerVP::emit_sub(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + tmp_insn = arith_ctor(insn,insn->dst,insn->src[0],none,neg(insn->src[2])); + emit_insn(&tmp_insn,gen_op(ADD,VEC)); +} + +void CCompilerVP::emit_tex(struct nvfx_insn *insn) +{ + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + param vpi = GetInputAttrib(insn->src[0].reg.index); + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + if(vpi.type==PARAM_FLOAT) { + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_X, insn->src[0], none, none); + emit_insn(&tmp_insn, gen_op(MOV,VEC)); + + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_W, swz(insn->src[0], X, X, X, X), swz(insn->src[0], X, X, X, X), none); + emit_insn(&tmp_insn,gen_op(SFL,VEC)); + + tmp_insn = arith_ctor(insn, insn->dst, swz(tmp, X, X, W, W), insn->src[1], none); + emit_insn(&tmp_insn,gen_op_nv40(TXL,VEC)); + } else if(vpi.type==PARAM_FLOAT2) { + tmp_insn = arith(0, tmp.reg, (NVFX_VP_MASK_X | NVFX_VP_MASK_Y), insn->src[0], none, none); + emit_insn(&tmp_insn, gen_op(MOV,VEC)); + + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_W, swz(insn->src[0], X, X, X, X), swz(insn->src[0], X, X, X, X), none); + emit_insn(&tmp_insn,gen_op(SFL,VEC)); + + tmp_insn = arith_ctor(insn, insn->dst, swz(tmp, X, Y, W, W), insn->src[1], none); + emit_insn(&tmp_insn,gen_op_nv40(TXL,VEC)); + } else if(vpi.type==PARAM_FLOAT3) { + tmp_insn = arith(0, tmp.reg, (NVFX_VP_MASK_X | NVFX_VP_MASK_Y | NVFX_VP_MASK_Z), insn->src[0], none, none); + emit_insn(&tmp_insn, gen_op(MOV,VEC)); + + tmp_insn = arith(0, tmp.reg, NVFX_VP_MASK_W, swz(insn->src[0], X, X, X, X), swz(insn->src[0], X, X, X, X), none); + emit_insn(&tmp_insn,gen_op(SFL,VEC)); + + tmp_insn = arith_ctor(insn, insn->dst, swz(tmp, X, Y, Z, W), insn->src[1], none); + emit_insn(&tmp_insn,gen_op_nv40(TXL,VEC)); + } +} + +void CCompilerVP::emit_lrp(struct nvfx_insn *insn) { - s32 idx = ffs(~m_rTemps) - 1; + struct nvfx_insn tmp_insn; + struct nvfx_src tmp = nvfx_src(temp()); + + tmp_insn = arith(0, tmp.reg, insn->mask, neg(insn->src[0]), insn->src[2], insn->src[2]); + emit_insn(&tmp_insn,gen_op(MAD,VEC)); + + tmp_insn = arith(insn->sat, insn->dst, insn->mask, insn->src[0], insn->src[1], tmp); + emit_insn(&tmp_insn,gen_op(MAD,VEC)); +} + +void CCompilerVP::emit_nop() +{ + struct nvfx_insn tmp_insn; + struct nvfx_src none = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); + + tmp_insn = arith(0,none.reg,0,none,none,none); + emit_insn(&tmp_insn,gen_op(NOP,VEC)); +} + +struct nvfx_reg CCompilerVP::temp() +{ + s32 idx = __builtin_ctzll(~m_rTemps); if(idx<0) return nvfx_reg(NVFXSR_NONE,0); m_rTemps |= (1<value[3] = w; return nvfx_reg(NVFXSR_CONST,idx); } + +int CCompilerVP::grow_insns(int count) +{ + int pos = m_nInstructions; + + m_nInstructions += count; + m_pInstructions = (struct vertex_program_exec*)realloc(m_pInstructions,m_nInstructions*sizeof(struct vertex_program_exec)); + + return pos; +} diff --git a/tools/cgcomp/source/fpparser.cpp b/tools/cgcomp/source/fpparser.cpp index b859880f..9657172f 100644 --- a/tools/cgcomp/source/fpparser.cpp +++ b/tools/cgcomp/source/fpparser.cpp @@ -68,6 +68,7 @@ struct _opcode { "KIL", OPCODE_KIL_NV, INPUT_CC, OUTPUT_NONE, 0 }, { "LG2", OPCODE_LG2, INPUT_1S, OUTPUT_S, _R | _H | _C | _S }, { "LIT", OPCODE_LIT, INPUT_1V, OUTPUT_V, _R | _H | _C | _S }, + { "LOOP", OPCODE_BGNLOOP, INPUT_1V, OUTPUT_NONE, 0 }, { "LRP", OPCODE_LRP, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MAD", OPCODE_MAD, INPUT_3V, OUTPUT_V, _R | _H | _X | _C | _S }, { "MAX", OPCODE_MAX, INPUT_2V, OUTPUT_V, _R | _H | _X | _C | _S }, @@ -110,8 +111,8 @@ struct _opcode { "XPD", OPCODE_X2D, INPUT_2V, OUTPUT_V, _R | _H | _C | _S }, // { "END", OPCODE_END,0,0,0 }, - { NULL, (enum nvfx_opcode) -1, 0, 0, 0 } }; +static const size_t FP_OPCODES_CNT = sizeof(fp_opcodes)/sizeof(struct _opcode); static ioset fp_inputs[] = { @@ -134,7 +135,7 @@ static ioset fp_inputs[] = { "TEX6", 10 }, { "TEX7", 11 } }; -static const u32 FP_INPUTS_CNT = sizeof(fp_inputs)/sizeof(ioset); +static const size_t FP_INPUTS_CNT = sizeof(fp_inputs)/sizeof(ioset); static ioset fp_outputs[] = { @@ -144,7 +145,7 @@ static ioset fp_outputs[] = { "COLH", 0}, { "DEPR", 1} }; -static const u32 FP_OUTPUTS_CNT = sizeof(fp_outputs)/sizeof(ioset); +static const size_t FP_OUTPUTS_CNT = sizeof(fp_outputs)/sizeof(ioset); CFPParser::CFPParser() : CParser() { @@ -194,10 +195,9 @@ int CFPParser::Parse(const char *str) continue; } - char *label = NULL; - char *col_ptr = NULL; - char *opcode = NULL; - char *ptr = line; + const char *col_ptr = NULL; + const char *ptr = line; + const char *param_str = NULL; if((col_ptr = strstr((char*)ptr,":"))!=NULL) { int j = 0; @@ -210,41 +210,43 @@ int CFPParser::Parse(const char *str) } if(valid) { - label = strtok(ptr,":\x20"); + (void)strtok((char*)ptr,":\x20"); ptr = col_ptr + 1; } } - opcode = strtok(ptr," "); + ptr = SkipSpaces(ptr); + if ((param_str = strstr(ptr, "OPTION"))!=NULL) { + param_str = SkipSpaces(param_str + 6); + if(strncasecmp(param_str,"NV_fragment_program2",20)==0) + m_nOption |= NV_OPTION_FP2; + continue; + } + else if ((param_str = strstr(ptr, "PARAM"))!=NULL) + continue; + else if ((param_str = strstr(ptr, "TEMP"))!=NULL) + continue; + else if ((param_str = strstr(ptr, "OUTPUT"))!=NULL) { + ParseOutput(ptr); + continue; + } else { + const char *opcode = strtok((char*)ptr," "); + struct _opcode opc = FindOpcode(opcode); - if(opcode) { - char *param_str = SkipSpaces(strtok(NULL,"\0")); - if(strcasecmp(opcode,"OPTION")==0) { - if(strncasecmp(param_str,"NV_fragment_program2",20)==0) - m_nOption |= NV_OPTION_FP2; - continue; - } else if(strcasecmp(opcode,"PARAM")==0) - continue; - else if(strcasecmp(opcode,"TEMP")==0) - continue; - else if(strcasecmp(opcode,"OUTPUT")==0) { - ParseOutput(param_str); + if(opc.opcode>=MAX_OPCODE) continue; - } else { - struct _opcode opc = FindOpcode(opcode); - insn = &m_pInstructions[m_nInstructions]; - - if(opc.opcode>=MAX_OPCODE) continue; - - InitInstruction(insn,opc.opcode); - if(opc.opcode==OPCODE_END) { - m_nInstructions++; - break; - } + + insn = &m_pInstructions[m_nInstructions]; + param_str = SkipSpaces(strtok(NULL,"\0")); - ParseInstruction(insn,&opc,param_str); + InitInstruction(insn,opc.opcode); + if(opc.opcode==OPCODE_END) { m_nInstructions++; + break; } + + ParseInstruction(insn,&opc,param_str); + m_nInstructions++; } } return 0; @@ -252,14 +254,17 @@ int CFPParser::Parse(const char *str) void CFPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char *param_str) { - char *token = SkipSpaces(strtok((char*)param_str,",")); + const char *token = SkipSpaces(strtok((char*)param_str,",")); insn->precision = opc->suffixes&(_R|_H|_X); insn->sat = ((opc->suffixes&_S) ? TRUE : FALSE); insn->cc_update = ((opc->suffixes&_C) ? TRUE : FALSE); + insn->disable_pc = IsPCDisablingInstruction(insn); if(opc->outputs==OUTPUT_S || opc->outputs==OUTPUT_V) { ParseMaskedDstReg(token,insn); + } else if(opc->outputs==OUTPUT_NONE) { + SetNoneDestReg(insn); } if(opc->outputs!=OUTPUT_NONE && opc->inputs!=INPUT_NONE) { @@ -289,20 +294,14 @@ void CFPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char * token = SkipSpaces(strtok(NULL,",")); ParseScalarSrc(token,&insn->src[1]); } else if(opc->inputs==INPUT_1V_T) { - u8 unit,target; - ParseVectorSrc(token,&insn->src[0]); token = SkipSpaces(strtok(NULL,",")); - ParseTextureUnit(token,&unit); + ParseTextureUnit(token,&insn->tex_unit); token = SkipSpaces(strtok(NULL,",")); - ParseTextureTarget(token,&target); - - insn->unit = unit; + ParseTextureTarget(token,&insn->tex_target); } else if(opc->inputs==INPUT_3V_T) { - u8 unit,target; - ParseVectorSrc(token,&insn->src[0]); token = SkipSpaces(strtok(NULL,",")); @@ -312,12 +311,10 @@ void CFPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char * ParseVectorSrc(token,&insn->src[2]); token = SkipSpaces(strtok(NULL,",")); - ParseTextureUnit(token,&unit); + ParseTextureUnit(token,&insn->tex_unit); token = SkipSpaces(strtok(NULL,",")); - ParseTextureTarget(token,&target); - - insn->unit = unit; + ParseTextureTarget(token,&insn->tex_target); } else if(opc->inputs==INPUT_CC) { ParseCond(token,insn); } @@ -325,7 +322,6 @@ void CFPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char * opcode CFPParser::FindOpcode(const char *mnemonic) { - const struct _opcode *inst; struct _opcode result; result.name = NULL; @@ -334,7 +330,8 @@ opcode CFPParser::FindOpcode(const char *mnemonic) result.outputs = 0; result.suffixes = 0; - for(inst=fp_opcodes;inst->name;inst++) { + for(size_t i=0;iname,strlen(inst->name))==0) { int i = strlen(inst->name); @@ -401,22 +398,23 @@ s32 CFPParser::ConvertInputReg(const char *token) void CFPParser::ParseOutput(const char *param_str) { oparam p; + u8 is_fp16 = 0; s32 reg = -1; - char *token = SkipSpaces(strtok((char*)param_str," =")); - char *name = SkipSpaces(strtok(NULL,"=\0")); + const char *param = SkipSpaces(strstr(param_str, "OUTPUT") + 6); + const char *token = SkipSpaces(strtok((char*)param," =")); + const char *name = SkipSpaces(strtok(NULL,"=\0")); - ParseOutputReg(name,®); + ParseOutputReg(name,®,&is_fp16); p.alias = token; p.index = reg; + p.is_fp16 = (strncmp(param_str, "SHORT", 5) == 0) || is_fp16; m_lOParameters.push_back(p); } -const char* CFPParser::ParseOutputReg(const char *token, s32 *reg) +const char* CFPParser::ParseOutputReg(const char *token, s32 *reg,u8 *is_fp16) { - u32 i; - if(isdigit(*token)) { char *p = (char*)token; while(isdigit(*p)) p++; @@ -426,10 +424,25 @@ const char* CFPParser::ParseOutputReg(const char *token, s32 *reg) return (token + (p - token)); } - for(i=0;i::iterator it = m_lOParameters.begin(); + *is_fp16 = 0; + for(;it!=m_lOParameters.end();it++) { if(strncmp(token,it->alias.c_str(),it->alias.size())==0) { *reg = it->index; + *is_fp16 = it->is_fp16; return (token + it->alias.size()); } } - return NULL; + return ParseOutputReg(token,reg,is_fp16); } void CFPParser::ParseMaskedDstReg(const char *token,struct nvfx_insn *insn) { s32 idx; + u8 is_fp16 = 0; if(!token) return; if(strncmp(token,"RC",2)==0 || strncmp(token,"HC",2)==0) { - insn->dst.type = NVFXSR_NONE; - insn->dst.is_fp16 = (token[0]=='H'); - insn->dst.index = 0x3f; - + SetNoneDestReg(insn); token += 2; } else if(token[0]=='R' || token[0]=='H') { insn->dst.type = NVFXSR_TEMP; insn->dst.is_fp16 = (token[0]=='H'); token = ParseTempReg(token,&insn->dst.index); } else if(token[0]=='o' && token[1]=='[') { - token = ParseOutputReg(&token[2],&idx); + token = ParseOutputReg(&token[2],&idx,&is_fp16); token++; insn->dst.type = NVFXSR_OUTPUT; insn->dst.index = idx; + insn->dst.is_fp16 = is_fp16; } else { - token = ParseOutputRegAlias(token,&idx); + token = ParseOutputRegAlias(token,&idx,&is_fp16); insn->dst.type = NVFXSR_OUTPUT; insn->dst.index = idx; @@ -569,10 +551,9 @@ void CFPParser::ParseVectorSrc(const char *token,struct nvfx_src *reg) } if(token[0]=='R' || token[0]=='H') { - token = ParseTempReg(token,&idx); - reg->reg.type = NVFXSR_TEMP; - reg->reg.index = idx; + reg->reg.is_fp16 = (token[0]=='H'); + token = ParseTempReg(token,®->reg.index); } else if(token[0]=='f') { if(token[1]=='[') { token = ParseInputReg(&token[2],&idx); @@ -693,3 +674,28 @@ const char* CFPParser::ParseOutputMask(const char *token,u8 *mask) } return token; } + +void CFPParser::SetNoneDestReg(struct nvfx_insn *insn) +{ + insn->dst.type = NVFXSR_NONE; + insn->dst.index = 0x3f; + insn->dst.is_fp16 = 0; //always treat as fp32 (on RSX there's only RC) +} + +u8 CFPParser::IsPCDisablingInstruction(struct nvfx_insn *insn) +{ + switch(insn->op) { + case OPCODE_DP2: + case OPCODE_DP2A: + case OPCODE_DP3: + case OPCODE_DP4: + case OPCODE_MUL: + case OPCODE_DIV: + case OPCODE_NRM3: + return 1; + case OPCODE_TEX: + if(insn->tex_target == PARAM_SAMPLERCUBE) return 1; + default: + return 0; + } +} diff --git a/tools/cgcomp/source/main.cpp b/tools/cgcomp/source/main.cpp index 6aae360d..32a12555 100644 --- a/tools/cgcomp/source/main.cpp +++ b/tools/cgcomp/source/main.cpp @@ -1,7 +1,7 @@ #include "types.h" #include "fpparser.h" #include "vpparser.h" -#include "compiler.h" +#include "compilervp.h" #include "compilerfp.h" #ifdef __CYGWIN__ @@ -33,16 +33,21 @@ struct _options const char *dst_file; const char *entry; int prog_type; + int profile; bool gen_asm; bool compile; bool strip; + bool dump_asm; + std::vector cg_args; } Options = { NULL, NULL, "main", PROG_TYPE_NONE, + -1, false, true, + false, false }; @@ -52,6 +57,8 @@ struct _options #define CG_PROFILE_FP30 6149 #define CG_PROFILE_FP40 6151 #define CG_PROFILE_VP40 7001 +#define CG_PROFILE_GP4FP 7010 +#define CG_PROFILE_GP4VP 7011 typedef void*(*_cgCreateContext)(); typedef void(*_cgDestroyContext)(void *context); @@ -65,6 +72,9 @@ _cgCreateProgramFromFile cgCreateProgramFromFile=NULL; _cgGetProgramString cgGetProgramString=NULL; _cgGetLastListing cgGetLastListing=NULL; +static const char *cgDefArgs[] = { "-O3", "-bestprecision", "-unroll", "count=4", "-ifcvt", "all", NULL }; +static size_t numCgDefArgs = sizeof(cgDefArgs)/sizeof(char*); + static bool InitCompiler() { #if defined(WIN32) @@ -102,9 +112,13 @@ static u32 endian_fp(u32 v) void usage() { - printf("cgcomp [options] input output\n"); - printf("\t-f Input is fragment program\n"); - printf("\t-v Input is vertex program\n"); + fprintf(stderr, "cgcomp [options] input output\n"); + fprintf(stderr, "\t-f Input is fragment program\n"); + fprintf(stderr, "\t-v Input is vertex program\n"); + fprintf(stderr, "\t-d Dump assembly to file (.asm)\n"); + fprintf(stderr, "\t-e Specify entry point function\n"); + fprintf(stderr, "\t-a Compile from assembly input file\n"); + fprintf(stderr, "\t-Wcg, Additional arguments passed to the cg compiler frontend\n"); } void readoptions(struct _options *options,int argc,char *argv[]) @@ -118,6 +132,15 @@ void readoptions(struct _options *options,int argc,char *argv[]) case 'v': options->prog_type = PROG_TYPE_VP; break; case 'e': options->entry = argv[++i]; break; case 'a': options->gen_asm = true; break; + case 'd': options->dump_asm = true; break; + case 'W': + { + char *cg_arg = &argv[i][2]; + + if(cg_arg[0] == 'c' && cg_arg[1] == 'g' && cg_arg[2] == ',') + options->cg_args.push_back(&cg_arg[3]); + } + break; } } else break; @@ -172,6 +195,28 @@ char* readfile(const char *filename) return prg; } +void* createProgram(void *context, int profile) +{ + int argc; + char **argv; + int numArgs; + + numArgs = numCgDefArgs + Options.cg_args.size(); + argv = new char*[numArgs]; + + memset(argv, 0, numArgs); + + argc = 0; + for(u32 i=0;i < numCgDefArgs && cgDefArgs[i];i++) { + argv[argc++] = strdup(cgDefArgs[i]); + } + for(u32 i=0;i < Options.cg_args.size();i++) { + argv[argc++] = strdup(Options.cg_args[i].c_str()); + } + + return cgCreateProgramFromFile(context, CG_SOURCE, Options.src_file, profile, Options.entry, (const char**)argv); +} + int compileVP() { char *prg; @@ -182,7 +227,7 @@ int compileVP() prg = readfile(Options.src_file); } else { context = cgCreateContext(); - program = cgCreateProgramFromFile(context,CG_SOURCE,Options.src_file,CG_PROFILE_VP40,Options.entry,NULL); + program = createProgram(context, CG_PROFILE_VP40); if(program==NULL) { const char *error = cgGetLastListing(context); fprintf(stderr,"%s\n",error); @@ -193,7 +238,17 @@ int compileVP() if(prg) { CVPParser parser; - CCompiler compiler; + CCompilerVP compiler; + + if(Options.dump_asm) { + FILE *fDump = NULL; + std::string fname = Options.dst_file; + + fname.append(".dump"); + fDump = fopen(fname.c_str(),"wb"); + fwrite(prg,strlen(prg),1,fDump); + fclose(fDump); + } parser.Parse(prg); compiler.Compile(&parser); @@ -225,8 +280,9 @@ int compileVP() rsxVertexProgram *vp = (rsxVertexProgram*)vertexprogram; vp->magic = SWAP16(magic); - vp->start_insn = SWAP16(0); + vp->insn_start = SWAP16(0); vp->const_start = SWAP16(0); + vp->num_regs = SWAP16(compiler.GetNumRegs()); vp->input_mask = SWAP32(compiler.GetInputMask()); vp->output_mask = SWAP32(compiler.GetOutputMask()); @@ -235,7 +291,7 @@ int compileVP() rsxProgramAttrib *attribs = (rsxProgramAttrib*)(vertexprogram + lastoff); - vp->attrib_off = SWAP32(lastoff); + vp->attr_off = SWAP32(lastoff); n = 0; std::list params = parser.GetParameters(); @@ -248,7 +304,7 @@ int compileVP() n++; } } - vp->num_attrib = SWAP16(n); + vp->num_attr = SWAP16(n); lastoff += (n*sizeof(rsxProgramAttrib)); while(lastoff&3) @@ -332,7 +388,7 @@ int compileFP() prg = readfile(Options.src_file); } else { context = cgCreateContext(); - program = cgCreateProgramFromFile(context,CG_SOURCE,Options.src_file,CG_PROFILE_FP40,Options.entry,NULL); + program = createProgram(context, CG_PROFILE_FP40); if(program==NULL) { const char *error = cgGetLastListing(context); fprintf(stderr,"%s\n",error); @@ -345,6 +401,16 @@ int compileFP() CFPParser parser; CCompilerFP compiler; + if(Options.dump_asm) { + FILE *fDump = NULL; + std::string fname = Options.dst_file; + + fname.append(".dump"); + fDump = fopen(fname.c_str(),"wb"); + fwrite(prg,strlen(prg),1,fDump); + fclose(fDump); + } + parser.Parse(prg); compiler.Compile(&parser); @@ -356,7 +422,7 @@ int compileFP() rsxFragmentProgram *fp = (rsxFragmentProgram*)fragmentprogram; fp->magic = SWAP16(magic); - fp->num_regs = SWAP32(compiler.GetNumRegs()); + fp->num_regs = SWAP16(compiler.GetNumRegs()); fp->fp_control = SWAP32(compiler.GetFPControl()); fp->texcoords = SWAP16(compiler.GetTexcoords()); fp->texcoord2D = SWAP16(compiler.GetTexcoord2D()); @@ -365,7 +431,7 @@ int compileFP() while(lastoff&3) fragmentprogram[lastoff++] = 0; - fp->attrib_off = SWAP32(lastoff); + fp->attr_off = SWAP32(lastoff); rsxProgramAttrib *attribs = (rsxProgramAttrib*)(fragmentprogram + lastoff); n = 0; @@ -379,7 +445,7 @@ int compileFP() n++; } } - fp->num_attrib = SWAP16(n); + fp->num_attr = SWAP16(n); lastoff += (n*sizeof(rsxProgramAttrib)); while(lastoff&3) diff --git a/tools/cgcomp/source/parser.cpp b/tools/cgcomp/source/parser.cpp index 1f6d87c8..0be1320b 100644 --- a/tools/cgcomp/source/parser.cpp +++ b/tools/cgcomp/source/parser.cpp @@ -8,17 +8,21 @@ static paramtype paramtypes[] = { { "float", PARAM_FLOAT }, + { "float1", PARAM_FLOAT1 }, { "float2", PARAM_FLOAT2 }, { "float3", PARAM_FLOAT3 }, { "float4", PARAM_FLOAT4 }, + { "float3x4", PARAM_FLOAT3x4 }, { "float4x4", PARAM_FLOAT4x4 }, + { "float3x3", PARAM_FLOAT3x3 }, + { "float4x3", PARAM_FLOAT4x3 }, { "sampler1D", PARAM_SAMPLER1D }, { "sampler2D", PARAM_SAMPLER2D }, { "sampler3D", PARAM_SAMPLER3D }, { "samplerCUBE", PARAM_SAMPLERCUBE }, { "samplerRECT", PARAM_SAMPLERRECT }, }; -static const u32 PARAM_TYPE_CNT = sizeof(paramtypes)/sizeof(struct _paramtype); +static const size_t PARAM_TYPE_CNT = sizeof(paramtypes)/sizeof(struct _paramtype); CParser::CParser() { @@ -40,37 +44,42 @@ void CParser::ParseComment(const char *line) line++; if(strncasecmp(line,"var",3)==0) { - char *token = SkipSpaces(strtok((char*)(line+3)," :")); + const char *token = SkipSpaces(strtok((char*)(line+3)," :")); p.type = GetParamType(token); p.is_const = 0; p.is_internal = 0; p.count = 1; p.name = SkipSpaces(strtok(NULL," :")); +next: token = SkipSpaces(strtok(NULL," :")); - if(strstr(token,"$vin")) { - token = SkipSpaces(strtok(NULL," :")); - if(strncasecmp(token,"ATTR",4)==0) - p.index = atoi(token+4); - else - p.index = ConvertInputReg(token); - } else if(strstr(token,"texunit")) { - token = SkipSpaces(strtok(NULL," :")); - p.index = atoi(token); - } else if(token[0]=='c') { - p.is_const = 1; - p.index = atoi(token+2); - - token = strtok(NULL," ,"); - if(isdigit(*token)) p.count = atoi(token); + if (token) { + if(strstr(token,"$vin")) { + token = SkipSpaces(strtok(NULL," :")); + if(strncasecmp(token,"ATTR",4)==0) + p.index = atoi(token+4); + else + p.index = ConvertInputReg(token); + } else if(strstr(token,"texunit")) { + token = SkipSpaces(strtok(NULL," :")); + p.index = atoi(token); + } else if(token[0]=='c') { + p.is_const = 1; + p.index = atoi(token+2); + + token = strtok(NULL," ,"); + if(isdigit(*token)) p.count = atoi(token); + } else + goto next; } else return; - InitParameter(&p); - - m_lParameters.push_back(p); + if(p.index>-1) { + InitParameter(&p); + m_lParameters.push_back(p); + } } else if(strncasecmp(line,"const",5)==0) { - char *token = SkipSpaces(strtok((char*)(line+5)," ")); + const char *token = SkipSpaces(strtok((char*)(line+5)," ")); p.is_const = 1; p.is_internal = 1; @@ -106,10 +115,13 @@ void CParser::InitParameter(param *p) switch(p->type) { case PARAM_FLOAT4x4: - p->values[0][0] = 1.0f; - p->values[1][1] = 1.0f; - p->values[2][2] = 1.0f; p->values[3][3] = 1.0f; + case PARAM_FLOAT4x3: + case PARAM_FLOAT3x3: + case PARAM_FLOAT3x4: + p->values[2][2] = 1.0f; + p->values[1][1] = 1.0f; + p->values[0][0] = 1.0f; break; default: break; @@ -150,7 +162,8 @@ void CParser::InitInstruction(struct nvfx_insn *insn,u8 op) { insn->op = op; insn->scale = 0; - insn->unit = -1; + insn->tex_unit = -1; + insn->tex_target = -1; insn->precision = FLOAT32; insn->mask = NVFX_VP_MASK_ALL; insn->cc_swz[0] = 0; insn->cc_swz[1] = 1; insn->cc_swz[2] = 2; insn->cc_swz[3] = 3; @@ -160,6 +173,7 @@ void CParser::InitInstruction(struct nvfx_insn *insn,u8 op) insn->cc_cond = NVFX_COND_TR; insn->cc_test = 0; insn->cc_test_reg = 0; + insn->disable_pc = 0; insn->dst = nvfx_reg(NVFXSR_NONE,0); insn->src[0] = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); insn->src[1] = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); insn->src[2] = nvfx_src(nvfx_reg(NVFXSR_NONE,0)); } @@ -181,10 +195,8 @@ bool CParser::isWhitespace(int c) s32 CParser::GetParamType(const char *param_str) { - u32 i; - - for(i=0;i::iterator i=m_lIdent.begin();i!=m_lIdent.end();i++) { - if(strcmp(r->ident,i->ident)==0) { + if(strcmp(r->ident.c_str(),i->ident.c_str())==0) { found = true; m_pInstructions[r->location].dst = nvfx_reg(NVFXSR_RELOCATED,i->location); break; @@ -276,7 +278,7 @@ int CVPParser::Parse(const char *str) } if(found==false) { - fprintf(stderr,"Identifier \'%s\' not found.\n",r->ident); + fprintf(stderr,"Identifier \'%s\' not found.\n",r->ident.c_str()); exit(EXIT_FAILURE); } } @@ -287,7 +289,7 @@ int CVPParser::Parse(const char *str) void CVPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char *param_str) { u32 i; - char *token = SkipSpaces(strtok((char*)param_str,",")); + const char *token = SkipSpaces(strtok((char*)param_str,",")); if(opc->is_imm) ParseMaskedDstAddr(token,insn); @@ -296,7 +298,7 @@ void CVPParser::ParseInstruction(struct nvfx_insn *insn,opcode *opc,const char * for(i=0;inr_src;i++) { token = SkipSpaces(strtok(NULL,",")); - ParseSwizzledSrcReg(token,&insn->src[opc->src_slots[i]]); + ParseSwizzledSrcReg(token,insn,opc->src_slots[i]); } } @@ -306,12 +308,13 @@ void CVPParser::ParseMaskedDstReg(const char *token,struct nvfx_insn *insn) if(!token) return; - if(token[0]=='R') { - if(token[1]=='C') return; - - token = ParseTempReg(token,&idx); - insn->dst.type = NVFXSR_TEMP; - insn->dst.index = idx; + if(token[0]=='R' || token[0]=='H') { + if(token[1]=='C') token += 2; + else { + token = ParseTempReg(token,&idx); + insn->dst.type = NVFXSR_TEMP; + insn->dst.index = idx; + } } else if(token[0]=='r' && token[1]=='e') { token = ParseOutputReg(token,&idx); insn->dst.type = NVFXSR_OUTPUT; @@ -320,17 +323,19 @@ void CVPParser::ParseMaskedDstReg(const char *token,struct nvfx_insn *insn) token = ParseOutputReg(&token[2],&idx); insn->dst.type = NVFXSR_OUTPUT; insn->dst.index = idx; + } else if(token[0]=='A' && (token[1]=='0' || token[1]=='1')) { + token = ParseOutputReg(&token[1],&idx); + insn->dst.type = NVFXSR_ADDRESS; + insn->dst.index = idx; } else if(token[0]=='C' && token[1]=='C') - return; + token += 2; ParseMaskedDstRegExt(token,insn); } opcode* CVPParser::FindOpcode(const char *mnemonic) { - u32 i; - - for(i=0;isrc[slot]; if(!token) return; @@ -380,6 +383,13 @@ void CVPParser::ParseSwizzledSrcReg(const char *token,struct nvfx_src *reg) reg->reg.type = NVFXSR_INPUT; reg->reg.index = idx; + } else if(!strncmp(token,"texture[",8)) { + ParseTextureUnit(token,&insn->tex_unit); + token = SkipSpaces(strtok(NULL,",")); + ParseTextureTarget(token,&insn->tex_target); + + reg->reg.type = NVFXSR_SAMPLER; + reg->reg.index = insn->tex_unit; } else if(token[0]=='R') { token = ParseTempReg(token,&idx); reg->reg.type = NVFXSR_TEMP; @@ -396,7 +406,7 @@ const char* CVPParser::ParseParamReg(const char *token,struct nvfx_src *reg) { if(!token) return NULL; - char *p = (char*)token; + const char *p = token; if(isdigit(*p)) { reg->reg.type = NVFXSR_CONST; @@ -429,9 +439,12 @@ const char* CVPParser::ParseParamReg(const char *token,struct nvfx_src *reg) } p += k; } + + p = SkipSpaces(p); if(*p=='-' || *p=='+') { const char sign = *p++; + p = SkipSpaces(p); if(isdigit(*p)) { const s32 k = atoi(p); if(sign=='-') { @@ -484,8 +497,6 @@ s32 CVPParser::ConvertInputReg(const char *token) const char* CVPParser::ParseOutputReg(const char *token,s32 *reg) { - u32 i; - if(isdigit(*token)) { char *p = (char*)token; while(isdigit(*p)) p++; @@ -495,12 +506,12 @@ const char* CVPParser::ParseOutputReg(const char *token,s32 *reg) return (token + (p - token)); } - for(i=0;i /dev/null || 10.4) + OSXCFLAGS := -mmacosx-version-min=$(OSX_MIN) + OSXCXXFLAGS := $(OSXCFLAGS) + CXXFLAGS += -fvisibility=hidden + CFLAGS += -I/usr/local/include + LDFLAGS += -mmacosx-version-min=$(OSX_MIN) -Wl,-syslibroot,$(SDK) -L/opt/local/lib -lz +endif + +ifneq (,$(findstring BSD,$(UNAME))) + CFLAGS += -I/usr/local/include + LDFLAGS += -L/usr/local/lib -lz +endif + +ifneq (,$(findstring SunOS,$(UNAME))) + CFLAGS += -I/opt/csw/include + LDFLAGS += -L/opt/csw/lib -R/opt/csw/lib -lz +endif + +ifneq (,$(findstring Linux,$(UNAME))) + LDFLAGS += -lz + OS := Linux +endif + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project +#--------------------------------------------------------------------------------- +LIBS := +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + + +export OUTPUT := $(CURDIR)/$(TARGET)$(EXEEXT) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) + +export CC := gcc +export CXX := g++ +export AR := ar +export OBJCOPY := objcopy + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) + +export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT) + +#--------------------------------------------------------------------------------- +install: $(BUILD) + @echo Installing $(TARGET)$(EXEEXT) + @[ -d $(PS3DEV)/bin ] || mkdir -p $(PS3DEV)/bin + @install -m 755 $(OUTPUT) $(PS3DEV)/bin + +#--------------------------------------------------------------------------------- +run: + $(OUTPUT) + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + @echo linking ... $(notdir $@) + @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ + +#--------------------------------------------------------------------------------- +# Compile Targets for C/C++ +#--------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------- +%.o : %.cpp + @echo $(notdir $<) + @$(CXX) -E -MMD $(CFLAGS) $< > /dev/null + @$(CXX) $(OSXCXXFLAGS) $(CFLAGS) -o $@ -c $< + +#--------------------------------------------------------------------------------- +%.o : %.c + @echo $(notdir $<) + @$(CC) -E -MMD $(CFLAGS) $< > /dev/null + @$(CC) $(OSXCFLAGS) $(CFLAGS) -o $@ -c $< + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/tools/fself/include/common.h b/tools/fself/include/common.h new file mode 100644 index 00000000..450ce74b --- /dev/null +++ b/tools/fself/include/common.h @@ -0,0 +1,53 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include + +#ifdef WIN32 +#include +#include +#else +#include +#endif + +#include "types.h" + +#ifdef WIN32 +#define MKDIR(x,y) mkdir(x) +#else +#define MKDIR(x,y) mkdir(x,y) +#endif + +#ifdef __BIG_ENDIAN__ +#define swap16(x) (x) +#define swap32(x) (x) +#define swap64(x) (x) +#else +#define swap16(x) ((((uint16_t)(x) & 0xff00) >> 8) | \ + (((uint16_t)(x) & 0x00ff) << 8)) +#define swap32(x) ((((uint32_t)(x) & 0xff000000) >> 24) | \ + (((uint32_t)(x) & 0x00ff0000) >> 8) | \ + (((uint32_t)(x) & 0x0000ff00) << 8) | \ + (((uint32_t)(x) & 0x000000ff) << 24)) +#define swap64(x) \ + ((((uint64_t)(x) & 0xff00000000000000ull) >> 56) | \ + ((uint64_t)((x) & 0x00ff000000000000ull) >> 40) | \ + ((uint64_t)((x) & 0x0000ff0000000000ull) >> 24) | \ + ((uint64_t)((x) & 0x000000ff00000000ull) >> 8) | \ + ((uint64_t)((x) & 0x00000000ff000000ull) << 8) | \ + ((uint64_t)((x) & 0x0000000000ff0000ull) << 24) | \ + ((uint64_t)((x) & 0x000000000000ff00ull) << 40) | \ + ((uint64_t)((x) & 0x00000000000000ffull) << 56)) +#endif + +#define align(x,y) (((x) + ((y) - 1)) & ~((y - 1))) + +#define error_done(err, msg) do { \ + fprintf(stderr,msg); \ + exit (err); \ + } while(0) + +#endif diff --git a/tools/fself/include/self.h b/tools/fself/include/self.h new file mode 100644 index 00000000..6eb683fb --- /dev/null +++ b/tools/fself/include/self.h @@ -0,0 +1,159 @@ +#ifndef __SELF_H__ +#define __SELF_H__ + +#include "common.h" +#include "tools.h" + +#define SCE_MAGIC 0x53434500 + +typedef struct { + uint32_t magic; + uint32_t version; + uint16_t flags; + uint16_t type; + uint32_t metadata_offset; + uint64_t header_len; + uint64_t elf_filesize; + uint64_t unknown; + uint64_t appinfo_offset; + uint64_t elf_offset; + uint64_t phdr_offset; + uint64_t shdr_offset; + uint64_t section_info_offset; + uint64_t sceversion_offset; + uint64_t controlinfo_offset; + uint64_t controlinfo_size; + uint64_t padding; +} __attribute__((packed)) SELF; + +typedef struct { + uint64_t authid; + uint32_t vendor_id; + uint32_t self_type; + uint32_t version; + uint8_t padding[12]; +} __attribute__((packed)) APP_INFO; + +typedef struct { + uint64_t offset; + uint64_t size; + uint32_t compressed; // 2=compressed + uint32_t unknown1; + uint32_t unknown2; + uint32_t encrypted; // 1=encrypted +} __attribute__((packed)) SECTION_INFO; + +typedef struct { + uint32_t unknown1; + uint32_t unknown2; + uint32_t size; + uint32_t unknown3; + uint16_t section_idx; + uint16_t unknown4; + uint32_t unknown5; + uint32_t unknown6; + uint32_t unknown7; + uint64_t offset; + uint64_t str_size; +} __attribute__((packed)) SCEVERSION_INFO; + +typedef struct { + uint32_t type; // 1==control flags; 2==file digest; 3==npdrm header + uint32_t size; + uint64_t cont_flag; // 1==next block; 0==end block + union { + // type 1 + struct { + uint32_t control_flags[8]; + } control_flags; + + // type 2 + struct { + uint8_t digest1[20]; + uint8_t digest2[20]; + uint8_t padding[8]; + } file_digest; + + struct { + uint32_t data[32]; + } npdrm; + }; +} __attribute__((packed)) CONTROL_INFO; + +typedef struct { + //uint8_t ignore[32]; + uint8_t key[16]; + uint8_t key_pad[16]; + uint8_t iv[16]; + uint8_t iv_pad[16]; +} __attribute__((packed)) METADATA_INFO; + +typedef struct { + uint64_t signature_input_length; + uint32_t unknown1; + uint32_t section_count; + uint32_t key_count; + uint32_t signature_info_size; + uint64_t unknown2; +} __attribute__((packed)) METADATA_HEADER; + +typedef struct { + uint64_t data_offset; + uint64_t data_size; + uint32_t type; // 1 = shdr, 2 == phdr + uint32_t program_idx; + uint32_t unknown; + uint32_t sha1_idx; + uint32_t encrypted; // 3=yes; 1=no + uint32_t key_idx; + uint32_t iv_idx; + uint32_t compressed; // 2=yes; 1=no +} __attribute__((packed)) METADATA_SECTION_HEADER; + +typedef struct { + uint8_t sha1[20]; + uint8_t padding[12]; + uint8_t hmac_key[64]; +} __attribute__((packed)) SECTION_HASH; + +typedef struct { + uint32_t unknown1; + uint32_t signature_size; + uint64_t unknown2; + uint64_t unknown3; + uint64_t unknown4; + uint64_t unknown5; + uint32_t unknown6; + uint32_t unknown7; +} __attribute__((packed)) SIGNATURE_INFO; + +typedef struct { + uint8_t r[21]; + uint8_t s[21]; + uint8_t padding[6]; +} __attribute__((packed)) SIGNATURE; + + +typedef struct { + uint8_t *data; + uint64_t size; + uint64_t offset; +} SELF_SECTION; + +void self_read_headers(FILE *in,SELF *self,APP_INFO *app_info,ELF *elf,ELF_PHDR **phdr, ELF_SHDR **shdr, SECTION_INFO **section_info,SCEVERSION_INFO *sceversion_info,CONTROL_INFO **control_info); + +void self_write_self_header(char *self_data,uint64_t offset,SELF *in); +void self_write_appinfo_header(char *self_data,uint64_t offset,APP_INFO *in); +void self_write_elf_header(char *self_data,uint64_t offset,ELF *in); +void self_write_phdr_header(char *self_data,uint64_t offset,ELF *elf_hdr,ELF_PHDR *in); +void self_write_sectioninfo_header(char *self_data,uint64_t offset,ELF *elf_hdr,SECTION_INFO *in); +void self_write_sceversion_header(char *self_data,uint64_t offset,SCEVERSION_INFO *in); +void self_write_control_info_header(char *self_data,uint64_t offset,CONTROL_INFO *in,int npdrm); + +void self_build_app_info_header(APP_INFO *app_info,int npdrm); +void self_build_sceversion_header(SCEVERSION_INFO *info,const void *elf_data,uint64_t elfOffset); +void self_build_controlinfo_header(CONTROL_INFO **control_info,int *info_len,const void *elf_data,int elf_len,int npdrm); +void self_build_self_header(SELF *self,ELF *elf_hdr,uint64_t *headerEnd,uint64_t *elfOffset,int elf_filesize,int ctrl_info_size,int npdrm); +void self_build_elf_section_info_headers(ELF *elf_hdr,ELF_PHDR **phdrs,ELF_SHDR **shdrs,SECTION_INFO **sec_info,const void *elf_data,uint64_t elfOffset); + +#endif diff --git a/tools/fself/include/sha1.h b/tools/fself/include/sha1.h new file mode 100644 index 00000000..b355d228 --- /dev/null +++ b/tools/fself/include/sha1.h @@ -0,0 +1,72 @@ +/* + * sha1.h + * + * Copyright (C) 1998 + * Paul E. Jones + * All Rights Reserved + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + ***************************************************************************** + * $Id: sha1.h,v 1.2 2004/03/27 18:00:33 paulej Exp $ + ***************************************************************************** + * + * Description: + * This class implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * Many of the variable names in the SHA1Context, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +/* + * This structure will hold context information for the hashing + * operation + */ +typedef struct SHA1Context +{ + unsigned Message_Digest[5]; /* Message Digest (output) */ + + unsigned Length_Low; /* Message length in bits */ + unsigned Length_High; /* Message length in bits */ + + unsigned char Message_Block[64]; /* 512-bit message blocks */ + int Message_Block_Index; /* Index into message block array */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corruped? */ +} SHA1Context; + +/* + * Function Prototypes + */ +void SHA1Reset(SHA1Context *); +int SHA1Result(SHA1Context *); +void SHA1Input( SHA1Context *, + const unsigned char *, + unsigned); + +#endif diff --git a/tools/fself/include/tools.h b/tools/fself/include/tools.h new file mode 100644 index 00000000..c9250440 --- /dev/null +++ b/tools/fself/include/tools.h @@ -0,0 +1,63 @@ +#ifndef __TOOLS_H__ +#define __TOOLS_H__ + +#include "common.h" + +typedef struct { + uint8_t ident[16]; + uint16_t type; + uint16_t machine; + uint32_t version; + uint64_t entry_point; + uint64_t phdr_offset; + uint64_t shdr_offset; + uint16_t flags; + uint32_t header_size; + uint16_t phent_size; + uint16_t phnum; + uint16_t shent_size; + uint16_t shnum; + uint16_t shstrndx; +} __attribute__((packed)) ELF; + +typedef struct { + uint32_t type; + uint32_t flags; + uint64_t offset_in_file; + uint64_t vitual_addr; + uint64_t phys_addr; + uint64_t segment_size; + uint64_t segment_mem_size; + uint64_t alignment; +} __attribute__((packed)) ELF_PHDR; + +typedef struct { + uint32_t name_idx; + uint32_t type; + uint64_t flags; + uint64_t virtual_addr; + uint64_t offset_in_file; + uint64_t segment_size; + uint32_t link; + uint32_t info; + uint64_t addr_align; + uint64_t entry_size; +} __attribute__((packed)) ELF_SHDR; + +void elf_read_elf_header(const void *elf_data,ELF *elf_hdr); +void elf_read_phdr_header(const void *elf_data,ELF *elf_hdr,ELF_PHDR **elf_phdr); +void elf_read_shdr_header(const void *elf_data,ELF *elf_hdr,ELF_SHDR **elf_shdr); +int elf_get_shstr_idx(const void *elf_data,const char *section_name); +uint64_t elf_get_shstr_off(const void *elf_data,const char *section_name); + +void elf_write_elf_header(void *elf_data,ELF *elf_hdr); +void elf_write_phdr_header(void *elf_data,ELF *elf_hdr,ELF_PHDR *phdr); + +void sha1(const void *data,uint32_t len,uint8_t *digest); +void sha1_hmac(const void *data,uint32_t len,uint8_t *key,uint8_t *digest); + +void get_rand(uint8_t *bfr,uint32_t size); + +void fail(const char *a, ...); + +#endif diff --git a/tools/fself/include/types.h b/tools/fself/include/types.h new file mode 100644 index 00000000..a7042d4d --- /dev/null +++ b/tools/fself/include/types.h @@ -0,0 +1,20 @@ +#ifndef __TYPES_H__ +#define __TYPES_H__ + +#if _MSC_VER>1300 +typedef signed char int8_t; +typedef unsigned char uint8_t; + +typedef signed short int16_t; +typedef unsigned short uint16_t; + +typedef signed int int32_t; +typedef unsigned int uint32_t; + +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#endif diff --git a/tools/fself/source/main.c b/tools/fself/source/main.c new file mode 100644 index 00000000..dcb0eaff --- /dev/null +++ b/tools/fself/source/main.c @@ -0,0 +1,94 @@ +#include "self.h" + +void usage() +{ + printf("fself [options] input.elf output.self\n"); + printf("If output is not specified, fself will default to EBOOT.BIN\n"); + printf("Options:\n"); + printf("\t-n create npdrm self, to be used with pkg.py\n"); +} + +int main(int argc,char *argv[]) +{ + int j,i,npdrm; + FILE *f = NULL; + ELF elf_header; + SELF self_header; + APP_INFO app_info; + ELF_PHDR *elf_phdr; + ELF_SHDR *elf_shdr; + SECTION_INFO *sec_info; + SCEVERSION_INFO sceversion_info; + CONTROL_INFO *control_info = NULL; + char *iofile[] = { NULL, "EBOOT.BIN" }; + + if(argc<2) usage(); + + npdrm = 0; + for(i=1;imagic = swap32 (self->magic); + self->version = swap32 (self->version); + self->flags = swap16 (self->flags); + self->type = swap16 (self->type); + self->metadata_offset = swap32 (self->metadata_offset); + self->header_len = swap64 (self->header_len); + self->elf_filesize = swap64 (self->elf_filesize); + self->appinfo_offset = swap64 (self->appinfo_offset); + self->elf_offset = swap64 (self->elf_offset); + self->phdr_offset = swap64 (self->phdr_offset); + self->shdr_offset = swap64 (self->shdr_offset); + self->section_info_offset = swap64 (self->section_info_offset); + self->sceversion_offset = swap64 (self->sceversion_offset); + self->controlinfo_offset = swap64 (self->controlinfo_offset); + self->controlinfo_size = swap64 (self->controlinfo_size); + + if (self->magic != SCE_MAGIC) { + fail("not a SELF\n"); + } + + // APP INFO + if (app_info) { + fseek (in, self->appinfo_offset, SEEK_SET); + if (fread (app_info, sizeof(APP_INFO), 1, in) != 1) { + fail("Couldn't read APP INFO header"); + } + app_info->authid = swap64 (app_info->authid); + app_info->vendor_id = swap32 (app_info->vendor_id); + app_info->self_type = swap32 (app_info->self_type); + app_info->version = swap32 (app_info->version); + } + + // ELF + if (elf) { + fseek (in, self->elf_offset, SEEK_SET); + if (fread (elf, sizeof(ELF), 1, in) != 1) { + fail("Couldn't read ELF header"); + } + elf->type = swap16 (elf->type); + elf->machine = swap16 (elf->machine); + elf->version = swap32 (elf->version); + elf->entry_point = swap64 (elf->entry_point); + elf->phdr_offset = swap64 (elf->phdr_offset); + elf->shdr_offset = swap64 (elf->shdr_offset); + elf->flags = swap16 (elf->flags); + elf->header_size = swap32 (elf->header_size); + elf->phent_size = swap16 (elf->phent_size); + elf->phnum = swap16 (elf->phnum); + elf->shent_size = swap16 (elf->shent_size); + elf->shnum = swap16 (elf->shnum); + elf->shstrndx = swap16 (elf->shstrndx); + } + + // PHDR and SECTION INFO + if (phdr || section_info) { + uint16_t phnum = 0; + uint16_t i; + + if (elf) { + phnum = elf->phnum; + } else { + fseek (in, self->elf_offset + 52, SEEK_SET); + fread (&phnum, sizeof(uint16_t), 1, in); + } + + if (phdr) { + ELF_PHDR *elf_phdr = NULL; + + elf_phdr = malloc (sizeof(ELF_PHDR) * phnum); + + fseek (in, self->phdr_offset, SEEK_SET); + if (fread (elf_phdr, sizeof(ELF_PHDR), phnum, in) != phnum) { + fail("Couldn't read ELF PHDR header"); + } + + for (i = 0; i < phnum; i++) { + elf_phdr[i].type = swap32 (elf_phdr[i].type); + elf_phdr[i].flags = swap32 (elf_phdr[i].flags); + elf_phdr[i].offset_in_file = swap64 (elf_phdr[i].offset_in_file); + elf_phdr[i].vitual_addr = swap64 (elf_phdr[i].vitual_addr); + elf_phdr[i].phys_addr = swap64 (elf_phdr[i].phys_addr); + elf_phdr[i].segment_size = swap64 (elf_phdr[i].segment_size); + elf_phdr[i].segment_mem_size = swap64 (elf_phdr[i].segment_mem_size); + elf_phdr[i].alignment = swap64 (elf_phdr[i].alignment); + } + + *phdr = elf_phdr; + } + + // SECTION INFO + if (section_info) { + SECTION_INFO *sections = NULL; + + sections = malloc (sizeof(SECTION_INFO) * phnum); + + fseek (in, self->section_info_offset, SEEK_SET); + if (fread (sections, sizeof(SECTION_INFO), phnum, in) != phnum) { + fail("Couldn't read SECTION INFO header"); + } + + for (i = 0; i < phnum; i++) { + sections[i].offset = swap64 (sections[i].offset); + sections[i].size = swap64 (sections[i].size); + sections[i].compressed = swap32 (sections[i].compressed); + sections[i].encrypted = swap32 (sections[i].encrypted); + } + + *section_info = sections; + } + } + + if (sceversion_info) { + fseek (in, self->sceversion_offset, SEEK_SET); + if (fread (sceversion_info, sizeof(SCEVERSION_INFO), 1, in) != 1) { + fail("Couldn't read SCE VERSION INFO header"); + } + sceversion_info->unknown1 = swap32(sceversion_info->unknown1); + sceversion_info->unknown2 = swap32(sceversion_info->unknown2); + sceversion_info->size = swap32(sceversion_info->size); + sceversion_info->unknown3 = swap32(sceversion_info->unknown3); + sceversion_info->section_idx = swap16(sceversion_info->section_idx); + sceversion_info->unknown4 = swap16(sceversion_info->unknown4); + sceversion_info->unknown5 = swap32(sceversion_info->unknown5); + sceversion_info->unknown6 = swap32(sceversion_info->unknown6); + sceversion_info->unknown7 = swap32(sceversion_info->unknown7); + sceversion_info->offset = swap64(sceversion_info->offset); + sceversion_info->str_size = swap64(sceversion_info->str_size); + } + + // CONTROL INFO + if (control_info) { + uint32_t i,offset = 0; + uint32_t index = 0; + CONTROL_INFO *info = NULL; + + while (offset < self->controlinfo_size) { + + info = realloc (info, sizeof(CONTROL_INFO) * (index + 1)); + + fseek (in, self->controlinfo_offset + offset, SEEK_SET); + + if (fread (info + index, sizeof(CONTROL_INFO), 1, in) != 1) { + fail("Couldn't read CONTROL INFO header"); + } + + info[index].type = swap32 (info[index].type); + info[index].size = swap32 (info[index].size); + info[index].cont_flag = swap64(info[index].cont_flag); + if (info[index].type == 1) { + for(i=0;i<8;i++) + info[index].control_flags.control_flags[i] = swap32(info[index].control_flags.control_flags[i]); + } + + offset += info[index].size; + index++; + } + *control_info = info; + } + + // SHDR + if (shdr) { + uint16_t shnum = 0; + uint16_t i; + ELF_SHDR *elf_shdr = NULL; + + if (elf) { + shnum = elf->shnum; + } else { + fseek (in, self->elf_offset + 56, SEEK_SET); + fread (&shnum, sizeof(uint16_t), 1, in); + } + + if (shnum > 0 && self->shdr_offset != 0) { + elf_shdr = malloc (sizeof(ELF_SHDR) * shnum); + + fseek (in, self->shdr_offset, SEEK_SET); + if (fread (elf_shdr, sizeof(ELF_SHDR), shnum, in) != shnum) { + fail("Couldn't read ELF SHDR header"); + } + + for (i = 0; i < shnum; i++) { + elf_shdr[i].name_idx = swap32 (elf_shdr[i].name_idx); + elf_shdr[i].type = swap32 (elf_shdr[i].type); + elf_shdr[i].flags = swap64 (elf_shdr[i].flags); + elf_shdr[i].virtual_addr = swap64 (elf_shdr[i].virtual_addr); + elf_shdr[i].offset_in_file = swap64 (elf_shdr[i].offset_in_file); + elf_shdr[i].segment_size = swap64 (elf_shdr[i].segment_size); + elf_shdr[i].link = swap32 (elf_shdr[i].link); + elf_shdr[i].info = swap32 (elf_shdr[i].info); + elf_shdr[i].addr_align = swap64 (elf_shdr[i].addr_align); + elf_shdr[i].entry_size = swap64 (elf_shdr[i].entry_size); + } + + *shdr = elf_shdr; + } + } +} + +void self_build_controlinfo_header(CONTROL_INFO **control_info,int *info_len,const void *elf_data,int elf_len,int npdrm) +{ + CONTROL_INFO *info = calloc((npdrm ? 3 : 2),sizeof(CONTROL_INFO)); + const char control_info_digest1[20] = { 0x62,0x7c,0xb1,0x80,0x8a,0xb9,0x38,0xe3,0x2c,0x8c,0x09,0x17,0x08,0x72,0x6a,0x57,0x9e,0x25,0x86,0xe4 }; + + info[0].type = 1; + info[0].size = 48; + info[0].cont_flag = 1; + + info[1].type = 2; + info[1].size = 64; + + memcpy(info[1].file_digest.digest1,control_info_digest1,20); + sha1(elf_data,elf_len,info[1].file_digest.digest2); + + if(npdrm) { + info[1].cont_flag = 1; + + info[2].type = 3; + info[2].size = 144; + } + + *control_info = info; + *info_len = 112 + (npdrm ? 144 : 0); +} + +void self_build_self_header(SELF *self,ELF *elf_hdr,uint64_t *headerEnd,uint64_t *elfOffset,int elf_filesize,int ctrl_info_size,int npdrm) +{ + memset(self,0,sizeof(SELF)); + + self->magic = SCE_MAGIC; + self->version = 2; + self->flags = 0x8000; + self->unknown = 3; + self->type = 1; + self->elf_filesize = elf_filesize; + self->appinfo_offset = align(sizeof(SELF),0x10); + self->elf_offset = align(self->appinfo_offset + sizeof(APP_INFO),0x10); + self->phdr_offset = self->elf_offset + sizeof(ELF); + self->section_info_offset = align(self->phdr_offset + (elf_hdr->phnum*sizeof(ELF_PHDR)),0x10); + self->sceversion_offset = align(self->section_info_offset + (elf_hdr->phnum*sizeof(SECTION_INFO)),0x10); + self->controlinfo_offset = align(self->sceversion_offset + sizeof(SCEVERSION_INFO),0x10); + self->controlinfo_size = ctrl_info_size; + + *headerEnd = self->controlinfo_offset + ctrl_info_size; + *elfOffset = align(*headerEnd + (npdrm ? 0x5c0 : 0x550),0x80); + + self->header_len = *elfOffset; + self->metadata_offset = (uint32_t)*headerEnd - 0x20; + self->shdr_offset = *elfOffset + elf_hdr->shdr_offset; +} + +void self_build_app_info_header(APP_INFO *app_info,int npdrm) +{ + memset(app_info,0,sizeof(APP_INFO)); + + app_info->authid = 0x1010000001000003ULL; + app_info->vendor_id = 0x01000002; + app_info->self_type = npdrm ? 0x08 : 0x04; + app_info->version = 0x00010000; +} + +void self_build_elf_section_info_headers(ELF *elf_hdr,ELF_PHDR **phdrs,ELF_SHDR **shdrs,SECTION_INFO **sec_info,const void *elf_data,uint64_t elfOffset) +{ + int i; + ELF_PHDR *phdr; + ELF_SHDR *shdr; + SECTION_INFO *secinfo; + + elf_read_phdr_header(elf_data,elf_hdr,&phdr); + elf_read_shdr_header(elf_data,elf_hdr,&shdr); + + secinfo = calloc(elf_hdr->phnum,sizeof(SECTION_INFO)); + + for(i=0;iphnum;i++) { + secinfo[i].offset = phdr[i].offset_in_file + elfOffset; + secinfo[i].size = phdr[i].segment_size; + secinfo[i].compressed = 1; + if(phdr[i].type==1) secinfo[i].encrypted = 2; + } + + *phdrs = phdr; + *shdrs = shdr; + *sec_info = secinfo; +} + +void self_build_sceversion_header(SCEVERSION_INFO *info,const void *elf_data,uint64_t elfOffset) +{ + int sce_idx = elf_get_shstr_idx(elf_data,".sceversion"); + uint64_t sce_off = elf_get_shstr_off(elf_data,".sceversion"); + + memset(info,0,sizeof(SCEVERSION_INFO)); + + info->unknown1 = 1; + info->unknown2 = 1; + info->size = sizeof(SCEVERSION_INFO); + info->section_idx = sce_idx; + info->unknown4 = 1; + info->unknown6 = 1; + info->offset = sce_off + elfOffset; + info->str_size = strlen((char*)elf_data + sce_off); +} + +void self_write_self_header(char *self_data,uint64_t offset,SELF *in) +{ + SELF *out = (SELF*)((char*)self_data + offset); + + out->magic = swap32(in->magic); + out->version = swap32(in->version); + out->flags = swap16(in->flags); + out->type = swap16(in->type); + out->metadata_offset = swap32(in->metadata_offset); + out->header_len = swap64(in->header_len); + out->elf_filesize = swap64(in->elf_filesize); + out->unknown = swap64(in->unknown); + out->appinfo_offset = swap64(in->appinfo_offset); + out->elf_offset = swap64(in->elf_offset); + out->phdr_offset = swap64(in->phdr_offset); + out->shdr_offset = swap64(in->shdr_offset); + out->section_info_offset = swap64(in->section_info_offset); + out->sceversion_offset = swap64(in->sceversion_offset); + out->controlinfo_offset = swap64(in->controlinfo_offset); + out->controlinfo_size = swap64(in->controlinfo_size); + out->padding = swap64(in->padding); +} + +void self_write_appinfo_header(char *self_data,uint64_t offset,APP_INFO *in) +{ + APP_INFO *out = (APP_INFO*)((char*)self_data + offset); + + out->authid = swap64(in->authid); + out->vendor_id = swap32(in->vendor_id); + out->self_type = swap32(in->self_type); + out->version = swap32(in->version); + memcpy(out->padding,in->padding,sizeof(in->padding)); +} + +void self_write_elf_header(char *self_data,uint64_t offset,ELF *in) +{ + char *elf_data = (char*)self_data + offset; + elf_write_elf_header(elf_data,in); +} + +void self_write_phdr_header(char *self_data,uint64_t offset,ELF *elf_hdr,ELF_PHDR *in) +{ + char *elf_data = (char*)self_data + offset; + elf_write_phdr_header(elf_data,elf_hdr,in); +} + +void self_write_sectioninfo_header(char *self_data,uint64_t offset,ELF *elf_hdr,SECTION_INFO *in) +{ + uint16_t i; + SECTION_INFO *out = (SECTION_INFO*)((char*)self_data + offset); + + for(i=0;iphnum;i++) { + out[i].offset = swap64(in[i].offset); + out[i].size = swap64(in[i].size); + out[i].compressed = swap32(in[i].compressed); // 2=compressed + out[i].unknown1 = swap32(in[i].unknown1); + out[i].unknown2 = swap32(in[i].unknown2); + out[i].encrypted = swap32(in[i].encrypted); // 1=encrypted + } +} + +void self_write_sceversion_header(char *self_data,uint64_t offset,SCEVERSION_INFO *in) +{ + SCEVERSION_INFO *out = (SCEVERSION_INFO*)((char*)self_data + offset); + + out->unknown1 = swap32(in->unknown1); + out->unknown2 = swap32(in->unknown2); + out->size = swap32(in->size); + out->unknown3 = swap32(in->unknown3); + out->section_idx = swap16(in->section_idx); + out->unknown4 = swap16(in->unknown4); + out->unknown5 = swap32(in->unknown5); + out->unknown6 = swap32(in->unknown6); + out->unknown7 = swap32(in->unknown7); + out->offset = swap64(in->offset); + out->str_size = swap64(in->str_size); +} + +void self_write_control_info_header(char *self_data,uint64_t offset,CONTROL_INFO *in,int npdrm) +{ + uint16_t i,j; + uint16_t cnt = npdrm ? 3 : 2; + + for(i=0;itype = swap32(in[i].type); + out->size = swap32(in[i].size); + out->cont_flag = swap64(in[i].cont_flag); + + switch(in[i].type) { + case 1: + for(j=0;j<8;j++) out->control_flags.control_flags[j] = swap32(in[i].control_flags.control_flags[j]); + break; + case 2: + memcpy(out->file_digest.digest1,in[i].file_digest.digest1,0x14); + memcpy(out->file_digest.digest2,in[i].file_digest.digest2,0x14); + memcpy(out->file_digest.padding,in[i].file_digest.padding,0x08); + break; + case 3: + for(j=0;j<8;j++) out->npdrm.data[j] = swap32(in[i].npdrm.data[j]); + break; + default: + break; + } + + offset += in[i].size; + } +} diff --git a/tools/fself/source/sha1.c b/tools/fself/source/sha1.c new file mode 100644 index 00000000..88629da5 --- /dev/null +++ b/tools/fself/source/sha1.c @@ -0,0 +1,380 @@ +/* + * sha1.c + * + * Copyright (C) 1998 + * Paul E. Jones + * All Rights Reserved + * + * This software is licensed as "freeware." Permission to distribute + * this software in source and binary forms is hereby granted without + * a fee. THIS SOFTWARE IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * THE AUTHOR SHALL NOT BE HELD LIABLE FOR ANY DAMAGES RESULTING + * FROM THE USE OF THIS SOFTWARE, EITHER DIRECTLY OR INDIRECTLY, INCLUDING, + * BUT NOT LIMITED TO, LOSS OF DATA OR DATA BEING RENDERED INACCURATE. + * + ***************************************************************************** + * $Id: sha1.c,v 1.2 2004/03/27 18:00:33 paulej Exp $ + ***************************************************************************** + * + * Description: + * This file implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * The Secure Hashing Standard, which uses the Secure Hashing + * Algorithm (SHA), produces a 160-bit message digest for a + * given data stream. In theory, it is highly improbable that + * two messages will produce the same message digest. Therefore, + * this algorithm can serve as a means of providing a "fingerprint" + * for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code was + * written with the expectation that the processor has at least + * a 32-bit machine word size. If the machine word size is larger, + * the code should still function properly. One caveat to that + * is that the input functions taking characters and character + * arrays assume that only 8 bits of information are stored in each + * character. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated for + * messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is a + * multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the circular shift macro + */ +#define SHA1CircularShift(bits,word) \ + ((((word) << (bits)) & 0xFFFFFFFF) | \ + ((word) >> (32-(bits)))) + +/* Function prototypes */ +void SHA1ProcessMessageBlock(SHA1Context *); +void SHA1PadMessage(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Reset(SHA1Context *context) +{ + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Message_Digest[0] = 0x67452301; + context->Message_Digest[1] = 0xEFCDAB89; + context->Message_Digest[2] = 0x98BADCFE; + context->Message_Digest[3] = 0x10325476; + context->Message_Digest[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array within the SHA1Context provided + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * + * Returns: + * 1 if successful, 0 if it failed. + * + * Comments: + * + */ +int SHA1Result(SHA1Context *context) +{ + + if (context->Corrupted) + { + return 0; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + context->Computed = 1; + } + + return 1; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion of + * the message. + * + * Parameters: + * context: [in/out] + * The SHA-1 context to update + * message_array: [in] + * An array of characters representing the next portion of the + * message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Input( SHA1Context *context, + const unsigned char *message_array, + unsigned length) +{ + if (!length) + { + return; + } + + if (context->Computed || context->Corrupted) + { + context->Corrupted = 1; + return; + } + + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + /* Force it to 32 bits */ + context->Length_Low &= 0xFFFFFFFF; + if (context->Length_Low == 0) + { + context->Length_High++; + /* Force it to 32 bits */ + context->Length_High &= 0xFFFFFFFF; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in the SHAContext, especially the + * single character names, were used because those were the names + * used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const unsigned K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned temp; /* Temporary word value */ + unsigned W[80]; /* Word sequence */ + unsigned A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Message_Digest[0]; + B = context->Message_Digest[1]; + C = context->Message_Digest[2]; + D = context->Message_Digest[3]; + E = context->Message_Digest[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Message_Digest[0] = + (context->Message_Digest[0] + A) & 0xFFFFFFFF; + context->Message_Digest[1] = + (context->Message_Digest[1] + B) & 0xFFFFFFFF; + context->Message_Digest[2] = + (context->Message_Digest[2] + C) & 0xFFFFFFFF; + context->Message_Digest[3] = + (context->Message_Digest[3] + D) & 0xFFFFFFFF; + context->Message_Digest[4] = + (context->Message_Digest[4] + E) & 0xFFFFFFFF; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call SHA1ProcessMessageBlock() + * appropriately. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; + context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; + context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; + context->Message_Block[59] = (context->Length_High) & 0xFF; + context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; + context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; + context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; + context->Message_Block[63] = (context->Length_Low) & 0xFF; + + SHA1ProcessMessageBlock(context); +} diff --git a/tools/fself/source/tools.c b/tools/fself/source/tools.c new file mode 100644 index 00000000..74bdc9af --- /dev/null +++ b/tools/fself/source/tools.c @@ -0,0 +1,241 @@ +#include "tools.h" +#include "sha1.h" + +static void sha1finalize(struct SHA1Context *ctx,uint8_t *digest) +{ + uint32_t i; + + for(i = 0; i < 5; i++) { + *digest++ = ctx->Message_Digest[i] >> 24 & 0xff; + *digest++ = ctx->Message_Digest[i] >> 16 & 0xff; + *digest++ = ctx->Message_Digest[i] >> 8 & 0xff; + *digest++ = ctx->Message_Digest[i] & 0xff; + } +} + +void fail(const char *a, ...) +{ + char msg[1024]; + va_list va; + + va_start(va, a); + vsnprintf(msg, sizeof msg, a, va); + fprintf(stderr, "%s\n", msg); + perror("perror"); + + exit(1); +} + +void elf_read_elf_header(const void *elf_data,ELF *elf_hdr) +{ + memcpy(elf_hdr,elf_data,sizeof(ELF)); + + elf_hdr->type = swap16 (elf_hdr->type); + elf_hdr->machine = swap16 (elf_hdr->machine); + elf_hdr->version = swap32 (elf_hdr->version); + elf_hdr->entry_point = swap64 (elf_hdr->entry_point); + elf_hdr->phdr_offset = swap64 (elf_hdr->phdr_offset); + elf_hdr->shdr_offset = swap64 (elf_hdr->shdr_offset); + elf_hdr->flags = swap16 (elf_hdr->flags); + elf_hdr->header_size = swap32 (elf_hdr->header_size); + elf_hdr->phent_size = swap16 (elf_hdr->phent_size); + elf_hdr->phnum = swap16 (elf_hdr->phnum); + elf_hdr->shent_size = swap16 (elf_hdr->shent_size); + elf_hdr->shnum = swap16 (elf_hdr->shnum); + elf_hdr->shstrndx = swap16 (elf_hdr->shstrndx); +} + +void elf_read_phdr_header(const void *elf_data,ELF *elf_hdr,ELF_PHDR **elf_phdr) +{ + uint16_t i; + ELF_PHDR *phdr = NULL; + + phdr = malloc (sizeof(ELF_PHDR) * elf_hdr->phnum); + + memcpy(phdr,(char*)elf_data + elf_hdr->phdr_offset,sizeof(ELF_PHDR)*elf_hdr->phnum); + + for (i = 0; i < elf_hdr->phnum; i++) { + phdr[i].type = swap32 (phdr[i].type); + phdr[i].flags = swap32 (phdr[i].flags); + phdr[i].offset_in_file = swap64 (phdr[i].offset_in_file); + phdr[i].vitual_addr = swap64 (phdr[i].vitual_addr); + phdr[i].phys_addr = swap64 (phdr[i].phys_addr); + phdr[i].segment_size = swap64 (phdr[i].segment_size); + phdr[i].segment_mem_size = swap64 (phdr[i].segment_mem_size); + phdr[i].alignment = swap64 (phdr[i].alignment); + } + + *elf_phdr = phdr; +} + +void elf_read_shdr_header(const void *elf_data,ELF *elf_hdr,ELF_SHDR **elf_shdr) +{ + uint16_t i; + ELF_SHDR *shdr = NULL; + + shdr = malloc(sizeof(ELF_SHDR) * elf_hdr->shnum); + + memcpy(shdr,(char*)elf_data + elf_hdr->shdr_offset,sizeof(ELF_SHDR)*elf_hdr->shnum); + + for(i=0;ishnum;i++) { + shdr[i].name_idx = swap32(shdr[i].name_idx); + shdr[i].type = swap32(shdr[i].type); + shdr[i].flags = swap64(shdr[i].flags); + shdr[i].virtual_addr = swap64(shdr[i].virtual_addr); + shdr[i].offset_in_file = swap64(shdr[i].offset_in_file); + shdr[i].segment_size = swap64(shdr[i].segment_size); + shdr[i].link = swap32(shdr[i].link); + shdr[i].info = swap32(shdr[i].info); + shdr[i].addr_align = swap64(shdr[i].addr_align); + shdr[i].entry_size = swap64(shdr[i].entry_size); + } + + *elf_shdr = shdr; +} + +int elf_get_shstr_idx(const void *elf_data,const char *section_name) +{ + uint16_t i; + ELF elf_hdr; + const char *name = NULL; + ELF_SHDR *elf_shdr = NULL; + ELF_SHDR *shstr_sec = NULL; + + elf_read_elf_header(elf_data,&elf_hdr); + elf_read_shdr_header(elf_data,&elf_hdr,&elf_shdr); + + shstr_sec = &elf_shdr[elf_hdr.shstrndx]; + for(i=0;ioffset_in_file + elf_shdr[i].name_idx; + if(strncmp(name,section_name,strlen(section_name))==0) break; + } + free(elf_shdr); + + if(i>=elf_hdr.shnum) return -1; + + return i; +} + +uint64_t elf_get_shstr_off(const void *elf_data,const char *section_name) +{ + uint16_t i; + ELF elf_hdr; + uint64_t off = -1; + const char *name = NULL; + ELF_SHDR *elf_shdr = NULL; + ELF_SHDR *shstr_sec = NULL; + + elf_read_elf_header(elf_data,&elf_hdr); + elf_read_shdr_header(elf_data,&elf_hdr,&elf_shdr); + + shstr_sec = &elf_shdr[elf_hdr.shstrndx]; + for(i=0;ioffset_in_file + elf_shdr[i].name_idx; + if(strncmp(name,section_name,strlen(section_name))==0) break; + } + if(iident,elf_hdr->ident,sizeof(elf_hdr->ident)); + out->type = swap16(elf_hdr->type); + out->machine = swap16(elf_hdr->machine); + out->version = swap32(elf_hdr->version); + out->entry_point = swap64(elf_hdr->entry_point); + out->phdr_offset = swap64(elf_hdr->phdr_offset); + out->shdr_offset = swap64(elf_hdr->shdr_offset); + out->flags = swap16(elf_hdr->flags); + out->header_size = swap32(elf_hdr->header_size); + out->phent_size = swap16(elf_hdr->phent_size); + out->phnum = swap16(elf_hdr->phnum); + out->shent_size = swap16(elf_hdr->shent_size); + out->shnum = swap16(elf_hdr->shnum); + out->shstrndx = swap16(elf_hdr->shstrndx); +} + +void elf_write_phdr_header(void *elf_data,ELF *elf_hdr,ELF_PHDR *phdr) +{ + uint16_t i; + ELF_PHDR *elf_phdr = (ELF_PHDR*)elf_data; + + for(i=0;iphnum;i++) { + elf_phdr[i].type = swap32(phdr[i].type); + elf_phdr[i].flags = swap32(phdr[i].flags); + elf_phdr[i].offset_in_file = swap64(phdr[i].offset_in_file); + elf_phdr[i].vitual_addr = swap64(phdr[i].vitual_addr); + elf_phdr[i].phys_addr = swap64(phdr[i].phys_addr); + elf_phdr[i].segment_size = swap64(phdr[i].segment_size); + elf_phdr[i].segment_mem_size = swap64(phdr[i].segment_mem_size); + elf_phdr[i].alignment = swap64(phdr[i].alignment); + } +} + +void sha1(const void *data,uint32_t len,uint8_t *digest) +{ + struct SHA1Context ctx; + + SHA1Reset(&ctx); + SHA1Input(&ctx, data, len); + SHA1Result(&ctx); + + sha1finalize(&ctx, digest); +} + +void sha1_hmac(const void *data,uint32_t len,uint8_t *key,uint8_t *digest) +{ + uint32_t i; + uint8_t tmp[84]; // opad + hash(ipad + message) + uint8_t ipad[64]; + struct SHA1Context ctx; + + SHA1Reset(&ctx); + + for(i=0;i<64;i++) { + tmp[i] = key[i] ^ 0x5c; // opad + ipad[i] = key[i] ^ 0x36; + } + + SHA1Input(&ctx, ipad, 64); + SHA1Input(&ctx, data, len); + SHA1Result(&ctx); + + sha1finalize(&ctx, tmp + 64); + + sha1(tmp, 84, digest); + +} + +#ifdef WIN32 +void get_rand(uint8_t *bfr,uint32_t size) +{ + HCRYPTPROV hProv; + + if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + fail("unable to open random"); + + if (!CryptGenRandom(hProv, size, bfr)) + fail("unable to read random numbers"); + + CryptReleaseContext(hProv, 0); +} +#else +void get_rand(uint8_t *bfr,uint32_t size) +{ + FILE *fp; + + fp = fopen("/dev/urandom", "r"); + if (fp == NULL) + fail("unable to open random"); + + if (fread(bfr, size, 1, fp) != 1) + fail("unable to read random numbers"); + + fclose(fp); +} +#endif