mirror of
https://github.com/zeldaret/tp
synced 2026-06-17 15:17:13 -04:00
copy homebuttonLib from oot-vc (#2960)
* initial copy of hbm from sdk_2009-12-11 * some more nw4hbm cleanup * nw4hbm db mostly done * nw4hbm snd copied from oot-vc * nw4hbm ut copied * nw4hbm lyt copied * nw4hbm copied, mostly matching usa 1.0 * setup nw4hbm debug define * fix HBMDataInfo struct * add rvl sdk card lib
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
#ifndef STD_NEW_H_
|
||||
#define STD_NEW_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
inline void* (operator new)(size_t, void *ptr) { return ptr; }
|
||||
|
||||
#endif
|
||||
@@ -39,6 +39,14 @@ inline float tan(float num) {
|
||||
return ::i_tanf(num);
|
||||
}
|
||||
|
||||
inline float tanf(float num) {
|
||||
return ::i_tanf(num);
|
||||
}
|
||||
|
||||
inline float acos(float num) {
|
||||
return ::acosf(num);
|
||||
}
|
||||
|
||||
inline float pow(float x, float y) {
|
||||
return ::pow(x, y);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
namespace std {
|
||||
using ::strlen;
|
||||
using ::strcpy;
|
||||
using ::wcslen;
|
||||
using ::strncpy;
|
||||
using ::strcmp;
|
||||
using ::strncmp;
|
||||
using ::strcat;
|
||||
|
||||
using ::memset;
|
||||
using ::memcpy;
|
||||
|
||||
inline char* strchr(char* str, int c) {
|
||||
return ::strchr(str, c);
|
||||
|
||||
@@ -15,8 +15,17 @@ int snprintf(char* s, size_t n, const char* format, ...);
|
||||
int vsnprintf(char* s, size_t n, const char* format, va_list arg);
|
||||
int vprintf(const char* format, va_list arg);
|
||||
|
||||
int vswprintf(wchar_t* s, size_t n, const wchar_t* format, va_list arg);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
namespace std {
|
||||
extern "C" { using ::vsnprintf; }
|
||||
extern "C" { using ::vswprintf; }
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _MSL_COMMON_PRINTF_H */
|
||||
#endif /* _MSL_COMMON_PRINTF_H */
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define _MSL_COMMON_STRING_H
|
||||
|
||||
#include "stddef.h"
|
||||
#include "ansi_files.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -22,6 +23,8 @@ char* strncpy(char* dst, const char* src, size_t n);
|
||||
char* strcpy(char* dst, const char* src);
|
||||
size_t strlen(const char* str);
|
||||
|
||||
size_t wcslen(const wchar_t* s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1000,7 +1000,7 @@ static int __pformatter(void* (*WriteProc)(void*, const char*, size_t), void* Wr
|
||||
if (format.argument_options == long_double_argument) {
|
||||
long_double_num = va_arg(arg, long double);
|
||||
} else {
|
||||
long_double_num = va_arg(arg, f64);
|
||||
long_double_num = va_arg(arg, double);
|
||||
}
|
||||
|
||||
if (!(buff_ptr = float2str(long_double_num, buff + 512, format))) {
|
||||
@@ -1015,7 +1015,7 @@ static int __pformatter(void* (*WriteProc)(void*, const char*, size_t), void* Wr
|
||||
if (format.argument_options == long_double_argument) {
|
||||
long_double_num = va_arg(arg, long double);
|
||||
} else {
|
||||
long_double_num = va_arg(arg, f64);
|
||||
long_double_num = va_arg(arg, double);
|
||||
}
|
||||
|
||||
if (!(buff_ptr = double2hex(long_double_num, buff + 512, format))) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef __VA_ARG_H
|
||||
#define __VA_ARG_H
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct __va_list_struct {
|
||||
char gpr;
|
||||
@@ -13,11 +15,7 @@ typedef struct __va_list_struct {
|
||||
|
||||
typedef _va_list_struct __va_list[1];
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" void* __va_arg(_va_list_struct*, int);
|
||||
#else
|
||||
void* __va_arg(_va_list_struct*, int);
|
||||
#endif
|
||||
|
||||
#ifndef __MWERKS__
|
||||
#define __builtin_va_info(...)
|
||||
@@ -37,4 +35,12 @@ void* __va_arg(_va_list_struct*, int);
|
||||
|
||||
#define __va_copy(a, b) (*(a) = *(b))
|
||||
|
||||
#if defined(__cplusplus)
|
||||
namespace std { extern "C" { using ::va_list; } }
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __VA_ARG_H */
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include "Z2AudioLib/Z2SeqMgr.h"
|
||||
#include "Z2AudioLib/Z2SeMgr.h"
|
||||
#include "Z2AudioLib/Z2SoundInfo.h"
|
||||
#include "Z2AudioLib/Z2AudioCS.h"
|
||||
#include "JSystem/JAudio2/JASCalc.h"
|
||||
#include "JSystem/JAudio2/JASDriverIF.h"
|
||||
#include "JSystem/JAudio2/JAUSectionHeap.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
|
||||
#if PLATFORM_WII || PLATFORM_SHIELD
|
||||
#include "Z2AudioLib/Z2AudioCS.h"
|
||||
#endif
|
||||
|
||||
u16 seqCallback(JASTrack* track, u16 command) {
|
||||
switch (command) {
|
||||
case 0x1000:
|
||||
|
||||
@@ -0,0 +1,849 @@
|
||||
#include <revolution/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
const char* __CARDVersion = "<< RVL_SDK - CARD \trelease build: Sep 7 2006 18:26:19 (0x4200_60422) >>";
|
||||
|
||||
CARDControl __CARDBlock[2];
|
||||
|
||||
static u16 __CARDEncode;
|
||||
static u16 __CARDFastMode;
|
||||
|
||||
DVDDiskID __CARDDiskNone;
|
||||
|
||||
// prototypes
|
||||
static void TimeoutHandler(OSAlarm* alarm, OSContext* context);
|
||||
static void SetupTimeoutAlarm(CARDControl* card);
|
||||
static s32 Retry(s32 chan);
|
||||
static void UnlockedCallback(s32 chan, s32 result);
|
||||
static BOOL OnShutdown(BOOL f, u32 event);
|
||||
|
||||
static OSShutdownFunctionInfo ShutdownFunctionInfo = {OnShutdown, 127};
|
||||
|
||||
void __CARDDefaultApiCallback(s32 chan, s32 result) {}
|
||||
|
||||
void __CARDSyncCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
card = &__CARDBlock[chan];
|
||||
OSWakeupThread(&card->threadQueue);
|
||||
}
|
||||
|
||||
void __CARDExtHandler(s32 chan, OSContext* context) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
ASSERTLINE(232, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (card->attached) {
|
||||
ASSERTLINE(239, card->txCallback == 0);
|
||||
card->attached = FALSE;
|
||||
EXISetExiCallback(chan, 0);
|
||||
OSCancelAlarm(&card->alarm);
|
||||
callback = card->exiCallback;
|
||||
|
||||
if (callback) {
|
||||
card->exiCallback = 0;
|
||||
callback(chan, CARD_RESULT_NOCARD);
|
||||
}
|
||||
|
||||
if (card->result != CARD_RESULT_BUSY) {
|
||||
card->result = CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
callback = card->extCallback;
|
||||
if (callback && CARD_MAX_MOUNT_STEP <= card->mountStep) {
|
||||
card->extCallback = 0;
|
||||
callback(chan, CARD_RESULT_NOCARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __CARDExiHandler(s32 chan, OSContext* context) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u8 status;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(283, 0 <= chan && chan < 2);
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
OSCancelAlarm(&card->alarm);
|
||||
|
||||
if (!card->attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EXILock(chan, 0, 0)) {
|
||||
result = CARD_RESULT_FATAL_ERROR;
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
if ((result = __CARDReadStatus(chan, &status)) < 0 || (result = __CARDClearStatus(chan)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((result = (status & 0x18) ? CARD_RESULT_IOERROR : CARD_RESULT_READY) == CARD_RESULT_IOERROR &&
|
||||
--card->retry > 0)
|
||||
{
|
||||
result = Retry(chan);
|
||||
if (result >= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
goto fatal;
|
||||
}
|
||||
|
||||
error:
|
||||
EXIUnlock(chan);
|
||||
|
||||
fatal:
|
||||
callback = card->exiCallback;
|
||||
if (callback) {
|
||||
card->exiCallback = 0;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
void __CARDTxHandler(s32 chan, OSContext* context) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
int err;
|
||||
|
||||
ASSERTLINE(365, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
err = !EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
callback = card->txCallback;
|
||||
if (callback) {
|
||||
card->txCallback = NULL;
|
||||
callback(chan, (!err && EXIProbe(chan)) ? CARD_RESULT_READY : CARD_RESULT_NOCARD);
|
||||
}
|
||||
}
|
||||
|
||||
void __CARDUnlockedHandler(s32 chan, OSContext* context) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
ASSERTLINE(412, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
callback = card->unlockCallback;
|
||||
if (callback) {
|
||||
card->unlockCallback = 0;
|
||||
callback(chan, EXIProbe(chan) ? CARD_RESULT_UNLOCKED : CARD_RESULT_NOCARD);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDEnableInterrupt(s32 chan, BOOL enable) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(431, 0 <= chan && chan < 2);
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
cmd = enable ? 0x81010000 : 0x81000000;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, NULL);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
s32 __CARDReadStatus(s32 chan, u8* status) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(450, 0 <= chan && chan < 2);
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
cmd = 0x83000000;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, NULL);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIImm(chan, status, 1, EXI_READ, NULL);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
int __CARDReadVendorID(s32 chan, u16* id) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(471, 0 <= chan && chan < 2);
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
cmd = 0x85000000;
|
||||
err = 0;
|
||||
err |= !EXIImm(chan, &cmd, 2, EXI_WRITE, 0);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIImm(chan, id, 2, EXI_READ, 0);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
s32 __CARDClearStatus(s32 chan) {
|
||||
BOOL err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(492, 0 <= chan && chan < 2);
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
cmd = 0x89000000;
|
||||
err = FALSE;
|
||||
err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
|
||||
return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
s32 __CARDSleep(s32 chan) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(511, 0 <= chan && chan < 2);
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
cmd = 0x88000000;
|
||||
err = 0;
|
||||
err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
|
||||
if(err) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
s32 __CARDWakeup(s32 chan) {
|
||||
int err;
|
||||
u32 cmd;
|
||||
|
||||
ASSERTLINE(530, 0 <= chan && chan < 2);
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
cmd = 0x87000000;
|
||||
err = 0;
|
||||
err |= !EXIImm(chan, &cmd, 1, EXI_WRITE, 0);
|
||||
err |= !EXISync(chan);
|
||||
err |= !EXIDeselect(chan);
|
||||
|
||||
if(err) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static void TimeoutHandler(OSAlarm* alarm, OSContext* context) {
|
||||
s32 chan;
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
for (chan = 0; chan < 2; ++chan) {
|
||||
card = &__CARDBlock[chan];
|
||||
if (alarm == &card->alarm) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTLINE(578, 0 <= chan && chan < 2);
|
||||
|
||||
if (!card->attached) {
|
||||
return;
|
||||
}
|
||||
|
||||
EXISetExiCallback(chan, NULL);
|
||||
callback = card->exiCallback;
|
||||
if (callback) {
|
||||
card->exiCallback = 0;
|
||||
callback(chan, CARD_RESULT_IOERROR);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupTimeoutAlarm(CARDControl* card) {
|
||||
OSCancelAlarm(&card->alarm);
|
||||
switch (card->cmd[0]) {
|
||||
case 0xF2:
|
||||
OSSetAlarm(&card->alarm, OSMillisecondsToTicks(100),
|
||||
TimeoutHandler);
|
||||
break;
|
||||
case 0xF3:
|
||||
break;
|
||||
case 0xF4:
|
||||
if (card->pageSize > 0x80) {
|
||||
OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->cBlock / 0x40),
|
||||
TimeoutHandler);
|
||||
break;
|
||||
}
|
||||
case 0xF1:
|
||||
OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->sectorSize / 0x2000),
|
||||
TimeoutHandler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static s32 Retry(s32 chan) {
|
||||
CARDControl* card;
|
||||
|
||||
ASSERTLINE(654, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
EXIUnlock(chan);
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
SetupTimeoutAlarm(card);
|
||||
|
||||
if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE)) {
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
if (card->cmd[0] == 0x52 &&
|
||||
!EXIImmEx(chan, (u8* )card->workArea + sizeof(CARDID), card->latency, EXI_WRITE))
|
||||
{
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
if (card->mode == 0xffffffff) {
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
if (!EXIDma(chan, card->buffer, (s32)((card->cmd[0] == 0x52) ? 512 : card->pageSize), card->mode,
|
||||
__CARDTxHandler))
|
||||
{
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static void UnlockedCallback(s32 chan, s32 result) {
|
||||
CARDCallback callback;
|
||||
CARDControl* card;
|
||||
|
||||
ASSERTLINE(718, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result >= 0) {
|
||||
card->unlockCallback = UnlockedCallback;
|
||||
if (!EXILock(chan, 0, __CARDUnlockedHandler)) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else {
|
||||
card->unlockCallback = 0;
|
||||
result = Retry(chan);
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
switch (card->cmd[0]) {
|
||||
case 0x52:
|
||||
callback = card->txCallback;
|
||||
if (callback) {
|
||||
card->txCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
break;
|
||||
case 0xF2:
|
||||
case 0xF4:
|
||||
case 0xF1:
|
||||
callback = card->exiCallback;
|
||||
if (callback) {
|
||||
card->exiCallback = 0;
|
||||
callback(chan, result);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static s32 __CARDStart(s32 chan, CARDCallback txCallback, CARDCallback exiCallback) {
|
||||
BOOL enabled;
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTLINE(784, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!card->attached) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else {
|
||||
if (txCallback) {
|
||||
card->txCallback = txCallback;
|
||||
}
|
||||
|
||||
if (exiCallback) {
|
||||
card->exiCallback = exiCallback;
|
||||
}
|
||||
|
||||
card->unlockCallback = UnlockedCallback;
|
||||
|
||||
if (!EXILock(chan, 0, __CARDUnlockedHandler)) {
|
||||
result = CARD_RESULT_BUSY;
|
||||
} else {
|
||||
card->unlockCallback = 0;
|
||||
|
||||
if (!EXISelect(chan, 0, CARDFreq)) {
|
||||
EXIUnlock(chan);
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else {
|
||||
SetupTimeoutAlarm(card);
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
#define AD1(x) ((u8)(((x) >> 17) & 0x7f))
|
||||
#define AD1EX(x) ((u8)(AD1(x) | 0x80));
|
||||
#define AD2(x) ((u8)(((x) >> 9) & 0xff))
|
||||
#define AD3(x) ((u8)(((x) >> 7) & 0x03))
|
||||
#define BA(x) ((u8)((x)&0x7f))
|
||||
|
||||
s32 __CARDReadSegment(s32 chan, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(846, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
ASSERTLINE(848, card->addr % CARD_SEG_SIZE == 0);
|
||||
ASSERTLINE(849, card->addr < (u32) card->size * 1024 * 1024 / 8);
|
||||
|
||||
card->cmd[0] = 0x52;
|
||||
card->cmd[1] = AD1(card->addr);
|
||||
card->cmd[2] = AD2(card->addr);
|
||||
card->cmd[3] = AD3(card->addr);
|
||||
card->cmd[4] = BA(card->addr);
|
||||
card->cmdlen = 5;
|
||||
card->mode = 0;
|
||||
card->retry = 0;
|
||||
|
||||
result = __CARDStart(chan, callback, 0);
|
||||
if (result == CARD_RESULT_BUSY) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else if (result >= 0) {
|
||||
if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE) ||
|
||||
!EXIImmEx(chan, (u8* )card->workArea + sizeof(CARDID), card->latency,
|
||||
EXI_WRITE) || // XXX use DMA if possible
|
||||
!EXIDma(chan, card->buffer, 512, card->mode, __CARDTxHandler))
|
||||
{
|
||||
card->txCallback = NULL;
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else {
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDWritePage(s32 chan, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(903, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
ASSERTLINE(905, card->addr % card->pageSize == 0);
|
||||
ASSERTLINE(906, card->addr < (u32) card->size * 1024 * 1024 / 8);
|
||||
card->cmd[0] = 0xF2;
|
||||
|
||||
if (card->pageSize > 0x80) {
|
||||
card->cmd[1] = AD1(card->addr) | 0x80;
|
||||
} else {
|
||||
card->cmd[1] = AD1(card->addr);
|
||||
}
|
||||
|
||||
card->cmd[2] = AD2(card->addr);
|
||||
card->cmd[3] = AD3(card->addr);
|
||||
card->cmd[4] = BA(card->addr);
|
||||
card->cmdlen = 5;
|
||||
card->mode = 1;
|
||||
card->retry = 3;
|
||||
|
||||
result = __CARDStart(chan, 0, callback);
|
||||
if (result == CARD_RESULT_BUSY) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else if (result >= 0) {
|
||||
if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE) ||
|
||||
!EXIDma(chan, card->buffer, card->pageSize, card->mode, __CARDTxHandler))
|
||||
{
|
||||
card->exiCallback = 0;
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else {
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDErase(s32 chan, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(962, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
card->cmd[0] = 0xF4;
|
||||
card->cmd[1] = 0;
|
||||
card->cmd[2] = 0;
|
||||
card->cmdlen = 3;
|
||||
card->mode = -1;
|
||||
card->retry = 3;
|
||||
result = __CARDStart(chan, 0, callback);
|
||||
if (result == CARD_RESULT_BUSY) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else if (result >= 0) {
|
||||
if (EXIImmEx(chan, &card->cmd, card->cmdlen, EXI_WRITE) == 0) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
card->exiCallback = 0;
|
||||
} else {
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(1010, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
ASSERTLINE(1012, addr % card->sectorSize == 0);
|
||||
ASSERTLINE(1013, addr < (u32) card->size * 1024 * 1024 / 8);
|
||||
|
||||
if (card->pageSize > 0x80) {
|
||||
if (callback) {
|
||||
callback(chan, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
card->cmd[0] = 0xF1;
|
||||
card->cmd[1] = AD1(addr);
|
||||
card->cmd[2] = AD2(addr);
|
||||
card->cmdlen = 3;
|
||||
card->mode = -1;
|
||||
card->retry = 3;
|
||||
|
||||
result = __CARDStart(chan, 0, callback);
|
||||
|
||||
if (result == CARD_RESULT_BUSY) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else if (result >= 0) {
|
||||
if (!EXIImmEx(chan, card->cmd, card->cmdlen, EXI_WRITE)) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
card->exiCallback = NULL;
|
||||
} else {
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
EXIDeselect(chan);
|
||||
EXIUnlock(chan);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void CARDInit(void) {
|
||||
int chan;
|
||||
|
||||
if (__CARDBlock[0].diskID && __CARDBlock[1].diskID) {
|
||||
return;
|
||||
}
|
||||
|
||||
__CARDEncode = OSGetFontEncode();
|
||||
|
||||
OSRegisterVersion(__CARDVersion);
|
||||
|
||||
DSPInit();
|
||||
|
||||
for (chan = 0; chan < 2; ++chan) {
|
||||
CARDControl* card = &__CARDBlock[chan];
|
||||
|
||||
card->result = CARD_RESULT_NOCARD;
|
||||
OSInitThreadQueue(&card->threadQueue);
|
||||
OSCreateAlarm(&card->alarm);
|
||||
}
|
||||
__CARDSetDiskID((void*)OSPhysicalToCached(0));
|
||||
|
||||
OSRegisterShutdownFunction(&ShutdownFunctionInfo);
|
||||
}
|
||||
|
||||
u16 __CARDGetFontEncode(void) {
|
||||
return __CARDEncode;
|
||||
}
|
||||
|
||||
u16 __CARDSetFontEncode(u16 encode) {
|
||||
u16 prev = __CARDEncode;
|
||||
|
||||
switch (encode) {
|
||||
case CARD_ENCODE_ANSI:
|
||||
case CARD_ENCODE_SJIS:
|
||||
__CARDEncode = encode;
|
||||
break;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
void __CARDSetDiskID(const DVDDiskID* id) {
|
||||
__CARDBlock[0].diskID = id ? id : &__CARDDiskNone;
|
||||
__CARDBlock[1].diskID = id ? id : &__CARDDiskNone;
|
||||
}
|
||||
|
||||
const DVDDiskID* CARDGetDiskID(s32 chan) {
|
||||
ASSERTLINE(1168, 0 <= chan && chan < 2);
|
||||
return __CARDBlock[chan].diskID;
|
||||
}
|
||||
|
||||
s32 CARDSetDiskID(s32 chan, const DVDDiskID* diskID) {
|
||||
BOOL enabled;
|
||||
CARDControl* card;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
ASSERTLINE(1189, 0 <= chan && chan < 2);
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (card->result == CARD_RESULT_BUSY) {
|
||||
return CARD_RESULT_BUSY;
|
||||
}
|
||||
|
||||
card->diskID = diskID != 0 ? diskID : (const DVDDiskID*)OSPhysicalToCached(0);
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 __CARDGetControlBlock(s32 chan, CARDControl** pcard) {
|
||||
BOOL enabled;
|
||||
s32 result;
|
||||
CARDControl* card;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
if (chan < 0 || chan >= 2 || card->diskID == 0) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (!card->attached) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else if (card->result == CARD_RESULT_BUSY) {
|
||||
result = CARD_RESULT_BUSY;
|
||||
} else {
|
||||
card->result = CARD_RESULT_BUSY;
|
||||
result = CARD_RESULT_READY;
|
||||
card->apiCallback = NULL;
|
||||
*pcard = card;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDPutControlBlock(CARDControl* card, s32 result) {
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTLINE(1259, result != CARD_RESULT_BUSY);
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
if (card->attached) {
|
||||
card->result = result;
|
||||
} else if (card->result == CARD_RESULT_BUSY) {
|
||||
card->result = result;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDGetResultCode(s32 chan) {
|
||||
CARDControl* card;
|
||||
|
||||
ASSERTLINE(1292, 0 <= chan && chan < 2);
|
||||
|
||||
if (chan < 0 || chan >= 2) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
card = &__CARDBlock[chan];
|
||||
return card->result;
|
||||
}
|
||||
|
||||
s32 CARDFreeBlocks(s32 chan, s32* byteNotUsed, s32* filesNotUsed) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
u16* fat;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
u16 fileNo;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
dir = __CARDGetDirBlock(card);
|
||||
if (fat == 0 || dir == 0) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
|
||||
if (byteNotUsed) {
|
||||
*byteNotUsed = (s32)(card->sectorSize * fat[CARD_FAT_FREEBLOCKS]);
|
||||
}
|
||||
|
||||
if (filesNotUsed) {
|
||||
*filesNotUsed = 0;
|
||||
for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) {
|
||||
ent = &dir[fileNo];
|
||||
if (ent->fileName[0] == 0xff) {
|
||||
++*filesNotUsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 CARDGetEncoding(s32 chan, u16* encode) {
|
||||
CARDControl* card;
|
||||
CARDID* id;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
id = card->workArea;
|
||||
*encode = id->encode;
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 CARDGetMemSize(s32 chan, u16* size) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*size = card->size;
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 CARDGetSectorSize(s32 chan, u32* size) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
*size = card->sectorSize;
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 __CARDSync(s32 chan) {
|
||||
CARDControl* block;
|
||||
s32 result;
|
||||
s32 enabled;
|
||||
|
||||
block = &__CARDBlock[chan];
|
||||
enabled = OSDisableInterrupts();
|
||||
while ((result = CARDGetResultCode(chan)) == CARD_RESULT_BUSY) {
|
||||
OSSleepThread(&block->threadQueue);
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
static BOOL OnShutdown(BOOL final, u32 event) {
|
||||
if (!final) {
|
||||
if (CARDUnmount(0) == CARD_RESULT_BUSY || CARDUnmount(1) == CARD_RESULT_BUSY) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CARDSetFastMode(BOOL enable) {
|
||||
u16 prev = __CARDFastMode;
|
||||
__CARDFastMode = enable ? TRUE : FALSE;
|
||||
|
||||
return prev ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
BOOL CARDGetFastMode(void) {
|
||||
return __CARDFastMode ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
s32 CARDGetCurrentMode(s32 chan, u32* mode) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (card->pageSize) {
|
||||
case 512:
|
||||
*mode = 1;
|
||||
break;
|
||||
case 128:
|
||||
default:
|
||||
*mode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void WriteCallback(s32 chan, s32 result);
|
||||
static void EraseCallback(s32 chan, s32 result);
|
||||
|
||||
void* __CARDGetFatBlock(CARDControl* card) {
|
||||
ASSERTLINE(57, card->currentFat);
|
||||
return card->currentFat;
|
||||
}
|
||||
|
||||
static void WriteCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u16* fat0;
|
||||
u16* fat1;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
if (result >= 0) {
|
||||
fat0 = (u16*)((u8*)card->workArea + 0x6000);
|
||||
fat1 = (u16*)((u8*)card->workArea + 0x8000);
|
||||
|
||||
ASSERTLINE(82, card->currentFat);
|
||||
if (card->currentFat == fat0) {
|
||||
card->currentFat = fat1;
|
||||
memcpy(fat1, fat0, 0x2000);
|
||||
} else {
|
||||
ASSERTLINE(90, card->currentFat == fat1);
|
||||
card->currentFat = fat0;
|
||||
memcpy(fat0, fat1, 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!card->apiCallback)
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
callback = card->eraseCallback;
|
||||
if (callback) {
|
||||
card->eraseCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void EraseCallback(s32 chan, s32 result) {
|
||||
CARDControl* card = &__CARDBlock[chan];
|
||||
CARDCallback callback;
|
||||
u16* fat;
|
||||
u32 addr;
|
||||
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
addr = ((u32)fat - (u32)card->workArea) / CARD_SYSTEM_BLOCK_SIZE * card->sectorSize;
|
||||
result = __CARDWrite(chan, addr, CARD_SYSTEM_BLOCK_SIZE, fat, WriteCallback);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
if (!card->apiCallback)
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
callback = card->eraseCallback;
|
||||
if (callback) {
|
||||
card->eraseCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
u16* fat;
|
||||
u16 iBlock;
|
||||
u16 startBlock;
|
||||
u16 prevBlock;
|
||||
u16 count;
|
||||
|
||||
ASSERTLINE(182, 0 < cBlock);
|
||||
ASSERTLINE(183, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!card->attached)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
if (fat[3] < cBlock)
|
||||
return CARD_RESULT_INSSPACE;
|
||||
|
||||
fat[3] -= cBlock;
|
||||
startBlock = 0xFFFF;
|
||||
iBlock = fat[4];
|
||||
count = 0;
|
||||
while (0 < cBlock) {
|
||||
if (card->cBlock - 5 < ++count)
|
||||
return CARD_RESULT_BROKEN;
|
||||
|
||||
iBlock++;
|
||||
if (!CARDIsValidBlockNo(card, iBlock))
|
||||
iBlock = 5;
|
||||
|
||||
if (fat[iBlock] == 0x0000u) {
|
||||
if (startBlock == 0xFFFF)
|
||||
startBlock = iBlock;
|
||||
else
|
||||
fat[prevBlock] = iBlock;
|
||||
prevBlock = iBlock;
|
||||
fat[iBlock] = 0xFFFF;
|
||||
--cBlock;
|
||||
}
|
||||
}
|
||||
|
||||
fat[4] = iBlock;
|
||||
card->startBlock = startBlock;
|
||||
return __CARDUpdateFatBlock(chan, fat, callback);
|
||||
}
|
||||
|
||||
s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
u16* fat;
|
||||
u16 nextBlock;
|
||||
|
||||
ASSERTLINE(253, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!card->attached)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
while (nBlock != 0xFFFF) {
|
||||
if (!CARDIsValidBlockNo(card, nBlock))
|
||||
return CARD_RESULT_BROKEN;
|
||||
|
||||
nextBlock = fat[nBlock];
|
||||
fat[nBlock] = 0;
|
||||
nBlock = nextBlock;
|
||||
++fat[3];
|
||||
}
|
||||
|
||||
return __CARDUpdateFatBlock(chan, fat, callback);
|
||||
}
|
||||
|
||||
s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
u32 addr;
|
||||
|
||||
ASSERTLINE(295, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
++fat[2];
|
||||
__CARDCheckSum(fat + 2, 0x1FFC, fat, fat + 1);
|
||||
DCStoreRange(fat, 0x2000);
|
||||
card->eraseCallback = callback;
|
||||
addr = (((char*)fat - (char*)card->workArea) / 8192u) * card->sectorSize;
|
||||
return __CARDEraseSector(chan, addr, EraseCallback);
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static s32 VerifyID(CARDControl* card);
|
||||
static s32 VerifyDir(CARDControl* card, int* pcurrent);
|
||||
static s32 VerifyFAT(CARDControl* card, int* pcurrent);
|
||||
|
||||
void __CARDCheckSum(void* ptr, int length, u16* checksum, u16* checksumInv) {
|
||||
u16* p;
|
||||
int i;
|
||||
|
||||
ASSERTLINE(82, length % sizeof(u16) == 0);
|
||||
|
||||
length /= sizeof(u16);
|
||||
*checksum = *checksumInv = 0;
|
||||
for (i = 0, p = ptr; i < length; i++, p++) {
|
||||
*checksum += *p;
|
||||
*checksumInv += ~*p;
|
||||
}
|
||||
|
||||
if (*checksum == 0xFFFF)
|
||||
*checksum = 0;
|
||||
|
||||
if (*checksumInv == 0xFFFF)
|
||||
*checksumInv = 0;
|
||||
}
|
||||
|
||||
static s32 VerifyID(CARDControl* card) {
|
||||
CARDID* id;
|
||||
u16 checksum;
|
||||
u16 checksumInv;
|
||||
OSSramEx* sramEx;
|
||||
OSTime rand;
|
||||
int i;
|
||||
|
||||
id = card->workArea;
|
||||
|
||||
if (id->deviceID != 0 || id->size != card->size)
|
||||
return CARD_RESULT_BROKEN;
|
||||
|
||||
__CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &checksum, &checksumInv);
|
||||
if (id->checkSum != checksum || id->checkSumInv != checksumInv)
|
||||
return CARD_RESULT_BROKEN;
|
||||
|
||||
rand = *(OSTime*)&id->serial[12];
|
||||
sramEx = __OSLockSramEx();
|
||||
for (i = 0; i < 12; i++) {
|
||||
rand = (rand * 1103515245 + 12345) >> 16;
|
||||
if (id->serial[i] != (u8)(sramEx->flashID[card - __CARDBlock][i] + rand)) {
|
||||
__OSUnlockSramEx(FALSE);
|
||||
return CARD_RESULT_BROKEN;
|
||||
}
|
||||
rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
__OSUnlockSramEx(FALSE);
|
||||
|
||||
if (id->encode != __CARDGetFontEncode())
|
||||
return CARD_RESULT_ENCODING;
|
||||
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static s32 VerifyDir(CARDControl* card, int* pcurrent) {
|
||||
CARDDir* dir[2];
|
||||
CARDDirCheck* check[2];
|
||||
u16 checkSum;
|
||||
u16 checkSumInv;
|
||||
int i;
|
||||
int errors;
|
||||
int current;
|
||||
|
||||
current = errors = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
dir[i] = (CARDDir*)((u8*)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
check[i] = CARDGetDirCheck(dir[i]);
|
||||
__CARDCheckSum(dir[i], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv);
|
||||
if (check[i]->checkSum != checkSum || check[i]->checkSumInv != checkSumInv) {
|
||||
++errors;
|
||||
current = i;
|
||||
card->currentDir = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == errors) {
|
||||
if (card->currentDir == 0) {
|
||||
if ((check[0]->checkCode - check[1]->checkCode) < 0)
|
||||
current = 0;
|
||||
else
|
||||
current = 1;
|
||||
card->currentDir = dir[current];
|
||||
memcpy(dir[current], dir[current ^ 1], CARD_SYSTEM_BLOCK_SIZE);
|
||||
} else {
|
||||
current = (card->currentDir == dir[0]) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcurrent)
|
||||
*pcurrent = current;
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
static s32 VerifyFAT(CARDControl* card, int* pcurrent) {
|
||||
u16* fat[2];
|
||||
u16* fatp;
|
||||
u16 nBlock;
|
||||
u16 cFree;
|
||||
int i;
|
||||
u16 checkSum;
|
||||
u16 checkSumInv;
|
||||
int errors;
|
||||
int current;
|
||||
|
||||
current = errors = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
fatp = fat[i] = (u16*)((u8*)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
|
||||
__CARDCheckSum(&fatp[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv);
|
||||
if (fatp[CARD_FAT_CHECKSUM] != checkSum || fatp[CARD_FAT_CHECKSUMINV] != checkSumInv) {
|
||||
++errors;
|
||||
current = i;
|
||||
card->currentFat = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
cFree = 0;
|
||||
for (nBlock = CARD_NUM_SYSTEM_BLOCK; nBlock < card->cBlock; nBlock++) {
|
||||
if (fatp[nBlock] == CARD_FAT_AVAIL)
|
||||
cFree++;
|
||||
}
|
||||
|
||||
if (cFree != fatp[CARD_FAT_FREEBLOCKS]) {
|
||||
++errors;
|
||||
current = i;
|
||||
card->currentFat = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == errors) {
|
||||
if (card->currentFat == 0) {
|
||||
if (((s16)fat[0][CARD_FAT_CHECKCODE] - (s16)fat[1][CARD_FAT_CHECKCODE]) < 0)
|
||||
current = 0;
|
||||
else
|
||||
current = 1;
|
||||
card->currentFat = fat[current];
|
||||
memcpy(fat[current], fat[current ^ 1], CARD_SYSTEM_BLOCK_SIZE);
|
||||
} else
|
||||
current = (card->currentFat == fat[0]) ? 0 : 1;
|
||||
}
|
||||
|
||||
if (pcurrent)
|
||||
*pcurrent = current;
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
s32 __CARDVerify(CARDControl* card) {
|
||||
s32 result;
|
||||
int errors;
|
||||
|
||||
result = VerifyID(card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
errors = VerifyDir(card, NULL);
|
||||
errors += VerifyFAT(card, NULL);
|
||||
switch (errors) {
|
||||
case 0:
|
||||
ASSERTLINE(301, card->currentDir);
|
||||
ASSERTLINE(302, card->currentFat);
|
||||
return CARD_RESULT_READY;
|
||||
case 1:
|
||||
return CARD_RESULT_BROKEN;
|
||||
default:
|
||||
return CARD_RESULT_BROKEN;
|
||||
}
|
||||
}
|
||||
|
||||
s32 CARDCheckExAsync(s32 chan, s32* xferBytes, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir[2];
|
||||
u16* fat[2];
|
||||
u16* map;
|
||||
s32 result;
|
||||
int errors;
|
||||
int currentFat;
|
||||
int currentDir;
|
||||
s32 fileNo;
|
||||
u16 iBlock;
|
||||
u16 cBlock;
|
||||
u16 cFree;
|
||||
BOOL updateFat = FALSE;
|
||||
BOOL updateDir = FALSE;
|
||||
BOOL updateOrphan = FALSE;
|
||||
|
||||
ASSERTLINE(346, 0 <= chan && chan < 2);
|
||||
|
||||
if (xferBytes) {
|
||||
*xferBytes = 0;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = VerifyID(card);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
errors = VerifyDir(card, ¤tDir);
|
||||
errors += VerifyFAT(card, ¤tFat);
|
||||
if (1 < errors) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
|
||||
dir[0] = (CARDDir*)((u8*)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
dir[1] = (CARDDir*)((u8*)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
fat[0] = (u16*)((u8*)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
fat[1] = (u16*)((u8*)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
|
||||
ASSERTLINE(377, errors == 0 || errors == 1);
|
||||
|
||||
switch (errors) {
|
||||
case 0:
|
||||
ASSERTLINE(381, card->currentDir);
|
||||
ASSERTLINE(382, card->currentFat);
|
||||
break;
|
||||
case 1:
|
||||
if (!card->currentDir) {
|
||||
ASSERTLINE(387, card->currentFat);
|
||||
card->currentDir = dir[currentDir];
|
||||
memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE);
|
||||
updateDir = TRUE;
|
||||
} else {
|
||||
ASSERTLINE(394, !card->currentFat);
|
||||
card->currentFat = fat[currentFat];
|
||||
memcpy(fat[currentFat], fat[currentFat ^ 1], CARD_SYSTEM_BLOCK_SIZE);
|
||||
updateFat = TRUE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
map = fat[currentFat ^ 1];
|
||||
memset(map, 0, CARD_SYSTEM_BLOCK_SIZE);
|
||||
|
||||
for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) {
|
||||
CARDDir* ent;
|
||||
|
||||
ent = &card->currentDir[fileNo];
|
||||
if (ent->gameName[0] == 0xff) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (iBlock = ent->startBlock, cBlock = 0; iBlock != 0xFFFF && cBlock < ent->length;
|
||||
iBlock = card->currentFat[iBlock], ++cBlock)
|
||||
{
|
||||
if (!CARDIsValidBlockNo(card, iBlock) || 1 < ++map[iBlock]) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (cBlock != ent->length || iBlock != 0xFFFF) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
}
|
||||
|
||||
cFree = 0;
|
||||
for (iBlock = CARD_NUM_SYSTEM_BLOCK; iBlock < card->cBlock; iBlock++) {
|
||||
u16 nextBlock;
|
||||
|
||||
nextBlock = card->currentFat[iBlock];
|
||||
if (map[iBlock] == 0) {
|
||||
if (nextBlock != CARD_FAT_AVAIL) {
|
||||
card->currentFat[iBlock] = CARD_FAT_AVAIL;
|
||||
updateOrphan = TRUE;
|
||||
}
|
||||
cFree++;
|
||||
} else if (!CARDIsValidBlockNo(card, nextBlock) && nextBlock != 0xFFFF) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
}
|
||||
|
||||
if (cFree != card->currentFat[CARD_FAT_FREEBLOCKS]) {
|
||||
card->currentFat[CARD_FAT_FREEBLOCKS] = cFree;
|
||||
updateOrphan = TRUE;
|
||||
}
|
||||
|
||||
if (updateOrphan) {
|
||||
__CARDCheckSum(&card->currentFat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32),
|
||||
&card->currentFat[CARD_FAT_CHECKSUM],
|
||||
&card->currentFat[CARD_FAT_CHECKSUMINV]);
|
||||
}
|
||||
|
||||
memcpy(fat[currentFat ^ 1], fat[currentFat], CARD_SYSTEM_BLOCK_SIZE);
|
||||
|
||||
if (updateDir) {
|
||||
if (xferBytes) {
|
||||
*xferBytes = CARD_SYSTEM_BLOCK_SIZE;
|
||||
}
|
||||
return __CARDUpdateDir(chan, callback);
|
||||
}
|
||||
|
||||
if (updateFat | updateOrphan) {
|
||||
if (xferBytes) {
|
||||
*xferBytes = CARD_SYSTEM_BLOCK_SIZE;
|
||||
}
|
||||
return __CARDUpdateFatBlock(chan, card->currentFat, callback);
|
||||
}
|
||||
|
||||
__CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
if (callback) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
callback(chan, CARD_RESULT_READY);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
s32 CARDCheckAsync(s32 chan, CARDCallback callback) {
|
||||
s32 xferBytes;
|
||||
return CARDCheckExAsync(chan, &xferBytes, callback);
|
||||
}
|
||||
|
||||
s32 CARDCheckEx(s32 chan, s32* xferBytes) {
|
||||
s32 result = CARDCheckExAsync(chan, xferBytes, __CARDSyncCallback);
|
||||
if (result < 0 || xferBytes == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
s32 CARDCheck(s32 chan) {
|
||||
s32 xferBytes;
|
||||
return CARDCheckEx(chan, &xferBytes);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void CreateCallbackFat(s32 chan, s32 result);
|
||||
|
||||
static void CreateCallbackFat(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
|
||||
if (result >= 0) {
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[card->freeNo];
|
||||
memcpy(ent->gameName, card->diskID->gameName, sizeof(ent->gameName));
|
||||
memcpy(ent->company, card->diskID->company, sizeof(ent->company));
|
||||
ent->permission = 4;
|
||||
ent->copyTimes = 0;
|
||||
|
||||
ASSERTLINE(111, CARDIsValidBlockNo(card, card->startBlock));
|
||||
ent->startBlock = (u16)card->startBlock;
|
||||
ent->bannerFormat = 0;
|
||||
ent->iconAddr = -1;
|
||||
ent->iconFormat = 0;
|
||||
ent->iconSpeed = 0;
|
||||
ent->commentAddr = -1;
|
||||
|
||||
CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST);
|
||||
card->fileInfo->offset = 0;
|
||||
card->fileInfo->iBlock = ent->startBlock;
|
||||
ent->time = OSTicksToSeconds(OSGetTime());
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
if (result < 0) {
|
||||
goto after;
|
||||
}
|
||||
} else {
|
||||
after:;
|
||||
__CARDPutControlBlock(card, result);
|
||||
if (callback) {
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 CARDCreateAsync(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
u16 fileNo;
|
||||
u16 freeNo;
|
||||
u16* fat;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(175, 0 <= chan && chan < 2);
|
||||
ASSERTLINE(176, strlen(fileName) <= CARD_FILENAME_MAX);
|
||||
|
||||
if (strlen(fileName) > (u32)CARD_FILENAME_MAX) {
|
||||
return CARD_RESULT_NAMETOOLONG;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ASSERTLINE(188, 0 < size && (size % card->sectorSize) == 0);
|
||||
|
||||
if (size <= 0 || (size % card->sectorSize) != 0) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
freeNo = (u16)-1;
|
||||
dir = __CARDGetDirBlock(card);
|
||||
for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) {
|
||||
ent = &dir[fileNo];
|
||||
if (ent->gameName[0] == 0xff) {
|
||||
if (freeNo == (u16)-1) {
|
||||
freeNo = fileNo;
|
||||
}
|
||||
} else if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) == 0 &&
|
||||
memcmp(ent->company, card->diskID->company, sizeof(ent->company)) == 0 &&
|
||||
__CARDCompareFileName(ent, fileName)) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_EXIST);
|
||||
}
|
||||
}
|
||||
|
||||
if (freeNo == (u16)-1) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_NOENT);
|
||||
}
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
if (card->sectorSize * fat[CARD_FAT_FREEBLOCKS] < size) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_INSSPACE);
|
||||
}
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
card->freeNo = freeNo;
|
||||
ent = &dir[freeNo];
|
||||
ent->length = (u16)(size / card->sectorSize);
|
||||
strncpy((char*)ent->fileName, fileName, CARD_FILENAME_MAX);
|
||||
|
||||
card->fileInfo = fileInfo;
|
||||
fileInfo->chan = chan;
|
||||
fileInfo->fileNo = freeNo;
|
||||
|
||||
result = __CARDAllocBlock(chan, size / card->sectorSize, CreateCallbackFat);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDCreate(s32 chan, const char* fileName, u32 size, CARDFileInfo* fileInfo) {
|
||||
s32 result = CARDCreateAsync(chan, fileName, size, fileInfo, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void DeleteCallback(s32 chan, s32 result);
|
||||
|
||||
static void DeleteCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
result = __CARDFreeBlock(chan, card->startBlock, callback);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
return;
|
||||
|
||||
error:
|
||||
__CARDPutControlBlock(card, result);
|
||||
if (callback)
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(133, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
ASSERTLINE(134, 0 <= chan && chan < 2);
|
||||
|
||||
if (fileNo < 0 || CARD_MAX_FILE <= fileNo)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
|
||||
if (__CARDIsOpened(card, fileNo))
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BUSY);
|
||||
|
||||
card->startBlock = ent->startBlock;
|
||||
memset(ent, 0xff, sizeof(CARDDir));
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
result = __CARDUpdateDir(chan, DeleteCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDFastDelete(s32 chan, s32 fileNo) {
|
||||
s32 result = CARDFastDeleteAsync(chan, fileNo, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
s32 CARDDeleteAsync(s32 chan, const char* fileName, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 fileNo;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
result = __CARDGetFileNo(card, fileName, &fileNo);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
if (__CARDIsOpened(card, fileNo))
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BUSY);
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
card->startBlock = ent->startBlock;
|
||||
memset(ent, 0xff, sizeof(CARDDir));
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
result = __CARDUpdateDir(chan, DeleteCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDDelete(s32 chan, const char* fileName) {
|
||||
s32 result = CARDDeleteAsync(chan, fileName, __CARDSyncCallback);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void WriteCallback(s32 chan, s32 result);
|
||||
static void EraseCallback(s32 chan, s32 result);
|
||||
|
||||
CARDDir* __CARDGetDirBlock(CARDControl* card) {
|
||||
ASSERTLINE(54, card->currentDir);
|
||||
return card->currentDir;
|
||||
}
|
||||
|
||||
static void WriteCallback(s32 chan, s32 result) {
|
||||
CARDControl* card = &__CARDBlock[chan];
|
||||
CARDCallback callback;
|
||||
|
||||
if (result >= 0) {
|
||||
CARDDir* dir0 = (CARDDir*)((u8*)card->workArea + 0x2000);
|
||||
CARDDir* dir1 = (CARDDir*)((u8*)card->workArea + 0x4000);
|
||||
|
||||
ASSERTLINE(79, card->currentDir);
|
||||
|
||||
if (card->currentDir == dir0) {
|
||||
card->currentDir = dir1;
|
||||
memcpy(dir1, dir0, 0x2000);
|
||||
} else {
|
||||
ASSERTLINE(87, card->currentDir == dir1);
|
||||
card->currentDir = dir0;
|
||||
memcpy(dir0, dir1, 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
if (!card->apiCallback)
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
callback = card->eraseCallback;
|
||||
if (callback) {
|
||||
card->eraseCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void EraseCallback(s32 chan, s32 result) {
|
||||
CARDControl* card = &__CARDBlock[chan];
|
||||
CARDCallback callback;
|
||||
CARDDir* dir;
|
||||
u32 addr;
|
||||
|
||||
if (result >= 0) {
|
||||
dir = __CARDGetDirBlock(card);
|
||||
addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize;
|
||||
result = __CARDWrite(chan, addr, 0x2000, dir, WriteCallback);
|
||||
if (result >= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!card->apiCallback)
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
callback = card->eraseCallback;
|
||||
if (callback) {
|
||||
card->eraseCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDUpdateDir(s32 chan, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDirCheck* check;
|
||||
u32 addr;
|
||||
CARDDir* dir;
|
||||
|
||||
ASSERTLINE(173, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!card->attached)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
check = CARDGetDirCheck(dir);
|
||||
++check->checkCode;
|
||||
__CARDCheckSum(dir, 0x2000 - sizeof(u32), &check->checkSum, &check->checkSumInv);
|
||||
DCStoreRange(dir, 0x2000);
|
||||
|
||||
card->eraseCallback = callback;
|
||||
addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize;
|
||||
return __CARDEraseSector(chan, addr, EraseCallback);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
static void EraseCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u16* fat;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
CARDFileInfo* fileInfo;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
if (result >= 0) {
|
||||
fileInfo = card->fileInfo;
|
||||
if (fileInfo->length < 0) {
|
||||
result = CARD_RESULT_CANCELED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
fileInfo->length -= card->sectorSize;
|
||||
if (fileInfo->length <= 0) {
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = dir + fileInfo->fileNo;
|
||||
ent->time = OSTicksToSeconds(OSGetTime());
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
} else {
|
||||
fat = __CARDGetFatBlock(card);
|
||||
fileInfo->offset += card->sectorSize;
|
||||
fileInfo->iBlock = fat[fileInfo->iBlock];
|
||||
|
||||
if (fileInfo->iBlock < 5 || fileInfo->iBlock >= card->cBlock) {
|
||||
result = CARD_RESULT_BROKEN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = __CARDEraseSector(chan, card->sectorSize * fileInfo->iBlock, EraseCallback);
|
||||
}
|
||||
|
||||
if (result < 0) {
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
error:
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(98, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 CARDEraseAsync(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
ASSERTLINE(132, 0 < length);
|
||||
|
||||
result = __CARDSeek(fileInfo, length, offset, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ASSERTLINE(138, OFFSET(offset, card->sectorSize) == 0);
|
||||
ASSERTLINE(139, OFFSET(length, card->sectorSize) == 0);
|
||||
|
||||
if (OFFSET(offset, card->sectorSize) != 0 || OFFSET(length, card->sectorSize) != 0) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR);
|
||||
}
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = dir + fileInfo->fileNo;
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
|
||||
result = __CARDEraseSector(fileInfo->chan, card->sectorSize * fileInfo->iBlock, EraseCallback);
|
||||
if (result < 0) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDErase(CARDFileInfo* fileInfo, s32 length, s32 offset) {
|
||||
s32 result = CARDEraseAsync(fileInfo, length, offset, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(fileInfo->chan);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
#include "__card.h"
|
||||
|
||||
static void FormatCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
++card->formatStep;
|
||||
if (card->formatStep < CARD_NUM_SYSTEM_BLOCK) {
|
||||
result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback);
|
||||
if (result >= 0)
|
||||
return;
|
||||
} else if (card->formatStep < 2 * CARD_NUM_SYSTEM_BLOCK) {
|
||||
int step = card->formatStep - CARD_NUM_SYSTEM_BLOCK;
|
||||
result = __CARDWrite(chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE,
|
||||
(u8* )card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), FormatCallback);
|
||||
if (result >= 0)
|
||||
return;
|
||||
} else {
|
||||
card->currentDir = (CARDDir*)((u8*)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
memcpy(card->currentDir, (u8*)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE);
|
||||
card->currentFat = (u16*)((u8*)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
memcpy(card->currentFat, (u8*)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
error:
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(133, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDID* id;
|
||||
CARDDir* dir;
|
||||
u16* fat;
|
||||
s16 i;
|
||||
s32 result;
|
||||
OSSram* sram;
|
||||
OSSramEx* sramEx;
|
||||
u16 dvdstatus;
|
||||
OSTime time;
|
||||
OSTime rand;
|
||||
|
||||
ASSERTLINE(167, encode == CARD_ENCODE_ANSI || encode == CARD_ENCODE_SJIS);
|
||||
ASSERTLINE(168, 0 <= chan && chan < 2);
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
id = (CARDID*)card->workArea;
|
||||
memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE);
|
||||
dvdstatus = __VIRegs[55];
|
||||
|
||||
id->encode = encode;
|
||||
sram = __OSLockSram();
|
||||
*(u32*)&id->serial[20] = sram->counterBias;
|
||||
*(u32*)&id->serial[24] = sram->language;
|
||||
__OSUnlockSram(FALSE);
|
||||
|
||||
rand = time = OSGetTime();
|
||||
|
||||
sramEx = __OSLockSramEx();
|
||||
for (i = 0; i < 12; i++) {
|
||||
rand = (rand * 1103515245 + 12345) >> 16;
|
||||
id->serial[i] = (u8)(sramEx->flashID[chan][i] + rand);
|
||||
rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF;
|
||||
}
|
||||
__OSUnlockSramEx(FALSE);
|
||||
|
||||
*(u32*)&id->serial[28] = dvdstatus;
|
||||
*(OSTime*)&id->serial[12] = time;
|
||||
|
||||
id->deviceID = 0;
|
||||
id->size = card->size;
|
||||
__CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &id->checkSum, &id->checkSumInv);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
CARDDirCheck* check;
|
||||
|
||||
dir = (CARDDir*)((u8*)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
memset(dir, 0xff, CARD_SYSTEM_BLOCK_SIZE);
|
||||
check = CARDGetDirCheck(dir);
|
||||
check->checkCode = i;
|
||||
__CARDCheckSum(dir, CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &check->checkSum, &check->checkSumInv);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
fat = (u16*)((u8*)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE);
|
||||
memset(fat, 0x00, CARD_SYSTEM_BLOCK_SIZE);
|
||||
fat[CARD_FAT_CHECKCODE] = (u16)i;
|
||||
fat[CARD_FAT_FREEBLOCKS] = (u16)(card->cBlock - CARD_NUM_SYSTEM_BLOCK);
|
||||
fat[CARD_FAT_LASTSLOT] = CARD_NUM_SYSTEM_BLOCK - 1;
|
||||
__CARDCheckSum(&fat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &fat[CARD_FAT_CHECKSUM],
|
||||
&fat[CARD_FAT_CHECKSUMINV]);
|
||||
}
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
DCStoreRange(card->workArea, CARD_WORKAREA_SIZE);
|
||||
|
||||
card->formatStep = 0;
|
||||
result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDFormatRegion(s32 chan, u16 encode) {
|
||||
s32 result = __CARDFormatRegionAsync(chan, encode, &__CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
s32 CARDFormatAsync(s32 chan, CARDCallback callback) {
|
||||
return __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), callback);
|
||||
}
|
||||
|
||||
s32 CARDFormat(s32 chan) {
|
||||
s32 result = __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), &__CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
#include <dolphin/card.h>
|
||||
#include <dolphin/exi.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
#include "__card.h"
|
||||
|
||||
static u32 SectorSizeTable[8] = {
|
||||
8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024, 128 * 1024, 256 * 1024, 0, 0,
|
||||
};
|
||||
|
||||
static u32 LatencyTable[8] = {
|
||||
4, 8, 16, 32, 64, 128, 256, 512,
|
||||
};
|
||||
|
||||
// prototypes
|
||||
static s32 DoMount(s32 chan);
|
||||
static void DoUnmount(s32 chan, s32 result);
|
||||
|
||||
static BOOL IsCard(u32 id) {
|
||||
u32 size;
|
||||
s32 sectorSize;
|
||||
if (id & (0xFFFF0000) && (id != 0x80000004 || __CARDVendorID == 0xFFFF)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((id & 3) != 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
size = id & 0xfc;
|
||||
switch (size) {
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:
|
||||
case 64:
|
||||
case 128:
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
sectorSize = SectorSizeTable[(id & 0x00003800) >> 11];
|
||||
if (sectorSize == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if ((size * 1024 * 1024 / 8) / sectorSize < 8) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void __CARDDisable(BOOL disable) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
__gUnknown800030E3 &= ~0x80;
|
||||
if (disable) {
|
||||
__gUnknown800030E3 |= 0x80;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int CARDProbe(s32 chan) {
|
||||
if (__gUnknown800030E3 & 0x80) {
|
||||
return 0;
|
||||
} else {
|
||||
return EXIProbe(chan);
|
||||
}
|
||||
}
|
||||
|
||||
s32 CARDProbeEx(s32 chan, s32* memSize, s32* sectorSize) {
|
||||
u32 id;
|
||||
CARDControl* card;
|
||||
BOOL enabled;
|
||||
s32 result;
|
||||
int probe;
|
||||
|
||||
if (chan < 0 || 2 <= chan)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
if (__gUnknown800030E3 & 0x80) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
probe = EXIProbeEx(chan);
|
||||
if (probe == -1)
|
||||
result = CARD_RESULT_NOCARD;
|
||||
else if (probe == 0)
|
||||
result = CARD_RESULT_BUSY;
|
||||
else if (card->attached) {
|
||||
if (card->mountStep < 1)
|
||||
result = CARD_RESULT_BUSY;
|
||||
else {
|
||||
if (memSize)
|
||||
*memSize = card->size;
|
||||
|
||||
if (sectorSize)
|
||||
*sectorSize = card->sectorSize;
|
||||
|
||||
result = CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
else if ((EXIGetState(chan) & 8))
|
||||
result = CARD_RESULT_WRONGDEVICE;
|
||||
else if (!EXIGetID(chan, 0, &id))
|
||||
result = CARD_RESULT_BUSY;
|
||||
else if (IsCard(id)) {
|
||||
if (memSize)
|
||||
*memSize = (s32)(id & 0xfc);
|
||||
|
||||
if (sectorSize)
|
||||
*sectorSize = SectorSizeTable[(id & 0x00003800) >> 11];
|
||||
result = CARD_RESULT_READY;
|
||||
} else {
|
||||
result = CARD_RESULT_WRONGDEVICE;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
|
||||
static s32 DoMount(s32 chan) {
|
||||
CARDControl* card;
|
||||
u32 id;
|
||||
u8 status;
|
||||
s32 result;
|
||||
OSSramEx* sram;
|
||||
int i;
|
||||
u8 checkSum;
|
||||
int step;
|
||||
|
||||
ASSERTLINE(399, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (card->mountStep == 0) {
|
||||
if (EXIGetID(chan, 0, &id) == 0) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
} else if (IsCard(id)) {
|
||||
result = CARD_RESULT_READY;
|
||||
} else {
|
||||
result = CARD_RESULT_WRONGDEVICE;
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
card->cid = id;
|
||||
card->size = (u16)(id & 0xFC);
|
||||
ASSERTLINE(424, card->size);
|
||||
|
||||
card->sectorSize = SectorSizeTable[(id & 0x00003800) >> 11];
|
||||
ASSERTLINE(426, card->sectorSize);
|
||||
|
||||
card->cBlock = (u16)((card->size * 1024 * 1024 / 8) / card->sectorSize);
|
||||
ASSERTLINE(428, 8 <= card->cBlock);
|
||||
|
||||
card->latency = LatencyTable[(id & 0x00000700) >> 8];
|
||||
|
||||
result = __CARDReadVendorID(chan, &card->vendorID);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
if (CARDGetFastMode() && (card->vendorID >> 8) == 0xEC) {
|
||||
card->pageSize = 512;
|
||||
} else {
|
||||
card->pageSize = 128;
|
||||
}
|
||||
|
||||
result = __CARDClearStatus(chan);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
result = __CARDReadStatus(chan, &status);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
if (!EXIProbe(chan)) {
|
||||
result = CARD_RESULT_NOCARD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(status & 0x40)) {
|
||||
result = __CARDUnlock(chan, card->id);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
checkSum = 0;
|
||||
sram = __OSLockSramEx();
|
||||
for (i = 0; i < 12; i++) {
|
||||
sram->flashID[chan][i] = card->id[i];
|
||||
checkSum += card->id[i];
|
||||
}
|
||||
sram->flashIDCheckSum[chan] = (u8)~checkSum;
|
||||
__OSUnlockSramEx(TRUE);
|
||||
|
||||
return result;
|
||||
} else {
|
||||
card->mountStep = 1;
|
||||
|
||||
checkSum = 0;
|
||||
sram = __OSLockSramEx();
|
||||
for (i = 0; i < 12; i++)
|
||||
checkSum += sram->flashID[chan][i];
|
||||
|
||||
__OSUnlockSramEx(FALSE);
|
||||
if (sram->flashIDCheckSum[chan] != (u8)~checkSum) {
|
||||
result = CARD_RESULT_IOERROR;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (card->mountStep == 1) {
|
||||
if (card->cid == 0x80000004) {
|
||||
u16 vendorID;
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
vendorID = *(u16*)sram->flashID[chan];
|
||||
__OSUnlockSramEx(FALSE);
|
||||
|
||||
if (__CARDVendorID == 0xFFFF || vendorID != __CARDVendorID) {
|
||||
result = CARD_RESULT_WRONGDEVICE;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
card->mountStep = 2;
|
||||
|
||||
result = __CARDEnableInterrupt(chan, TRUE);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
EXISetExiCallback(chan, __CARDExiHandler);
|
||||
EXIUnlock(chan);
|
||||
DCInvalidateRange(card->workArea, CARD_WORKAREA_SIZE);
|
||||
}
|
||||
|
||||
step = card->mountStep - 2;
|
||||
result = __CARDRead(chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE,
|
||||
(u8 *)card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), __CARDMountCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
|
||||
error:
|
||||
EXIUnlock(chan);
|
||||
DoUnmount(chan, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void __CARDMountCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
ASSERTLINE(570, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
switch (result) {
|
||||
case CARD_RESULT_READY:
|
||||
if (++card->mountStep < CARD_MAX_MOUNT_STEP) {
|
||||
result = DoMount(chan);
|
||||
if (0 <= result)
|
||||
return;
|
||||
} else
|
||||
result = __CARDVerify(card);
|
||||
break;
|
||||
case CARD_RESULT_UNLOCKED:
|
||||
card->unlockCallback = __CARDMountCallback;
|
||||
if (!EXILock(chan, 0, __CARDUnlockedHandler)) {
|
||||
return;
|
||||
}
|
||||
card->unlockCallback = 0;
|
||||
|
||||
result = DoMount(chan);
|
||||
if (result >= 0)
|
||||
return;
|
||||
break;
|
||||
case CARD_RESULT_IOERROR:
|
||||
case CARD_RESULT_NOCARD:
|
||||
DoUnmount(chan, result);
|
||||
break;
|
||||
}
|
||||
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(620, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 CARDMountAsync(s32 chan, void* workArea, CARDCallback detachCallback, CARDCallback attachCallback) {
|
||||
CARDControl* card;
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTLINE(652, workArea && ((u32) workArea % 32 == 0));
|
||||
ASSERTLINE(653, 0 <= chan && chan < 2);
|
||||
|
||||
if (chan < 0 || 2 <= chan)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
if (__gUnknown800030E3 & 0x80) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
if (card->result == CARD_RESULT_BUSY) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return CARD_RESULT_BUSY;
|
||||
}
|
||||
|
||||
if (!card->attached && (EXIGetState(chan) & 0x08)) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return CARD_RESULT_WRONGDEVICE;
|
||||
}
|
||||
|
||||
card->result = CARD_RESULT_BUSY;
|
||||
card->workArea = workArea;
|
||||
card->extCallback = detachCallback;
|
||||
card->apiCallback = attachCallback ? attachCallback : __CARDDefaultApiCallback;
|
||||
card->exiCallback = 0;
|
||||
|
||||
if (!card->attached && !EXIAttach(chan, __CARDExtHandler)) {
|
||||
card->result = CARD_RESULT_NOCARD;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
|
||||
card->mountStep = 0;
|
||||
card->attached = TRUE;
|
||||
EXISetExiCallback(chan, 0);
|
||||
OSCancelAlarm(&card->alarm);
|
||||
|
||||
card->currentDir = 0;
|
||||
card->currentFat = 0;
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
card->unlockCallback = __CARDMountCallback;
|
||||
if (!EXILock(chan, 0, __CARDUnlockedHandler))
|
||||
return CARD_RESULT_READY;
|
||||
|
||||
card->unlockCallback = 0;
|
||||
return DoMount(chan);
|
||||
}
|
||||
|
||||
s32 CARDMount(s32 chan, void* workArea, CARDCallback detachCallback) {
|
||||
s32 result = CARDMountAsync(chan, workArea, detachCallback, __CARDSyncCallback);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
static void DoUnmount(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTLINE(758, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
enabled = OSDisableInterrupts();
|
||||
if (card->attached) {
|
||||
EXISetExiCallback(chan, 0);
|
||||
EXIDetach(chan);
|
||||
OSCancelAlarm(&card->alarm);
|
||||
card->attached = FALSE;
|
||||
card->result = result;
|
||||
card->mountStep = 0;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
s32 CARDUnmount(s32 chan) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(793, 0 <= chan && chan < 2);
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
DoUnmount(chan, CARD_RESULT_NOCARD);
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "os/__os.h"
|
||||
#include "__card.h"
|
||||
|
||||
u16 __CARDVendorID = 0xFFFF;
|
||||
u8 __CARDPermMask = 0x1C;
|
||||
|
||||
u16 CARDSetVendorID(u16 vendorID) {
|
||||
u16 prevID = __CARDVendorID;
|
||||
__CARDVendorID = vendorID;
|
||||
|
||||
return prevID;
|
||||
}
|
||||
|
||||
u16 CARDGetVendorID() {
|
||||
return __CARDVendorID;
|
||||
}
|
||||
|
||||
s32 CARDGetSerialNo(s32 chan, u64* serialNo) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
CARDID* id;
|
||||
u64 code;
|
||||
int i;
|
||||
|
||||
ASSERTLINE(105, 0 <= chan && chan < 2);
|
||||
|
||||
if (!(0 <= chan && chan < 2)) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
id = (CARDID*)card->workArea;
|
||||
for (code = 0, i = 0; i < sizeof(id->serial) / sizeof(u64); ++i) {
|
||||
code ^= *(u64*)&id->serial[sizeof(u64) * i];
|
||||
}
|
||||
*serialNo = code;
|
||||
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 CARDGetUniqueCode(s32 chan, u64* uniqueCode) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
OSSramEx* sram;
|
||||
|
||||
ASSERTLINE(146, 0 <= chan && chan < 2);
|
||||
|
||||
if (!(0 <= chan && chan < 2)) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
sram = __OSLockSramEx();
|
||||
memcpy(uniqueCode, &sram->flashID[chan][4], 8);
|
||||
__OSUnlockSramEx(0);
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
s32 CARDGetAttributes(s32 chan, s32 fileNo, u8* attr) {
|
||||
CARDDir dirent;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetStatusEx(chan, fileNo, &dirent);
|
||||
if (result == 0) {
|
||||
*attr = dirent.permission;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CARDCheckAttr(attr, flag) ((u32)(attr & flag) != 0)
|
||||
|
||||
s32 CARDSetAttributesAsync(s32 chan, s32 fileNo, u8 attr, CARDCallback callback) {
|
||||
CARDDir dirent;
|
||||
s32 result;
|
||||
|
||||
if (attr & ~__CARDPermMask) {
|
||||
return CARD_RESULT_NOPERM;
|
||||
}
|
||||
|
||||
result = __CARDGetStatusEx(chan, fileNo, &dirent);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((CARDCheckAttr(dirent.permission, 0x20) && !CARDCheckAttr(attr, 0x20)) || (CARDCheckAttr(dirent.permission, 0x40) && !CARDCheckAttr(attr, 0x40))) {
|
||||
return CARD_RESULT_NOPERM;
|
||||
}
|
||||
|
||||
if ((CARDCheckAttr(attr, 0x20) && CARDCheckAttr(attr, 0x40)) || (CARDCheckAttr(attr, 0x20) && CARDCheckAttr(dirent.permission, 0x40)) || (CARDCheckAttr(attr, 0x40) && CARDCheckAttr(dirent.permission, 0x20))) {
|
||||
return CARD_RESULT_NOPERM;
|
||||
}
|
||||
|
||||
dirent.permission = attr;
|
||||
return __CARDSetStatusExAsync(chan, fileNo, &dirent, callback);
|
||||
}
|
||||
|
||||
s32 CARDSetAttributes(s32 chan, s32 fileNo, u8 attr) {
|
||||
s32 result;
|
||||
|
||||
result = CARDSetAttributesAsync(chan, fileNo, attr, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
static int __CARDEnablePerm(u8 perm, BOOL enable) {
|
||||
int prev;
|
||||
prev = __CARDPermMask & perm ? TRUE : FALSE;
|
||||
|
||||
if (enable) {
|
||||
__CARDPermMask |= perm;
|
||||
} else {
|
||||
__CARDPermMask &= ~perm;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
int __CARDEnableGlobal(BOOL enable) {
|
||||
return __CARDEnablePerm(0x20, enable);
|
||||
}
|
||||
|
||||
int __CARDEnableCompany(BOOL enable) {
|
||||
return __CARDEnablePerm(0x40, enable);
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
BOOL __CARDCompareFileName(CARDDir* ent, const char* fileName) {
|
||||
char* entName = (char*)ent->fileName;
|
||||
char c1;
|
||||
char c2;
|
||||
int n = CARD_FILENAME_MAX;
|
||||
|
||||
while (--n >= 0) {
|
||||
if ((c1 = *entName++) != (c2 = *fileName++))
|
||||
return FALSE;
|
||||
else if (c2 == '\0')
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (*fileName == '\0')
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s32 __CARDAccess(CARDControl* card, CARDDir* ent) {
|
||||
const DVDDiskID* diskID = card->diskID;
|
||||
|
||||
if (ent->gameName[0] == 0xFF)
|
||||
return CARD_RESULT_NOFILE;
|
||||
|
||||
if (diskID == &__CARDDiskNone
|
||||
|| (memcmp(ent->gameName, diskID->gameName, sizeof(ent->gameName)) == 0
|
||||
&& memcmp(ent->company, diskID->company, sizeof(ent->company)) == 0))
|
||||
return CARD_RESULT_READY;
|
||||
|
||||
return CARD_RESULT_NOPERM;
|
||||
}
|
||||
|
||||
s32 __CARDIsWritable(CARDControl* card, CARDDir* ent) {
|
||||
const DVDDiskID* diskID = card->diskID;
|
||||
s32 result;
|
||||
u8 perm;
|
||||
|
||||
result = __CARDAccess(card, ent);
|
||||
if (result == CARD_RESULT_NOPERM) {
|
||||
perm = ent->permission & __CARDPermMask;
|
||||
if (perm & 0x20 && (memcmp(ent->gameName, __CARDDiskNone.gameName, sizeof(ent->gameName)) == 0 &&
|
||||
memcmp(ent->company, __CARDDiskNone.company, sizeof(ent->company)) == 0))
|
||||
{
|
||||
return CARD_RESULT_READY;
|
||||
} else if (perm & 0x40 && (memcmp(ent->gameName, __CARDDiskNone.gameName, sizeof(ent->gameName)) == 0 &&
|
||||
memcmp(ent->company, diskID->company, sizeof(ent->company)) == 0))
|
||||
{
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDIsReadable(CARDControl* card, CARDDir* ent) {
|
||||
s32 result = __CARDIsWritable(card, ent);
|
||||
if (result == CARD_RESULT_NOPERM && (ent->permission & 0x4)) {
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDGetFileNo(CARDControl* card, const char* fileName, s32* pfileNo) {
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 fileNo;
|
||||
s32 result;
|
||||
|
||||
if (!card->attached)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) {
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDAccess(card, ent);
|
||||
|
||||
if (result < 0)
|
||||
continue;
|
||||
if (__CARDCompareFileName(ent, fileName)) {
|
||||
*pfileNo = fileNo;
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
}
|
||||
|
||||
return CARD_RESULT_NOFILE;
|
||||
}
|
||||
|
||||
s32 CARDFastOpen(s32 chan, s32 fileNo, CARDFileInfo* fileInfo) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(278, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
ASSERTLINE(279, 0 <= chan && chan < 2);
|
||||
|
||||
if (fileNo < 0 || fileNo >= CARD_MAX_FILE)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
fileInfo->chan = -1;
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsReadable(card, ent);
|
||||
if (0 <= result) {
|
||||
if (!CARDIsValidBlockNo(card, ent->startBlock))
|
||||
result = CARD_RESULT_BROKEN;
|
||||
else {
|
||||
fileInfo->chan = chan;
|
||||
fileInfo->fileNo = fileNo;
|
||||
fileInfo->offset = 0;
|
||||
fileInfo->iBlock = ent->startBlock;
|
||||
}
|
||||
}
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
s32 CARDOpen(s32 chan, const char* fileName, CARDFileInfo* fileInfo) {
|
||||
CARDControl* card;
|
||||
s32 fileNo;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
ASSERTLINE(336, 0 <= chan && chan < 2);
|
||||
|
||||
fileInfo->chan = -1;
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
result = __CARDGetFileNo(card, fileName, &fileNo);
|
||||
if (result >= 0) {
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
if (!CARDIsValidBlockNo(card, ent->startBlock))
|
||||
result = CARD_RESULT_BROKEN;
|
||||
else {
|
||||
fileInfo->chan = chan;
|
||||
fileInfo->fileNo = fileNo;
|
||||
fileInfo->offset = 0;
|
||||
fileInfo->iBlock = ent->startBlock;
|
||||
}
|
||||
}
|
||||
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
s32 CARDClose(CARDFileInfo* fileInfo) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(380, 0 <= fileInfo->chan && fileInfo->chan < 2);
|
||||
ASSERTLINE(381, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE);
|
||||
|
||||
result = __CARDGetControlBlock(fileInfo->chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
fileInfo->chan = -1;
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_READY);
|
||||
}
|
||||
|
||||
BOOL __CARDIsOpened(CARDControl* card, s32 fileNo) {
|
||||
return FALSE;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
#define CARD_PROGRAM_SIZE 128
|
||||
|
||||
static void ProgramCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u16* fat;
|
||||
CARDFileInfo* fileInfo;
|
||||
s32 length;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
if (result >= 0) {
|
||||
fileInfo = card->fileInfo;
|
||||
if (fileInfo->length < 0) {
|
||||
result = CARD_RESULT_CANCELED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
length = TRUNC(fileInfo->offset + card->sectorSize, card->sectorSize) - fileInfo->offset;
|
||||
fileInfo->length -= length;
|
||||
if (fileInfo->length > 0) {
|
||||
fat = __CARDGetFatBlock(card);
|
||||
fileInfo->offset += length;
|
||||
fileInfo->iBlock = fat[fileInfo->iBlock];
|
||||
|
||||
if (fileInfo->iBlock < 5 || fileInfo->iBlock >= card->cBlock) {
|
||||
result = CARD_RESULT_BROKEN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ASSERTLINE(94, OFFSET(fileInfo->length, CARD_PROGRAM_SIZE) == 0);
|
||||
ASSERTLINE(95, OFFSET(fileInfo->offset, card->sectorSize) == 0);
|
||||
|
||||
result = __CARDWrite(chan, card->sectorSize * fileInfo->iBlock, fileInfo->length < card->sectorSize ? fileInfo->length : card->sectorSize, card->buffer, ProgramCallback);
|
||||
if (result >= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(114, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 CARDProgramAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
ASSERTLINE(147, buf && OFFSET(buf, 32) == 0);
|
||||
ASSERTLINE(148, OFFSET(offset, CARD_PROGRAM_SIZE) == 0);
|
||||
ASSERTLINE(149, 0 < length && OFFSET(length, CARD_PROGRAM_SIZE) == 0);
|
||||
|
||||
if (offset & 0x7F || length & 0x7F) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
result = __CARDSeek(fileInfo, length, offset, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileInfo->fileNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
DCStoreRange(buf, length);
|
||||
|
||||
card->apiCallback = callback ? callback : &__CARDDefaultApiCallback;
|
||||
offset = fileInfo->offset & (card->sectorSize - 1);
|
||||
length = length < (card->sectorSize - offset) ? length : card->sectorSize - offset;
|
||||
|
||||
result = __CARDWrite(fileInfo->chan, offset + (card->sectorSize * fileInfo->iBlock), length, buf, ProgramCallback);
|
||||
if (result < 0) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDProgram(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) {
|
||||
s32 result = CARDProgramAsync(fileInfo, buf, length, offset, __CARDSyncCallback);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return __CARDSync(fileInfo->chan);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
s32 __CARDRawReadAsync(s32 chan, void* buf, s32 length, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(59, buf && ((u32) buf % 32) == 0);
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
ASSERTLINE(67, 0 < length && (length % CARD_SEG_SIZE) == 0 && length < CARD_MAX_SIZE);
|
||||
ASSERTLINE(68, (offset % card->sectorSize) == 0);
|
||||
|
||||
DCInvalidateRange(buf, length);
|
||||
result = __CARDRead(chan, offset, length, buf, callback);
|
||||
if (result < 0) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDRawRead(s32 chan, void* buf, s32 length, s32 offset) {
|
||||
s32 result = __CARDRawReadAsync(chan, buf, length, offset, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
|
||||
static void EraseCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
ASSERTLINE(117, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 __CARDRawEraseAsync(s32 chan, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
if (offset % card->sectorSize) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR);
|
||||
}
|
||||
|
||||
if ((card->size * 1024 * 1024) / 8 <= offset) {
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_LIMIT);
|
||||
}
|
||||
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
result = __CARDEraseSector(chan, offset, EraseCallback);
|
||||
if (result < 0) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDRawErase(s32 chan, s32 offset) {
|
||||
s32 result = __CARDRawEraseAsync(chan, offset, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void BlockReadCallback(s32 chan, s32 result);
|
||||
static void BlockWriteCallback(s32 chan, s32 result);
|
||||
|
||||
static void BlockReadCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
if ((result >= 0)) {
|
||||
card->xferred += 0x200;
|
||||
card->addr += 0x200;
|
||||
((u8*)card->buffer) += 0x200;
|
||||
|
||||
if (--card->repeat > 0) {
|
||||
result = __CARDReadSegment(chan, BlockReadCallback);
|
||||
if (result >= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!card->apiCallback) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
callback = card->xferCallback;
|
||||
if (callback) {
|
||||
card->xferCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDRead(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
|
||||
ASSERTLINE(91, 0 < length && length % CARD_SEG_SIZE == 0);
|
||||
ASSERTLINE(92, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (card->attached == 0) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
card->xferCallback = callback;
|
||||
card->repeat = (length / 512u);
|
||||
card->addr = addr;
|
||||
card->buffer = dst;
|
||||
return __CARDReadSegment(chan, BlockReadCallback);
|
||||
}
|
||||
|
||||
static void BlockWriteCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result >= 0) {
|
||||
card->xferred += card->pageSize;
|
||||
card->addr += card->pageSize;
|
||||
((u8*)card->buffer) += card->pageSize;
|
||||
|
||||
if (--card->repeat > 0) {
|
||||
result = __CARDWritePage(chan, BlockWriteCallback);
|
||||
if (result >= 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!card->apiCallback) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
callback = card->xferCallback;
|
||||
if (callback) {
|
||||
card->xferCallback = NULL;
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDWrite(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
card = &__CARDBlock[chan];
|
||||
|
||||
ASSERTLINE(153, 0 < length && length % card->pageSize == 0);
|
||||
ASSERTLINE(154, 0 <= chan && chan < 2);
|
||||
|
||||
if (card->attached == 0) {
|
||||
return CARD_RESULT_NOCARD;
|
||||
}
|
||||
card->xferCallback = callback;
|
||||
card->repeat = (length / card->pageSize);
|
||||
card->addr = addr;
|
||||
card->buffer = dst;
|
||||
return __CARDWritePage(chan, BlockWriteCallback);
|
||||
}
|
||||
|
||||
s32 CARDGetXferredBytes(s32 chan) {
|
||||
ASSERTLINE(183, 0 <= chan && chan < 2);
|
||||
return __CARDBlock[chan].xferred;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
#define TRUNC(n, a) (((u32)(n)) & ~((a)-1))
|
||||
|
||||
// prototypes
|
||||
static void ReadCallback(s32 chan, s32 result);
|
||||
|
||||
s32 __CARDSeek(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDControl** pcard) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
u16* fat;
|
||||
|
||||
ASSERTLINE(98, 0 <= fileInfo->chan && fileInfo->chan < 2);
|
||||
ASSERTLINE(99, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE);
|
||||
|
||||
result = __CARDGetControlBlock(fileInfo->chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
ASSERTLINE(106, CARDIsValidBlockNo(card, fileInfo->iBlock));
|
||||
ASSERTLINE(107, fileInfo->offset < card->cBlock * card->sectorSize);
|
||||
|
||||
if (!CARDIsValidBlockNo(card, fileInfo->iBlock) || card->cBlock * card->sectorSize <= fileInfo->offset)
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR);
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileInfo->fileNo];
|
||||
|
||||
ASSERTLINE(117, ent->gameName[0] != 0xff);
|
||||
|
||||
if (ent->length * card->sectorSize <= offset || ent->length * card->sectorSize < offset + length)
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_LIMIT);
|
||||
|
||||
card->fileInfo = fileInfo;
|
||||
fileInfo->length = length;
|
||||
if (offset < fileInfo->offset) {
|
||||
fileInfo->offset = 0;
|
||||
fileInfo->iBlock = ent->startBlock;
|
||||
if (!CARDIsValidBlockNo(card, fileInfo->iBlock))
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
while (fileInfo->offset < TRUNC(offset, card->sectorSize)) {
|
||||
fileInfo->offset += card->sectorSize;
|
||||
fileInfo->iBlock = fat[fileInfo->iBlock];
|
||||
if (!CARDIsValidBlockNo(card, fileInfo->iBlock))
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_BROKEN);
|
||||
}
|
||||
|
||||
fileInfo->offset = offset;
|
||||
|
||||
*pcard = card;
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static void ReadCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u16* fat;
|
||||
CARDFileInfo* fileInfo;
|
||||
s32 length;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
fileInfo = card->fileInfo;
|
||||
if (fileInfo->length < 0) {
|
||||
result = CARD_RESULT_CANCELED;
|
||||
goto error;
|
||||
}
|
||||
|
||||
length = TRUNC(fileInfo->offset + card->sectorSize, card->sectorSize) - fileInfo->offset;
|
||||
fileInfo->length -= length;
|
||||
if (fileInfo->length <= 0)
|
||||
goto error;
|
||||
|
||||
fat = __CARDGetFatBlock(card);
|
||||
fileInfo->offset += length;
|
||||
fileInfo->iBlock = fat[fileInfo->iBlock];
|
||||
if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) {
|
||||
result = CARD_RESULT_BROKEN;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ASSERTLINE(199, OFFSET(fileInfo->length, CARD_SEG_SIZE) == 0);
|
||||
ASSERTLINE(200, OFFSET(fileInfo->offset, card->sectorSize) == 0);
|
||||
|
||||
result = __CARDRead(chan, card->sectorSize * (u32)fileInfo->iBlock,
|
||||
(fileInfo->length < card->sectorSize) ? fileInfo->length : card->sectorSize, card->buffer,
|
||||
ReadCallback);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(217, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
|
||||
s32 CARDReadAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
ASSERTLINE(250, buf && OFFSET(buf, 32) == 0);
|
||||
ASSERTLINE(251, OFFSET(offset, CARD_SEG_SIZE) == 0);
|
||||
ASSERTLINE(252, 0 < length && OFFSET(length, CARD_SEG_SIZE) == 0);
|
||||
|
||||
if (OFFSET(offset, CARD_SEG_SIZE) != 0 || OFFSET(length, CARD_SEG_SIZE) != 0)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
result = __CARDSeek(fileInfo, length, offset, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileInfo->fileNo];
|
||||
result = __CARDIsReadable(card, ent);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
|
||||
DCInvalidateRange(buf, (u32)length);
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
|
||||
offset = (s32)OFFSET(fileInfo->offset, card->sectorSize);
|
||||
length = (length < card->sectorSize - offset) ? length : card->sectorSize - offset;
|
||||
result = __CARDRead(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock + offset, length, buf, ReadCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDRead(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) {
|
||||
s32 result = CARDReadAsync(fileInfo, buf, length, offset, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(fileInfo->chan);
|
||||
}
|
||||
|
||||
s32 CARDCancel(CARDFileInfo* fileInfo) {
|
||||
BOOL enabled;
|
||||
s32 result;
|
||||
CARDControl* card;
|
||||
|
||||
ASSERTLINE(338, 0 <= fileInfo->chan && fileInfo->chan < 2);
|
||||
ASSERTLINE(339, 0 <= fileInfo->fileNo && fileInfo->fileNo < CARD_MAX_FILE);
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
card = &__CARDBlock[fileInfo->chan];
|
||||
result = CARD_RESULT_READY;
|
||||
if (!card->attached)
|
||||
result = CARD_RESULT_NOCARD;
|
||||
else if (card->result == CARD_RESULT_BUSY && card->fileInfo == fileInfo) {
|
||||
fileInfo->length = -1;
|
||||
result = CARD_RESULT_CANCELED;
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
s32 CARDRenameAsync(s32 chan, const char* old, const char* new, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
int fileNo;
|
||||
int newNo;
|
||||
int oldNo;
|
||||
|
||||
ASSERTLINE(0x56, 0 <= chan && chan < 2);
|
||||
ASSERTLINE(0x57, *old != 0xff && *new != 0xff);
|
||||
ASSERTLINE(0x58, *old != 0x00 && *new != 0x00);
|
||||
|
||||
if (old[0] == 0xFF || new[0] == 0xFF || old[0] == 0 || new[0] == 0)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
if (CARD_FILENAME_MAX < (u32)strlen(old) || CARD_FILENAME_MAX < (u32)strlen(new))
|
||||
return CARD_RESULT_NAMETOOLONG;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
newNo = oldNo = -1;
|
||||
dir = __CARDGetDirBlock(card);
|
||||
for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) {
|
||||
ent = &dir[fileNo];
|
||||
if (ent->gameName[0] == 0xFF)
|
||||
continue;
|
||||
|
||||
if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) != 0
|
||||
|| memcmp(ent->company, card->diskID->company, sizeof(ent->company)) != 0)
|
||||
continue;
|
||||
|
||||
if (__CARDCompareFileName(ent, old))
|
||||
oldNo = fileNo;
|
||||
if (__CARDCompareFileName(ent, new))
|
||||
newNo = fileNo;
|
||||
}
|
||||
|
||||
if (oldNo == -1)
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_NOFILE);
|
||||
if (newNo != -1)
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_EXIST);
|
||||
|
||||
ent = &dir[oldNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
|
||||
strncpy((char*)ent->fileName, new, CARD_FILENAME_MAX);
|
||||
ent->time = (u32)OSTicksToSeconds(OSGetTime());
|
||||
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDRename(s32 chan, const char* old, const char* new) {
|
||||
s32 result = CARDRenameAsync(chan, old, new, __CARDSyncCallback);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
static void UpdateIconOffsets(CARDDir* ent, CARDStat* stat) {
|
||||
u32 offset;
|
||||
BOOL iconTlut;
|
||||
int i;
|
||||
|
||||
offset = ent->iconAddr;
|
||||
if (offset == 0xffffffff) {
|
||||
stat->bannerFormat = 0;
|
||||
stat->iconFormat = 0;
|
||||
stat->iconSpeed = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
iconTlut = FALSE;
|
||||
switch (CARDGetBannerFormat(ent)) {
|
||||
case CARD_STAT_BANNER_C8:
|
||||
stat->offsetBanner = offset;
|
||||
offset += CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
|
||||
stat->offsetBannerTlut = offset;
|
||||
offset += 2 * 256;
|
||||
break;
|
||||
case CARD_STAT_BANNER_RGB5A3:
|
||||
stat->offsetBanner = offset;
|
||||
offset += 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT;
|
||||
stat->offsetBannerTlut = 0xffffffff;
|
||||
break;
|
||||
default:
|
||||
stat->offsetBanner = 0xffffffff;
|
||||
stat->offsetBannerTlut = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < CARD_ICON_MAX; ++i) {
|
||||
switch (CARDGetIconFormat(ent, i)) {
|
||||
case CARD_STAT_ICON_C8:
|
||||
stat->offsetIcon[i] = offset;
|
||||
offset += CARD_ICON_WIDTH * CARD_ICON_HEIGHT;
|
||||
iconTlut = TRUE;
|
||||
break;
|
||||
case CARD_STAT_ICON_RGB5A3:
|
||||
stat->offsetIcon[i] = offset;
|
||||
offset += 2 * CARD_ICON_WIDTH * CARD_ICON_HEIGHT;
|
||||
break;
|
||||
default:
|
||||
stat->offsetIcon[i] = 0xffffffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iconTlut) {
|
||||
stat->offsetIconTlut = offset;
|
||||
offset += 2 * 256;
|
||||
} else {
|
||||
stat->offsetIconTlut = 0xffffffff;
|
||||
}
|
||||
stat->offsetData = offset;
|
||||
}
|
||||
|
||||
s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat* stat) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(172, 0 <= chan && chan < 2);
|
||||
ASSERTLINE(173, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
|
||||
if (fileNo < 0 || CARD_MAX_FILE <= fileNo)
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsReadable(card, ent);
|
||||
|
||||
if (result >= 0) {
|
||||
memcpy(stat->gameName, ent->gameName, sizeof(stat->gameName));
|
||||
memcpy(stat->company, ent->company, sizeof(stat->company));
|
||||
stat->length = (u32)ent->length * card->sectorSize;
|
||||
memcpy(stat->fileName, ent->fileName, CARD_FILENAME_MAX);
|
||||
stat->time = ent->time;
|
||||
|
||||
stat->bannerFormat = ent->bannerFormat;
|
||||
stat->iconAddr = ent->iconAddr;
|
||||
stat->iconFormat = ent->iconFormat;
|
||||
stat->iconSpeed = ent->iconSpeed;
|
||||
stat->commentAddr = ent->commentAddr;
|
||||
|
||||
UpdateIconOffsets(ent, stat);
|
||||
}
|
||||
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat* stat, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
|
||||
ASSERTLINE(231, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
ASSERTLINE(232, 0 <= chan && chan < 2);
|
||||
ASSERTMSGLINE(240, stat->iconAddr == 0xffffffff || stat->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE.");
|
||||
ASSERTMSGLINE(243, stat->commentAddr == 0xffffffff || (stat->commentAddr & 0x1FFF) <= 8128, "CARDSetStatus[Async](): comment strings (set by stat->commentAddr) must not cross 8KB byte boundary.");
|
||||
|
||||
if (fileNo < 0 || CARD_MAX_FILE <= fileNo ||
|
||||
(stat->iconAddr != 0xffffffff && CARD_READ_SIZE <= stat->iconAddr) ||
|
||||
(stat->commentAddr != 0xffffffff &&
|
||||
CARD_SYSTEM_BLOCK_SIZE - CARD_COMMENT_SIZE < stat->commentAddr % CARD_SYSTEM_BLOCK_SIZE))
|
||||
{
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
|
||||
ent->bannerFormat = stat->bannerFormat;
|
||||
ent->iconAddr = stat->iconAddr;
|
||||
ent->iconFormat = stat->iconFormat;
|
||||
ent->iconSpeed = stat->iconSpeed;
|
||||
ent->commentAddr = stat->commentAddr;
|
||||
UpdateIconOffsets(ent, stat);
|
||||
|
||||
if (ent->iconAddr == 0xffffffff) {
|
||||
CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST);
|
||||
}
|
||||
|
||||
ent->time = (u32)OSTicksToSeconds(OSGetTime());
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat* stat) {
|
||||
s32 result = CARDSetStatusAsync(chan, fileNo, stat, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
s32 __CARDGetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent) {
|
||||
ASSERTLINE(85, 0 <= chan && chan < 2);
|
||||
ASSERTLINE(86, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
|
||||
if ((fileNo < 0) || (fileNo >= CARD_MAX_FILE)) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
{
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result = __CARDGetControlBlock(chan, &card);
|
||||
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsReadable(card, ent);
|
||||
if (result >= 0) {
|
||||
memcpy(dirent, ent, 0x40);
|
||||
}
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 __CARDSetStatusExAsync(s32 chan, s32 fileNo, CARDDir* dirent, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
s32 result;
|
||||
u8* p;
|
||||
s32 i;
|
||||
|
||||
ASSERTLINE(142, 0 <= fileNo && fileNo < CARD_MAX_FILE);
|
||||
ASSERTLINE(143, 0 <= chan && chan < 2);
|
||||
ASSERTLINE(144, *dirent->fileName != 0xff && *dirent->fileName != 0x00);
|
||||
|
||||
ASSERTMSGLINE(152, dirent->iconAddr == 0xffffffff || dirent->iconAddr < CARD_READ_SIZE, "CARDSetStatus[Async](): stat->iconAddr must be 0xffffffff or less than CARD_READ_SIZE.");
|
||||
ASSERTMSGLINE(155, dirent->commentAddr == 0xffffffff || (dirent->commentAddr & 0x1FFF) <= 8128, "CARDSetStatus[Async](): comment strings (set by stat->commentAddr) must not cross 8KB byte boundary.");
|
||||
|
||||
if ((fileNo < 0) || (fileNo >= CARD_MAX_FILE) || ((u8) dirent->fileName[0] == 0xFF) || ((u8) dirent->fileName[0] == 0)) {
|
||||
return CARD_RESULT_FATAL_ERROR;
|
||||
}
|
||||
|
||||
result = __CARDGetControlBlock(chan, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0) {
|
||||
return __CARDPutControlBlock(card, result);
|
||||
}
|
||||
|
||||
for (p = dirent->fileName; p < (u8*)&dirent->time; p++) {
|
||||
if (*p != 0) {
|
||||
continue;
|
||||
}
|
||||
while ((++p) < (u8*)&dirent->time) {
|
||||
*p = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dirent->permission & 0x20) {
|
||||
memset(dirent->gameName, 0, sizeof(dirent->gameName));
|
||||
memset(dirent->company, 0, sizeof(dirent->company));
|
||||
}
|
||||
|
||||
if (dirent->permission & 0x40) {
|
||||
memset(dirent->gameName, 0, sizeof(dirent->gameName));
|
||||
}
|
||||
|
||||
if ((memcmp(&ent->fileName, &dirent->fileName, 32) != 0) || (memcmp(ent->gameName, dirent->gameName, 4) != 0) || (memcmp(ent->company, dirent->company, 2) != 0)) {
|
||||
for(i = 0; i < CARD_MAX_FILE; i++) {
|
||||
if (i != fileNo) {
|
||||
CARDDir* ent = &dir[i]; // sure, just redeclare ent again...
|
||||
if (((u8) ent->gameName[0] != 0xFF)
|
||||
&& (memcmp(&ent->gameName, &dirent->gameName, 4) == 0)
|
||||
&& (memcmp(&ent->company, &dirent->company, 2) == 0)
|
||||
&& (memcmp(&ent->fileName, &dirent->fileName, 0x20) == 0)) {
|
||||
return __CARDPutControlBlock(card, -7);
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy(&ent->fileName, &dirent->fileName, 0x20);
|
||||
memcpy(&ent->gameName, &dirent->gameName, 4);
|
||||
memcpy(&ent->company, &dirent->company, 2);
|
||||
}
|
||||
|
||||
ent->time = dirent->time;
|
||||
ent->bannerFormat = dirent->bannerFormat;
|
||||
ent->iconAddr = dirent->iconAddr;
|
||||
ent->iconFormat = dirent->iconFormat;
|
||||
ent->iconSpeed = dirent->iconSpeed;
|
||||
ent->commentAddr = dirent->commentAddr;
|
||||
ent->permission = dirent->permission;
|
||||
ent->copyTimes = dirent->copyTimes;
|
||||
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
if (result < 0) {
|
||||
__CARDPutControlBlock(card, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 __CARDSetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent) {
|
||||
s32 result = __CARDSetStatusExAsync(chan, fileNo, dirent, &__CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
#include <stdlib.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
static u8 CardData[352] ATTRIBUTE_ALIGN(DOLPHIN_ALIGNMENT) = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0xFF, 0x00, 0x21, 0x13, 0x06, 0x12, 0x03, 0x12, 0x04,
|
||||
0x13, 0x05, 0x00, 0x92, 0x00, 0xFF, 0x00, 0x88, 0xFF, 0xFF, 0x00, 0x89, 0xFF, 0xFF, 0x00, 0x8A, 0xFF, 0xFF, 0x00,
|
||||
0x8B, 0xFF, 0xFF, 0x8F, 0x00, 0x02, 0xBF, 0x00, 0x88, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x00, 0x16, 0xFB,
|
||||
0x00, 0x01, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x03, 0x80, 0xFF, 0x00, 0x02, 0x94, 0x00, 0x27, 0x02, 0xBF, 0x00,
|
||||
0x8E, 0x1F, 0xDF, 0x24, 0xFF, 0x02, 0x40, 0x0F, 0xFF, 0x00, 0x98, 0x04, 0x00, 0x00, 0x9A, 0x00, 0x10, 0x00, 0x99,
|
||||
0x00, 0x00, 0x8E, 0x00, 0x02, 0xBF, 0x00, 0x94, 0x02, 0xBF, 0x86, 0x44, 0x02, 0xBF, 0x00, 0x88, 0x16, 0xFC, 0xDC,
|
||||
0xD1, 0x16, 0xFD, 0x00, 0x03, 0x16, 0xFB, 0x00, 0x01, 0x8F, 0x00, 0x02, 0xBF, 0x00, 0x8E, 0x03, 0x80, 0xCD, 0xD1,
|
||||
0x02, 0x94, 0x00, 0x48, 0x27, 0xFF, 0x03, 0x80, 0x00, 0x01, 0x02, 0x95, 0x00, 0x5A, 0x03, 0x80, 0x00, 0x02, 0x02,
|
||||
0x95, 0x80, 0x00, 0x02, 0x9F, 0x00, 0x48, 0x00, 0x21, 0x8E, 0x00, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF,
|
||||
0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC5, 0xFF, 0xFF, 0x03,
|
||||
0x40, 0x0F, 0xFF, 0x1C, 0x9F, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC7, 0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC6,
|
||||
0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC0, 0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x20, 0xFF, 0x03, 0x40, 0x0F,
|
||||
0xFF, 0x1F, 0x5F, 0x02, 0xBF, 0x00, 0x8E, 0x21, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x23, 0xFF, 0x12, 0x05, 0x12, 0x06,
|
||||
0x02, 0x9F, 0x80, 0xB5, 0x00, 0x21, 0x27, 0xFC, 0x03, 0xC0, 0x80, 0x00, 0x02, 0x9D, 0x00, 0x88, 0x02, 0xDF, 0x27,
|
||||
0xFE, 0x03, 0xC0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x8E, 0x02, 0xDF, 0x2E, 0xCE, 0x2C, 0xCF, 0x00, 0xF8, 0xFF, 0xCD,
|
||||
0x00, 0xF9, 0xFF, 0xC9, 0x00, 0xFA, 0xFF, 0xCB, 0x26, 0xC9, 0x02, 0xC0, 0x00, 0x04, 0x02, 0x9D, 0x00, 0x9C, 0x02,
|
||||
0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static u32 next = 1;
|
||||
|
||||
// prototypes
|
||||
static u32 exnor_1st(u32 data, u32 rshift);
|
||||
static u32 exnor(u32 data, u32 lshift);
|
||||
static u32 bitrev(u32 data);
|
||||
static s32 ReadArrayUnlock(s32 chan, u32 data, void* rbuf, s32 rlen, int mode);
|
||||
static u32 GetInitVal(void);
|
||||
static s32 DummyLen(void);
|
||||
static void InitCallback(void* _task);
|
||||
static void DoneCallback(void* _task);
|
||||
|
||||
static int CARDRand(void) {
|
||||
next = (next * 0x41C64E6D) + 0x3039;
|
||||
return (next / 0x10000) & 0x7FFF;
|
||||
}
|
||||
|
||||
static void CARDSrand(unsigned int seed) {
|
||||
next = seed;
|
||||
}
|
||||
|
||||
static u32 exnor_1st(u32 data, u32 rshift) {
|
||||
u32 wk;
|
||||
u32 work;
|
||||
u32 i;
|
||||
|
||||
work = data;
|
||||
for (i = 0; i < rshift; i++) {
|
||||
wk = ~(work ^ (work >> 7) ^ (work >> 15) ^ (work >> 23));
|
||||
work = (work >> 1) | ((wk << 30) & 0x40000000);
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
static u32 exnor(u32 data, u32 lshift) {
|
||||
u32 wk;
|
||||
u32 work;
|
||||
u32 i;
|
||||
|
||||
work = data;
|
||||
for (i = 0; i < lshift; i++) {
|
||||
// 1bit Left Shift
|
||||
wk = ~(work ^ (work << 7) ^ (work << 15) ^ (work << 23));
|
||||
work = (work << 1) | ((wk >> 30) & 0x00000002);
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
static u32 bitrev(u32 data) {
|
||||
u32 wk;
|
||||
u32 i;
|
||||
u32 k = 0;
|
||||
u32 j = 1;
|
||||
|
||||
wk = 0;
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (i > 15) {
|
||||
if (i == 31)
|
||||
wk |= (((data & (0x01 << 31)) >> 31) & 0x01);
|
||||
else {
|
||||
wk |= ((data & (0x01 << i)) >> j);
|
||||
j += 2;
|
||||
}
|
||||
} else {
|
||||
wk |= ((data & (0x01 << i)) << (31 - i - k));
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
return wk;
|
||||
}
|
||||
|
||||
#define SEC_AD1(x) ((u8)(((x) >> 29) & 0x03))
|
||||
#define SEC_AD2(x) ((u8)(((x) >> 21) & 0xff))
|
||||
#define SEC_AD3(x) ((u8)(((x) >> 19) & 0x03))
|
||||
#define SEC_BA(x) ((u8)(((x) >> 12) & 0x7f))
|
||||
|
||||
static s32 ReadArrayUnlock(s32 chan, u32 data, void* rbuf, s32 rlen, int mode) {
|
||||
CARDControl* card;
|
||||
BOOL err;
|
||||
u8 cmd[5];
|
||||
|
||||
ASSERTLINE(240, 0 <= chan && chan < 2);
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (!EXISelect(chan, 0, CARDFreq))
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
data &= 0xfffff000;
|
||||
memset(cmd, 0, 5);
|
||||
cmd[0] = 0x52;
|
||||
if (mode == 0) {
|
||||
cmd[1] = SEC_AD1(data);
|
||||
cmd[2] = SEC_AD2(data);
|
||||
cmd[3] = SEC_AD3(data);
|
||||
cmd[4] = SEC_BA(data);
|
||||
} else {
|
||||
cmd[1] = (u8)((data & 0xff000000) >> 24);
|
||||
cmd[2] = (u8)((data & 0x00ff0000) >> 16);
|
||||
}
|
||||
|
||||
err = FALSE;
|
||||
err |= !EXIImmEx(chan, cmd, 5, 1);
|
||||
err |= !EXIImmEx(chan, (u8* )card->workArea + (u32)sizeof(CARDID), card->latency, 1);
|
||||
err |= !EXIImmEx(chan, rbuf, rlen, 0);
|
||||
err |= !EXIDeselect(chan);
|
||||
|
||||
return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static u32 GetInitVal(void) {
|
||||
u32 tmp;
|
||||
u32 tick;
|
||||
|
||||
tick = OSGetTick();
|
||||
CARDSrand(tick);
|
||||
tmp = 0x7fec8000;
|
||||
tmp |= CARDRand();
|
||||
tmp &= 0xfffff000;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static s32 DummyLen(void) {
|
||||
u32 tick;
|
||||
u32 wk;
|
||||
s32 tmp;
|
||||
u32 max;
|
||||
|
||||
wk = 1;
|
||||
max = 0;
|
||||
tick = OSGetTick();
|
||||
CARDSrand(tick);
|
||||
|
||||
tmp = CARDRand();
|
||||
tmp &= 0x0000001f;
|
||||
tmp += 1;
|
||||
while ((tmp < 4) && (max < 10)) {
|
||||
tick = OSGetTick();
|
||||
tmp = (s32)(tick << wk);
|
||||
wk++;
|
||||
if (wk > 16)
|
||||
wk = 1;
|
||||
CARDSrand((u32)tmp);
|
||||
tmp = CARDRand();
|
||||
tmp &= 0x0000001f;
|
||||
tmp += 1;
|
||||
max++;
|
||||
}
|
||||
|
||||
if (tmp < 4)
|
||||
tmp = 4;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
s32 __CARDUnlock(s32 chan, u8 flashID[12]) {
|
||||
u32 init_val;
|
||||
u32 data;
|
||||
|
||||
s32 dummy;
|
||||
s32 rlen;
|
||||
u32 rshift;
|
||||
|
||||
u8 fsts;
|
||||
u32 wk, wk1;
|
||||
u32 Ans1 = 0;
|
||||
u32 Ans2 = 0;
|
||||
u32* dp;
|
||||
u8 rbuf[64];
|
||||
u32 para1A = 0;
|
||||
u32 para1B = 0;
|
||||
u32 para2A = 0;
|
||||
u32 para2B = 0;
|
||||
|
||||
CARDControl* card;
|
||||
DSPTaskInfo* task;
|
||||
CARDDecParam* param;
|
||||
u8* input;
|
||||
u8* output;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
task = &card->task;
|
||||
param = (CARDDecParam*)card->workArea;
|
||||
input = (u8*)((u8* )param + sizeof(CARDDecParam));
|
||||
input = (u8*)OSRoundUp32B(input);
|
||||
output = input + 32;
|
||||
|
||||
fsts = 0;
|
||||
init_val = GetInitVal();
|
||||
|
||||
dummy = DummyLen();
|
||||
rlen = dummy;
|
||||
if (ReadArrayUnlock(chan, init_val, rbuf, rlen, 0) < 0)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
rshift = (u32)(dummy * 8 + 1);
|
||||
wk = exnor_1st(init_val, rshift);
|
||||
wk1 = ~(wk ^ (wk >> 7) ^ (wk >> 15) ^ (wk >> 23));
|
||||
card->scramble = (wk | ((wk1 << 31) & 0x80000000));
|
||||
card->scramble = bitrev(card->scramble);
|
||||
dummy = DummyLen();
|
||||
rlen = 20 + dummy;
|
||||
data = 0;
|
||||
if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0)
|
||||
return CARD_RESULT_NOCARD;
|
||||
|
||||
dp = (u32* )rbuf;
|
||||
para1A = *dp++;
|
||||
para1B = *dp++;
|
||||
Ans1 = *dp++;
|
||||
para2A = *dp++;
|
||||
para2B = *dp++;
|
||||
para1A = (para1A ^ card->scramble);
|
||||
rshift = 32;
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
para1B = (para1B ^ card->scramble);
|
||||
rshift = 32;
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
Ans1 ^= card->scramble;
|
||||
rshift = 32;
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
para2A = (para2A ^ card->scramble);
|
||||
rshift = 32;
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
para2B = (para2B ^ card->scramble);
|
||||
rshift = (u32)(dummy * 8);
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
rshift = 32 + 1;
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
*(u32*)&input[0] = para2A;
|
||||
*(u32*)&input[4] = para2B;
|
||||
|
||||
param->inputAddr = input;
|
||||
param->inputLength = 8;
|
||||
param->outputAddr = output;
|
||||
param->aramAddr = 0;
|
||||
|
||||
DCFlushRange(input, 8);
|
||||
DCInvalidateRange(output, 4);
|
||||
DCFlushRange(param, sizeof(CARDDecParam));
|
||||
|
||||
task->priority = 255;
|
||||
task->iram_mmem_addr = (u16*)OSCachedToPhysical(CardData);
|
||||
task->iram_length = 0x160;
|
||||
task->iram_addr = 0;
|
||||
task->dsp_init_vector = 0x10;
|
||||
task->init_cb = InitCallback;
|
||||
task->res_cb = NULL;
|
||||
task->done_cb = DoneCallback;
|
||||
task->req_cb = NULL;
|
||||
DSPAddTask(task);
|
||||
|
||||
dp = (u32*)flashID;
|
||||
*dp++ = para1A;
|
||||
*dp++ = para1B;
|
||||
*dp = Ans1;
|
||||
|
||||
return CARD_RESULT_READY;
|
||||
}
|
||||
|
||||
static void InitCallback(void* _task) {
|
||||
s32 chan;
|
||||
CARDControl* card;
|
||||
DSPTaskInfo* task;
|
||||
CARDDecParam* param;
|
||||
|
||||
task = _task;
|
||||
for (chan = 0; chan < 2; ++chan) {
|
||||
card = &__CARDBlock[chan];
|
||||
if ((DSPTaskInfo*)&card->task == task)
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERTLINE(514, 0 <= chan && chan < 2);
|
||||
|
||||
param = (CARDDecParam*)card->workArea;
|
||||
|
||||
DSPSendMailToDSP(0xff000000);
|
||||
while (DSPCheckMailToDSP())
|
||||
;
|
||||
|
||||
DSPSendMailToDSP((u32)param);
|
||||
while (DSPCheckMailToDSP())
|
||||
;
|
||||
}
|
||||
|
||||
static void DoneCallback(void* _task) {
|
||||
u8 rbuf[64];
|
||||
u32 data;
|
||||
s32 dummy;
|
||||
s32 rlen;
|
||||
u32 rshift;
|
||||
|
||||
u8 unk;
|
||||
u32 wk, wk1;
|
||||
u32 Ans2;
|
||||
|
||||
s32 chan;
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
DSPTaskInfo* task;
|
||||
CARDDecParam* param;
|
||||
|
||||
u8* input;
|
||||
u8* output;
|
||||
task = _task;
|
||||
for (chan = 0; chan < 2; ++chan) {
|
||||
card = &__CARDBlock[chan];
|
||||
if ((DSPTaskInfo* )&card->task == task)
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERTLINE(563, 0 <= chan && chan < 2);
|
||||
|
||||
param = (CARDDecParam*)card->workArea;
|
||||
input = (u8*)((u8*)param + sizeof(CARDDecParam));
|
||||
input = (u8*)OSRoundUp32B(input);
|
||||
output = input + 32;
|
||||
|
||||
Ans2 = *(u32*)output;
|
||||
dummy = DummyLen();
|
||||
rlen = dummy;
|
||||
data = ((Ans2 ^ card->scramble) & 0xffff0000);
|
||||
if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) {
|
||||
EXIUnlock(chan);
|
||||
__CARDMountCallback(chan, CARD_RESULT_NOCARD);
|
||||
return;
|
||||
}
|
||||
|
||||
rshift = (u32)((dummy + 4 + card->latency) * 8 + 1);
|
||||
wk = exnor(card->scramble, rshift);
|
||||
wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23));
|
||||
card->scramble = (wk | ((wk1 >> 31) & 0x00000001));
|
||||
|
||||
dummy = DummyLen();
|
||||
rlen = dummy;
|
||||
data = (((Ans2 << 16) ^ card->scramble) & 0xffff0000);
|
||||
if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) {
|
||||
EXIUnlock(chan);
|
||||
__CARDMountCallback(chan, CARD_RESULT_NOCARD);
|
||||
return;
|
||||
}
|
||||
|
||||
result = __CARDReadStatus(chan, &unk);
|
||||
if (!EXIProbe(chan)) {
|
||||
EXIUnlock(chan);
|
||||
__CARDMountCallback(chan, CARD_RESULT_NOCARD);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result == CARD_RESULT_READY && !(unk & 0x40)) {
|
||||
EXIUnlock(chan);
|
||||
result = CARD_RESULT_IOERROR;
|
||||
}
|
||||
|
||||
__CARDMountCallback(chan, result);
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
#include <dolphin/card.h>
|
||||
|
||||
#include "__card.h"
|
||||
|
||||
// prototypes
|
||||
static void WriteCallback(s32 chan, s32 result);
|
||||
static void EraseCallback(s32 chan, s32 result);
|
||||
|
||||
static void WriteCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
u16* fat;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
CARDFileInfo* fileInfo;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result >= 0) {
|
||||
fileInfo = card->fileInfo;
|
||||
if (fileInfo->length < 0) {
|
||||
result = CARD_RESULT_CANCELED;
|
||||
goto after;
|
||||
}
|
||||
fileInfo->length -= card->sectorSize;
|
||||
if (fileInfo->length <= 0) {
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = dir + fileInfo->fileNo;
|
||||
ent->time = OSGetTime()/(__OSBusClock/4);
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
result = __CARDUpdateDir(chan, callback);
|
||||
goto check;
|
||||
} else {
|
||||
fat = __CARDGetFatBlock(card);
|
||||
fileInfo->offset += card->sectorSize;
|
||||
fileInfo->iBlock = fat[fileInfo->iBlock];
|
||||
if ((fileInfo->iBlock < 5) || (fileInfo->iBlock >= card->cBlock)) {
|
||||
result = CARD_RESULT_BROKEN;
|
||||
goto after;
|
||||
}
|
||||
result = __CARDEraseSector(chan, card->sectorSize * fileInfo->iBlock, EraseCallback);
|
||||
check:;
|
||||
if (result < 0) {
|
||||
goto after;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
after:;
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(0x86, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void EraseCallback(s32 chan, s32 result) {
|
||||
CARDControl* card;
|
||||
CARDCallback callback;
|
||||
CARDFileInfo* fileInfo;
|
||||
|
||||
card = &__CARDBlock[chan];
|
||||
if (result >= 0) {
|
||||
fileInfo = card->fileInfo;
|
||||
ASSERTLINE(161, OFFSET(fileInfo->offset, card->sectorSize) == 0);
|
||||
result = __CARDWrite(chan, card->sectorSize * fileInfo->iBlock, card->sectorSize, card->buffer, WriteCallback);
|
||||
if (result < 0) {
|
||||
goto after;
|
||||
}
|
||||
} else {
|
||||
after:;
|
||||
callback = card->apiCallback;
|
||||
card->apiCallback = NULL;
|
||||
__CARDPutControlBlock(card, result);
|
||||
ASSERTLINE(175, callback);
|
||||
callback(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
s32 CARDWriteAsync(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset, CARDCallback callback) {
|
||||
CARDControl* card;
|
||||
s32 result;
|
||||
CARDDir* dir;
|
||||
CARDDir* ent;
|
||||
|
||||
ASSERTLINE(210, buf && ((u32) buf % 32) == 0);
|
||||
ASSERTLINE(211, 0 < length);
|
||||
|
||||
result = __CARDSeek(fileInfo, length, offset, &card);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ASSERTLINE(217, OFFSET(offset, card->sectorSize) == 0);
|
||||
ASSERTLINE(218, OFFSET(length, card->sectorSize) == 0);
|
||||
|
||||
if (OFFSET(offset, card->sectorSize) != 0 || OFFSET(length, card->sectorSize) != 0)
|
||||
return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR);
|
||||
|
||||
dir = __CARDGetDirBlock(card);
|
||||
ent = &dir[fileInfo->fileNo];
|
||||
result = __CARDIsWritable(card, ent);
|
||||
if (result < 0)
|
||||
return __CARDPutControlBlock(card, result);
|
||||
|
||||
DCStoreRange((void*)buf, (u32)length);
|
||||
card->apiCallback = callback ? callback : __CARDDefaultApiCallback;
|
||||
card->buffer = (void*)buf;
|
||||
|
||||
result = __CARDEraseSector(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock, EraseCallback);
|
||||
if (result < 0)
|
||||
__CARDPutControlBlock(card, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 CARDWrite(CARDFileInfo* fileInfo, void* buf, s32 length, s32 offset) {
|
||||
s32 result = CARDWriteAsync(fileInfo, buf, length, offset, __CARDSyncCallback);
|
||||
if (result < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return __CARDSync(fileInfo->chan);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef _REVOLUTION_CARD_INTERNAL_H_
|
||||
#define _REVOLUTION_CARD_INTERNAL_H_
|
||||
|
||||
#include <revolution/card.h>
|
||||
#include <revolution/exi.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// CARDStatEx
|
||||
s32 __CARDGetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent);
|
||||
s32 __CARDSetStatusExAsync(s32 chan, s32 fileNo, CARDDir* dirent, CARDCallback callback);
|
||||
s32 __CARDSetStatusEx(s32 chan, s32 fileNo, CARDDir* dirent);
|
||||
|
||||
// CARDUnlock
|
||||
s32 __CARDUnlock(s32 chan, u8 flashID[12]);
|
||||
|
||||
// CARDRead
|
||||
s32 __CARDSeek(CARDFileInfo* fileInfo, s32 length, s32 offset, CARDControl** pcard);
|
||||
|
||||
// CARDRdwr
|
||||
s32 __CARDRead(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback);
|
||||
s32 __CARDWrite(s32 chan, u32 addr, s32 length, void* dst, CARDCallback callback);
|
||||
|
||||
// CARDRaw
|
||||
s32 __CARDRawReadAsync(s32 chan, void* buf, s32 length, s32 offset, CARDCallback callback);
|
||||
s32 __CARDRawRead(s32 chan, void* buf, s32 length, s32 offset);
|
||||
s32 __CARDRawErase(s32 chan, s32 offset);
|
||||
s32 __CARDRawEraseAsync(s32 chan, s32 offset, CARDCallback callback);
|
||||
|
||||
// CARDOpen
|
||||
BOOL __CARDCompareFileName(CARDDir* ent, const char* fileName);
|
||||
s32 __CARDAccess(CARDControl* card, CARDDir* ent);
|
||||
s32 __CARDIsPublic(CARDDir* ent);
|
||||
s32 __CARDGetFileNo(CARDControl* card, const char* fileName, s32* pfileNo);
|
||||
BOOL __CARDIsOpened(CARDControl* card, s32 fileNo);
|
||||
s32 __CARDIsWritable(CARDControl* card, CARDDir* ent);
|
||||
s32 __CARDIsReadable(CARDControl* card, CARDDir* ent);
|
||||
|
||||
// CARDNet
|
||||
extern u16 __CARDVendorID;
|
||||
extern u8 __CARDPermMask;
|
||||
int __CARDEnableGlobal(int enable);
|
||||
int __CARDEnableCompany(int enable);
|
||||
|
||||
// CARDMount
|
||||
void __CARDMountCallback(s32 chan, s32 result);
|
||||
void __CARDDisable(BOOL disable);
|
||||
|
||||
// CARDFormat
|
||||
s32 CARDFormatAsync(s32 chan, CARDCallback callback);
|
||||
s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback);
|
||||
s32 __CARDFormatRegion(s32 chan, u16 encode);
|
||||
|
||||
// CARDDir
|
||||
CARDDir* __CARDGetDirBlock(CARDControl* card);
|
||||
s32 __CARDUpdateDir(s32 chan, CARDCallback callback);
|
||||
|
||||
// CARDCheck
|
||||
void __CARDCheckSum(void* ptr, int length, u16* checksum, u16* checksumInv);
|
||||
s32 __CARDVerify(CARDControl* card);
|
||||
|
||||
// CARDBlock
|
||||
void* __CARDGetFatBlock(CARDControl* card);
|
||||
s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback);
|
||||
s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback);
|
||||
s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback);
|
||||
|
||||
// CARDBios
|
||||
extern CARDControl __CARDBlock[2];
|
||||
|
||||
extern DVDDiskID* __CARDDiskID;
|
||||
extern DVDDiskID __CARDDiskNone;
|
||||
|
||||
void __CARDDefaultApiCallback(s32 chan, s32 result);
|
||||
void __CARDSyncCallback(s32 chan, s32 result);
|
||||
void __CARDExtHandler(s32 chan, OSContext* context);
|
||||
void __CARDExiHandler(s32 chan, OSContext* context);
|
||||
void __CARDTxHandler(s32 chan, OSContext* context);
|
||||
void __CARDUnlockedHandler(s32 chan, OSContext* context);
|
||||
int __CARDReadNintendoID(s32 chan, u32* id);
|
||||
s32 __CARDEnableInterrupt(s32 chan, BOOL enable);
|
||||
s32 __CARDReadStatus(s32 chan, u8* status);
|
||||
int __CARDReadVendorID(s32 chan, u16* id);
|
||||
s32 __CARDClearStatus(s32 chan);
|
||||
s32 __CARDSleep(s32 chan);
|
||||
s32 __CARDWakeup(s32 chan);
|
||||
s32 __CARDReadSegment(s32 chan, CARDCallback callback);
|
||||
s32 __CARDWritePage(s32 chan, CARDCallback callback);
|
||||
s32 __CARDErase(s32 chan, CARDCallback callback);
|
||||
s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback);
|
||||
void __CARDSetDiskID(const DVDDiskID* id);
|
||||
s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard);
|
||||
s32 __CARDPutControlBlock(CARDControl* card, s32 result);
|
||||
s32 __CARDSync(s32 chan);
|
||||
u16 __CARDGetFontEncode(void);
|
||||
u16 __CARDSetFontEncode(u16 encode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DOLPHIN_CARD_INTERNAL_H_
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "HBMAnmController.h"
|
||||
|
||||
#include "nw4hbm/lyt/animation.h"
|
||||
#include "nw4hbm/lyt/group.h"
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
GroupAnmController::GroupAnmController() : mpGroup(), mpAnimGroup() {}
|
||||
|
||||
GroupAnmController::~GroupAnmController() {}
|
||||
|
||||
void GroupAnmController::do_calc() {
|
||||
bool flag;
|
||||
|
||||
if (mState == ANIM_STATE_PLAY) {
|
||||
calc();
|
||||
flag = true;
|
||||
|
||||
mpAnimGroup->SetFrame(mFrame);
|
||||
} else {
|
||||
flag = false;
|
||||
}
|
||||
|
||||
nw4hbm::lyt::PaneLinkList& list = mpGroup->GetPaneList();
|
||||
|
||||
for (nw4hbm::lyt::PaneLinkList::Iterator it = list.GetBeginIter(); it != list.GetEndIter();
|
||||
it++)
|
||||
{
|
||||
it->mTarget->SetAnimationEnable(mpAnimGroup, flag, false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace homebutton
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef HOMEBUTTON_ANM_CONTROLLER_H
|
||||
#define HOMEBUTTON_ANM_CONTROLLER_H
|
||||
|
||||
#include "HBMFrameController.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
class AnimTransform;
|
||||
class Group;
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
class GroupAnmController : public FrameController {
|
||||
public:
|
||||
/* 0x00 (base) */
|
||||
/* 0x20 */ nw4hbm::lyt::Group* mpGroup;
|
||||
/* 0x24 */ nw4hbm::lyt::AnimTransform* mpAnimGroup;
|
||||
|
||||
GroupAnmController();
|
||||
virtual ~GroupAnmController();
|
||||
|
||||
void do_calc();
|
||||
}; // size = 0x28
|
||||
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,295 @@
|
||||
#ifndef HOMEBUTTON_BASE_H
|
||||
#define HOMEBUTTON_BASE_H
|
||||
|
||||
#include <revolution/ax.h>
|
||||
#include <revolution/axfx.h>
|
||||
#include <revolution/wpad.h>
|
||||
#include "HBMCommon.h"
|
||||
#include "HBMController.h"
|
||||
#include "HBMGUIManager.h"
|
||||
#include "nw4hbm/lyt/drawInfo.h"
|
||||
#include "nw4hbm/lyt/layout.h"
|
||||
#include "nw4hbm/snd/DvdSoundArchive.h"
|
||||
#include "nw4hbm/snd/MemorySoundArchive.h"
|
||||
#include "nw4hbm/snd/NandSoundArchive.h"
|
||||
#include "nw4hbm/snd/SoundArchivePlayer.h"
|
||||
#include "nw4hbm/snd/SoundPlayer.h"
|
||||
#include "nw4hbm/snd/SoundSystem.h"
|
||||
|
||||
|
||||
#include "new.h"
|
||||
|
||||
namespace homebutton {
|
||||
static void initgx();
|
||||
static void drawBlackPlate(f32 left, f32 top, f32 right, f32 bottom);
|
||||
static u32 get_comma_length(char* pBuf);
|
||||
static void SpeakerCallback(OSAlarm* alm, OSContext* ctx);
|
||||
static void MotorCallback(OSAlarm* alm, OSContext* ctx);
|
||||
static void RetrySimpleSyncCallback(OSAlarm* alm, OSContext* ctx);
|
||||
static void SimpleSyncCallback(s32 result, s32 num);
|
||||
} // namespace homebutton
|
||||
|
||||
namespace nw4hbm {
|
||||
|
||||
namespace lyt {
|
||||
class ArcResourceAccessor;
|
||||
class ArcResourceLink;
|
||||
class Layout;
|
||||
class MultiArcResourceAccessor;
|
||||
class Pane;
|
||||
} // namespace lyt
|
||||
|
||||
namespace ut {
|
||||
class ResFont;
|
||||
}
|
||||
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
class HomeButton;
|
||||
class Controller;
|
||||
class GroupAnmController;
|
||||
class RemoteSpk;
|
||||
|
||||
class HomeButtonEventHandler : public gui::EventHandler {
|
||||
public:
|
||||
HomeButtonEventHandler(homebutton::HomeButton* pHomeButton) : mpHomeButton(pHomeButton) {}
|
||||
|
||||
/* 0x08 */ virtual void onEvent(u32 uID, u32 uEvent, void* pData);
|
||||
|
||||
homebutton::HomeButton* getHomeButton() { return mpHomeButton; }
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0x08 */ HomeButton* mpHomeButton;
|
||||
}; // size = 0x0C
|
||||
|
||||
class HomeButton {
|
||||
private:
|
||||
typedef enum {
|
||||
/* 0 */ eSeq_Normal,
|
||||
/* 1 */ eSeq_Control,
|
||||
/* 2 */ eSeq_Cmn,
|
||||
} eSeq;
|
||||
|
||||
class BlackFader {
|
||||
public:
|
||||
BlackFader(int maxFrame) {
|
||||
init(maxFrame);
|
||||
setColor(0, 0, 0);
|
||||
}
|
||||
|
||||
void setColor(u8 r, u8 g, u8 b) {
|
||||
red_ = r;
|
||||
green_ = g;
|
||||
blue_ = b;
|
||||
}
|
||||
|
||||
int getFrame() const { return frame_; }
|
||||
int getMaxFrame() const { return maxFrame_; }
|
||||
void start() { state_ = 1; }
|
||||
GXColor GetColor(u8 alpha) { return (GXColor){red_, green_, blue_, alpha}; }
|
||||
|
||||
bool isDone();
|
||||
void init(int maxFrame);
|
||||
void calc();
|
||||
void draw();
|
||||
|
||||
private:
|
||||
/* 0x00 */ int frame_;
|
||||
/* 0x04 */ int maxFrame_;
|
||||
/* 0x08 */ int state_;
|
||||
/* 0x0D */ u8 red_;
|
||||
/* 0x0E */ u8 green_;
|
||||
/* 0x0F */ u8 blue_;
|
||||
}; // size = 0x10
|
||||
|
||||
public:
|
||||
HomeButton(const HBMDataInfo* dataInfo);
|
||||
~HomeButton();
|
||||
|
||||
int getVolume();
|
||||
HBMSelectBtnNum getSelectBtnNum();
|
||||
bool isActive() const;
|
||||
bool isUpBarActive() const;
|
||||
bool isDownBarActive();
|
||||
void setAdjustFlag(int flag);
|
||||
void setForcusSE();
|
||||
void setSimpleSyncAlarm(int type);
|
||||
void setSpeakerAlarm(int chan, int msec);
|
||||
void setVolume(int vol);
|
||||
bool getVibFlag();
|
||||
int getPaneNo(const char*);
|
||||
void setVibFlag(bool flag);
|
||||
void create();
|
||||
void init();
|
||||
void calc(const HBMControllerData* pController);
|
||||
void draw();
|
||||
void update(const HBMControllerData* pController);
|
||||
void updateTrigPane();
|
||||
void startPointEvent(const char* pPane, void* pData);
|
||||
void startLeftEvent(const char* pPane);
|
||||
void startTrigEvent(const char* pPane);
|
||||
int findAnimator(int pane, int anm);
|
||||
int findGroupAnimator(int pane, int anm);
|
||||
void callSimpleSyncCallback(s32 result, s32 num);
|
||||
void startBlackOut();
|
||||
|
||||
const HBMDataInfo* getHBMDataInfo() { return mpHBInfo; }
|
||||
Controller* getController(int chan) { return mpController[chan]; }
|
||||
const char* getFuncPaneName(int no) { return scFuncTouchPaneName[no]; }
|
||||
const char* getPaneName(int no) { return scBtnName[no]; }
|
||||
bool getReassignedFlag() const { return mReassignedFlag; }
|
||||
HomeButtonEventHandler* getEventHandler() const { return mpHomeButtonEventHandler; }
|
||||
nw4hbm::snd::SoundArchivePlayer* GetSoundArchivePlayer() { return mpSoundArchivePlayer; }
|
||||
void setEndSimpleSyncFlag(bool flag) { mEndSimpleSyncFlag = flag; }
|
||||
void setReassignedFlag(bool flag) { mReassignedFlag = flag; }
|
||||
void setSimpleSyncFlag(bool flag) { mSimpleSyncFlag = flag; }
|
||||
|
||||
static void createInstance(const HBMDataInfo* dataInfo);
|
||||
static HomeButton* getInstance() { return spHomeButtonObj; }
|
||||
static void deleteInstance();
|
||||
|
||||
private:
|
||||
void init_battery(const HBMControllerData* pController);
|
||||
void calc_battery(int chan);
|
||||
void reset_battery();
|
||||
|
||||
void init_sound();
|
||||
void fadeout_sound(f32 gain);
|
||||
|
||||
void init_msg();
|
||||
void init_vib();
|
||||
void init_volume();
|
||||
|
||||
void set_config();
|
||||
void set_text();
|
||||
|
||||
void calc_fadeoutAnm();
|
||||
|
||||
void update_controller(int id);
|
||||
void update_posController(int id);
|
||||
|
||||
void reset_btn();
|
||||
void reset_control();
|
||||
void reset_guiManager(int num);
|
||||
void reset_window();
|
||||
|
||||
public:
|
||||
void play_sound(int id);
|
||||
void createSound(nw4hbm::snd::NandSoundArchive* pNandSoundArchive, bool bCreateSoundHeap);
|
||||
void deleteSound();
|
||||
void draw_impl();
|
||||
void updateSoundArchivePlayer();
|
||||
void setSoundVolume(f32 volume);
|
||||
inline void stopSound(bool checkFlag);
|
||||
void initSound(const char* path);
|
||||
void updateSound();
|
||||
|
||||
void PlaySeq(int num) {
|
||||
if (mpSoundArchivePlayer != NULL && mpSoundHandle != NULL) {
|
||||
mpSoundHandle->DetachSound();
|
||||
mpSoundArchivePlayer->StartSound(mpSoundHandle, num);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x000 */ eSeq mSequence;
|
||||
/* 0x004 */ const HBMDataInfo* mpHBInfo;
|
||||
/* 0x008 */ int mButtonNum;
|
||||
/* 0x00C */ int mAnmNum;
|
||||
/* 0x010 */ int mState;
|
||||
/* 0x014 */ int mSelectAnmNum;
|
||||
/* 0x018 */ int mMsgCount;
|
||||
/* 0x01C */ int mPaneCounter[14];
|
||||
/* 0x054 */ int mPadDrawTime[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x064 */ int mForcusSEWaitTime;
|
||||
/* 0x068 */ int mBar0AnmRev;
|
||||
/* 0x06C */ int mBar1AnmRev;
|
||||
/* 0x070 */ int mBar0AnmRevHold;
|
||||
/* 0x074 */ int mBar1AnmRevHold;
|
||||
/* 0x078 */ int mGetPadInfoTime;
|
||||
/* 0x07C */ bool mControllerFlag[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x080 */ int mVolumeNum;
|
||||
/* 0x084 */ bool mVibFlag;
|
||||
/* 0x085 */ bool mControlFlag;
|
||||
/* 0x086 */ bool mLetterFlag;
|
||||
/* 0x087 */ bool mAdjustFlag;
|
||||
/* 0x088 */ bool mReassignedFlag;
|
||||
/* 0x089 */ bool mSimpleSyncFlag;
|
||||
/* 0x08A */ bool mEndSimpleSyncFlag;
|
||||
/* 0x08B */ bool mInitFlag;
|
||||
/* 0x08C */ bool mForceSttInitProcFlag;
|
||||
/* 0x08D */ bool mForceSttFadeInProcFlag;
|
||||
/* 0x08E */ bool mEndInitSoundFlag;
|
||||
/* 0x08F */ bool mForceStopSyncFlag;
|
||||
/* 0x090 */ bool mForceEndMsgAnmFlag;
|
||||
#if HBM_REVISION > 1
|
||||
/* 0x094 */ int mSoundRetryCnt;
|
||||
#endif
|
||||
/* 0x098 */ int mDialogFlag[4];
|
||||
/* 0x0A8 */ char* mpLayoutName;
|
||||
/* 0x0AC */ char* mpAnmName;
|
||||
/* 0x0B0 */ HBMSelectBtnNum mSelectBtnNum;
|
||||
/* 0x0B4 */ wchar_t* mpText[7][6];
|
||||
/* 0x15C */ WPADInfo mWpadInfo[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x1BC */ WPADSimpleSyncCallback mSimpleSyncCallback;
|
||||
/* 0x1CC */ f32 mOnPaneVibFrame[4];
|
||||
/* 0x1DC */ f32 mOnPaneVibWaitFrame[4];
|
||||
/* 0x1E0 */ int mWaitStopMotorCount;
|
||||
/* 0x1E4 */ nw4hbm::lyt::Layout* mpLayout;
|
||||
/* 0x1E8 */ nw4hbm::lyt::Layout* mpCursorLayout[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x1F8 */ nw4hbm::lyt::ArcResourceAccessor* mpResAccessor;
|
||||
/* 0x1FC */ gui::PaneManager* mpPaneManager;
|
||||
/* 0x200 */ HomeButtonEventHandler* mpHomeButtonEventHandler;
|
||||
/* 0x204 */ nw4hbm::lyt::DrawInfo mDrawInfo;
|
||||
/* 0x258 */ Controller* mpController[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x268 */ RemoteSpk* mpRemoteSpk;
|
||||
/* 0x26C */ GroupAnmController* mpAnmController[12];
|
||||
/* 0x29C */ GroupAnmController* mpGroupAnmController[74];
|
||||
/* 0x3C4 */ GroupAnmController* mpPairGroupAnmController[15];
|
||||
/* 0x400 */ BlackFader mFader;
|
||||
/* 0x410 */ OSAlarm mAlarm[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x4D0 */ OSAlarm mSpeakerAlarm[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x590 */ OSAlarm mSimpleSyncAlarm;
|
||||
/* 0x5C0 */ nw4hbm::snd::SoundArchivePlayer* mpSoundArchivePlayer;
|
||||
/* 0x5C4 */ nw4hbm::snd::DvdSoundArchive* mpDvdSoundArchive;
|
||||
/* 0x5C8 */ nw4hbm::snd::MemorySoundArchive* mpMemorySoundArchive;
|
||||
/* 0x5CC */ nw4hbm::snd::NandSoundArchive* mpNandSoundArchive;
|
||||
/* 0x5D0 */ nw4hbm::snd::SoundHeap* mpSoundHeap;
|
||||
/* 0x5D4 */ nw4hbm::snd::SoundHandle* mpSoundHandle;
|
||||
/* 0x5D8 */ u16 mAppVolume[3];
|
||||
/* 0x5E0 */ AXFXAllocFunc mAxFxAlloc;
|
||||
/* 0x5E4 */ AXFXFreeFunc mAxFxFree;
|
||||
/* 0x5E8 */ AXFX_REVERBHI mAxFxReverb;
|
||||
/* 0x748 */ AXAuxCallback mAuxCallback;
|
||||
/* 0x74C */ void* mpAuxContext;
|
||||
/* 0x750 */ f32 mFadeOutSeTime;
|
||||
|
||||
// static members
|
||||
private:
|
||||
static HomeButton* spHomeButtonObj;
|
||||
|
||||
static const char* scCursorLytName[WPAD_MAX_CONTROLLERS];
|
||||
static const char* scCursorPaneName;
|
||||
static const char* scCursorRotPaneName;
|
||||
static const char* scCursorSRotPaneName;
|
||||
|
||||
static const char* scBtnName[4];
|
||||
static const char* scTxtName[4];
|
||||
static const char* scGrName[8];
|
||||
static const char* scAnimName[3];
|
||||
static const char* scPairGroupAnimName[15];
|
||||
static const char* scPairGroupName[15];
|
||||
static const char* scGroupAnimName[22];
|
||||
static const char* scGroupName[35];
|
||||
static const char* scFuncPaneName[5];
|
||||
static const char* scFuncTouchPaneName[10];
|
||||
static const char* scFuncTextPaneName[3];
|
||||
static const char* scBatteryPaneName[WPAD_MAX_CONTROLLERS][4];
|
||||
}; // size = 0x740
|
||||
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef HOMEBUTTON_COMMON_H
|
||||
#define HOMEBUTTON_COMMON_H
|
||||
|
||||
#include <revolution/mem.h>
|
||||
|
||||
extern "C" MEMAllocator* spAllocator;
|
||||
|
||||
void* HBMAllocMem(u32 length);
|
||||
void HBMFreeMem(void* ptr);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,356 @@
|
||||
#include "HBMController.h"
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
bool Controller::sBatteryFlag[WPAD_MAX_CONTROLLERS];
|
||||
OSAlarm Controller::sAlarm[WPAD_MAX_CONTROLLERS];
|
||||
OSAlarm Controller::sAlarmSoundOff[WPAD_MAX_CONTROLLERS];
|
||||
Controller* Controller::sThis[WPAD_MAX_CONTROLLERS];
|
||||
bool Controller::sSetInfoAsync[WPAD_MAX_CONTROLLERS];
|
||||
RemoteSpk* Controller::sPInstance;
|
||||
s32 Controller::lbl_8025DBBC;
|
||||
|
||||
void Controller::wpadConnectCallback(s32 chan, s32 result) {
|
||||
switch (result) {
|
||||
case WPAD_ESUCCESS:
|
||||
if (!sThis[chan]->mCallbackFlag) {
|
||||
sThis[chan]->mOldExtensionCallback =
|
||||
WPADSetExtensionCallback(chan, wpadExtensionCallback);
|
||||
sThis[chan]->mCallbackFlag = true;
|
||||
}
|
||||
|
||||
WPADControlSpeaker(chan, WPAD_SPEAKER_DISABLE, NULL);
|
||||
break;
|
||||
|
||||
case WPAD_ENODEV:
|
||||
WPADSetExtensionCallback(chan, sThis[chan]->mOldExtensionCallback);
|
||||
sThis[chan]->mOldExtensionCallback = NULL;
|
||||
sThis[chan]->mCallbackFlag = false;
|
||||
sThis[chan]->mCheckSoundTimeFlag = false;
|
||||
sThis[chan]->mCheckSoundIntervalFlag = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sThis[chan]->mOldConnectCallback) {
|
||||
(*sThis[chan]->mOldConnectCallback)(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::wpadExtensionCallback(s32 chan, s32 result) {
|
||||
switch (result) {
|
||||
case WPAD_DEV_INITIALIZING:
|
||||
sThis[chan]->soundOff(1000);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sThis[chan]->mOldExtensionCallback) {
|
||||
(*sThis[chan]->mOldExtensionCallback)(chan, result);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::soundOnCallback(OSAlarm* alm, OSContext*) {
|
||||
int chan = (int)OSGetAlarmUserData(alm);
|
||||
sThis[chan]->soundOn();
|
||||
}
|
||||
|
||||
Controller::Controller(int chan, RemoteSpk* spk) {
|
||||
mHBController.chan = chan;
|
||||
mHBController.rumble = false;
|
||||
mHBController.spVol = 1.0f;
|
||||
|
||||
remotespk = spk;
|
||||
mOldConnectCallback = NULL;
|
||||
mOldExtensionCallback = NULL;
|
||||
mCallbackFlag = false;
|
||||
mSoundOffFlag = false;
|
||||
|
||||
if (chan < WPAD_MAX_CONTROLLERS) {
|
||||
sBatteryFlag[chan] = false;
|
||||
OSCreateAlarm(&sAlarm[chan]);
|
||||
OSCreateAlarm(&sAlarmSoundOff[chan]);
|
||||
sThis[chan] = this;
|
||||
}
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
OSCancelAlarm(&sAlarm[mHBController.chan]);
|
||||
OSCancelAlarm(&sAlarmSoundOff[mHBController.chan]);
|
||||
}
|
||||
|
||||
void Controller::initCallback() {
|
||||
u32 type;
|
||||
|
||||
mOldConnectCallback = WPADSetConnectCallback(mHBController.chan, &wpadConnectCallback);
|
||||
|
||||
switch (WPADProbe(mHBController.chan, &type)) {
|
||||
case WPAD_ESUCCESS:
|
||||
mOldExtensionCallback =
|
||||
WPADSetExtensionCallback(mHBController.chan, &wpadExtensionCallback);
|
||||
mCallbackFlag = true;
|
||||
break;
|
||||
case WPAD_ENODEV:
|
||||
mCallbackFlag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::clearCallback() {
|
||||
WPADSetConnectCallback(mHBController.chan, mOldConnectCallback);
|
||||
mOldConnectCallback = NULL;
|
||||
|
||||
WPADSetExtensionCallback(mHBController.chan, mOldExtensionCallback);
|
||||
mOldExtensionCallback = NULL;
|
||||
}
|
||||
|
||||
void Controller::setKpad(const HBMKPadData* con, bool updatePos) {
|
||||
if (!con->kpad) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (updatePos) {
|
||||
if (con->kpad->dev_type == WPAD_DEV_CLASSIC && con->use_devtype == WPAD_DEV_CLASSIC) {
|
||||
mHBController.x = con->pos.x;
|
||||
mHBController.y = con->pos.y;
|
||||
} else {
|
||||
mHBController.x = con->kpad->pos.x;
|
||||
mHBController.y = con->kpad->pos.y;
|
||||
}
|
||||
}
|
||||
|
||||
mHBController.trig = con->kpad->trig;
|
||||
mHBController.hold = con->kpad->hold;
|
||||
mHBController.release = con->kpad->release;
|
||||
|
||||
if (con->kpad->dev_type == WPAD_DEV_CLASSIC) {
|
||||
u32 h = con->kpad->ex_status.cl.hold;
|
||||
u32 t = con->kpad->ex_status.cl.trig;
|
||||
u32 r = con->kpad->ex_status.cl.release;
|
||||
|
||||
if (h & WPAD_BUTTON_CL_A) {
|
||||
mHBController.hold |= WPAD_BUTTON_A;
|
||||
}
|
||||
if (t & WPAD_BUTTON_CL_A) {
|
||||
mHBController.trig |= WPAD_BUTTON_A;
|
||||
}
|
||||
if (r & WPAD_BUTTON_CL_A) {
|
||||
mHBController.release |= WPAD_BUTTON_A;
|
||||
}
|
||||
|
||||
if (h & WPAD_BUTTON_CL_PLUS) {
|
||||
mHBController.hold |= WPAD_BUTTON_PLUS;
|
||||
}
|
||||
if (t & WPAD_BUTTON_CL_PLUS) {
|
||||
mHBController.trig |= WPAD_BUTTON_PLUS;
|
||||
}
|
||||
if (r & WPAD_BUTTON_CL_PLUS) {
|
||||
mHBController.release |= WPAD_BUTTON_PLUS;
|
||||
}
|
||||
|
||||
if (h & WPAD_BUTTON_CL_MINUS) {
|
||||
mHBController.hold |= WPAD_BUTTON_MINUS;
|
||||
}
|
||||
if (t & WPAD_BUTTON_CL_MINUS) {
|
||||
mHBController.trig |= WPAD_BUTTON_MINUS;
|
||||
}
|
||||
if (r & WPAD_BUTTON_CL_MINUS) {
|
||||
mHBController.release |= WPAD_BUTTON_MINUS;
|
||||
}
|
||||
|
||||
if (h & WPAD_BUTTON_CL_HOME) {
|
||||
mHBController.hold |= WPAD_BUTTON_HOME;
|
||||
}
|
||||
if (t & WPAD_BUTTON_CL_HOME) {
|
||||
mHBController.trig |= WPAD_BUTTON_HOME;
|
||||
}
|
||||
if (r & WPAD_BUTTON_CL_HOME) {
|
||||
mHBController.release |= WPAD_BUTTON_HOME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::clrKpadButton() {
|
||||
mHBController.trig = 0;
|
||||
mHBController.hold = 0;
|
||||
mHBController.release = 0;
|
||||
}
|
||||
|
||||
void Controller::setInValidPos() {
|
||||
mHBController.x = -10000.0f;
|
||||
mHBController.y = -10000.0f;
|
||||
}
|
||||
|
||||
int Controller::getChan() const {
|
||||
return mHBController.chan;
|
||||
}
|
||||
|
||||
void Controller::connect() {
|
||||
getRemoteSpk()->Connect(getChan());
|
||||
}
|
||||
|
||||
void Controller::disconnect() { /* ... */ }
|
||||
|
||||
void Controller::setSpeakerVol(f32 vol) {
|
||||
mHBController.spVol = vol;
|
||||
}
|
||||
|
||||
f32 Controller::getSpeakerVol() const {
|
||||
return mHBController.spVol;
|
||||
}
|
||||
|
||||
void Controller::playSound(nw4hbm::snd::SoundArchivePlayer* pSoundArchivePlayer, int id) {
|
||||
if (!mSoundOffFlag) {
|
||||
getRemoteSpk()->Play(getChan(), id, getSpeakerVol() * 10.0f);
|
||||
|
||||
if (WPADIsSpeakerEnabled(getChan())) {
|
||||
if (!mCheckSoundTimeFlag) {
|
||||
mPlaySoundTime = OSGetTime();
|
||||
}
|
||||
|
||||
mCheckSoundTimeFlag = true;
|
||||
mCheckSoundIntervalFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::isPlayingSound() const {
|
||||
return getRemoteSpk()->isPlaying(getChan());
|
||||
}
|
||||
|
||||
bool Controller::isPlayingSoundId(int id) const {
|
||||
if (!isPlayingSound()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!getRemoteSpk()->isPlayingId(getChan(), id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Controller::initSound() {
|
||||
mCheckSoundTimeFlag = false;
|
||||
mCheckSoundIntervalFlag = false;
|
||||
}
|
||||
|
||||
void Controller::updateSound() {
|
||||
int chan = getChan();
|
||||
|
||||
if (!isPlayingSound()) {
|
||||
if (mCheckSoundTimeFlag) {
|
||||
if (!mCheckSoundIntervalFlag) {
|
||||
mStopSoundTime = OSGetTime();
|
||||
mCheckSoundIntervalFlag = true;
|
||||
} else {
|
||||
OSTime time = OSGetTime();
|
||||
if (OSTicksToMilliseconds(time - mStopSoundTime) >= 1000) {
|
||||
mCheckSoundTimeFlag = false;
|
||||
mCheckSoundIntervalFlag = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
} else {
|
||||
if (mCheckSoundTimeFlag) {
|
||||
mCheckSoundIntervalFlag = false;
|
||||
|
||||
OSTime time = OSGetTime();
|
||||
if (OSTicksToMilliseconds(time - mPlaySoundTime) >= 480000) {
|
||||
mCheckSoundTimeFlag = false;
|
||||
mCheckSoundIntervalFlag = false;
|
||||
soundOff(1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Average radio sensitivity is 80 (see __wpadCalcRadioQuality)
|
||||
if (!mSoundOffFlag && WPADGetRadioSensitivity(chan) <= 85) {
|
||||
soundOff(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::soundOff(int msec) {
|
||||
int chan = getChan();
|
||||
|
||||
if (!WPADIsSpeakerEnabled(chan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WPADControlSpeaker(chan, WPAD_SPEAKER_MUTE, NULL);
|
||||
|
||||
OSSetAlarmUserData(&sAlarmSoundOff[chan], (void*)chan);
|
||||
OSCancelAlarm(&sAlarmSoundOff[chan]);
|
||||
OSSetAlarm(&sAlarmSoundOff[chan], OSMillisecondsToTicks(msec), &soundOnCallback);
|
||||
|
||||
mSoundOffFlag = true;
|
||||
}
|
||||
|
||||
void Controller::soundOn() {
|
||||
int chan = getChan();
|
||||
|
||||
if (WPADIsSpeakerEnabled(chan)) {
|
||||
WPADControlSpeaker(chan, WPAD_SPEAKER_UNMUTE, NULL);
|
||||
}
|
||||
|
||||
mSoundOffFlag = false;
|
||||
}
|
||||
|
||||
bool Controller::isPlayReady() const {
|
||||
return getRemoteSpk()->isPlayReady(getChan());
|
||||
}
|
||||
|
||||
HBController* Controller::getController() {
|
||||
return &mHBController;
|
||||
}
|
||||
|
||||
void Controller::startMotor() {
|
||||
if (getChan() < WPAD_MAX_CONTROLLERS && !isPlayingSound()) {
|
||||
setRumble();
|
||||
WPADControlMotor(getChan(), WPAD_MOTOR_RUMBLE);
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::stopMotor() {
|
||||
if (getChan() < WPAD_MAX_CONTROLLERS && isRumbling()) {
|
||||
clrRumble();
|
||||
WPADControlMotor(getChan(), WPAD_MOTOR_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
s32 Controller::getInfoAsync(WPADInfo* info) {
|
||||
if (getChan() >= WPAD_MAX_CONTROLLERS) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (isPlayingSound() || isRumbling()) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
return WPADGetInfoAsync(getChan(), info, &ControllerCallback);
|
||||
}
|
||||
|
||||
void Controller::ControllerCallback(s32 chan, s32 result) {
|
||||
if (result == WPAD_ESUCCESS && chan < WPAD_MAX_CONTROLLERS) {
|
||||
sBatteryFlag[chan] = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Controller::getBatteryFlag() const {
|
||||
if (getChan() >= WPAD_MAX_CONTROLLERS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return sBatteryFlag[getChan()];
|
||||
}
|
||||
|
||||
void Controller::clrBatteryFlag() {
|
||||
if (getChan() >= WPAD_MAX_CONTROLLERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
sBatteryFlag[getChan()] = false;
|
||||
}
|
||||
|
||||
} // namespace homebutton
|
||||
@@ -0,0 +1,102 @@
|
||||
#ifndef HOMEBUTTON_CONTROLLER_H
|
||||
#define HOMEBUTTON_CONTROLLER_H
|
||||
|
||||
#include <revolution/mtx.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/wpad.h>
|
||||
#include "HBMCommon.h"
|
||||
#include "HBMRemoteSpk.h"
|
||||
#include "nw4hbm/snd/SoundArchivePlayer.h"
|
||||
#include "nw4hbm/snd/SoundHandle.h"
|
||||
|
||||
|
||||
struct HBController {
|
||||
/* 0x00 */ int chan;
|
||||
/* 0x04 */ f32 spVol;
|
||||
/* 0x08 */ f32 x;
|
||||
/* 0x0C */ f32 y;
|
||||
/* 0x10 */ u32 trig;
|
||||
/* 0x14 */ u32 hold;
|
||||
/* 0x18 */ u32 release;
|
||||
/* 0x1C */ bool rumble;
|
||||
}; // size = 0x20
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
Controller(int chan, RemoteSpk* spk);
|
||||
~Controller();
|
||||
|
||||
HBController* getController();
|
||||
int getChan() const;
|
||||
f32 getSpeakerVol() const;
|
||||
RemoteSpk* getRemoteSpk() const { return remotespk; }
|
||||
bool isRumbling() { return mHBController.rumble; }
|
||||
bool getBatteryFlag() const;
|
||||
|
||||
void setSpeakerVol(f32 vol);
|
||||
void setRumble() { mHBController.rumble = true; }
|
||||
void clrRumble() { mHBController.rumble = false; }
|
||||
|
||||
s32 getInfoAsync(WPADInfo* info);
|
||||
bool isPlayReady() const;
|
||||
bool isPlayingSound() const;
|
||||
bool isPlayingSoundId(int id) const;
|
||||
|
||||
void setKpad(const HBMKPadData* con, bool updatePos);
|
||||
void setInValidPos();
|
||||
void clrBatteryFlag();
|
||||
void clrKpadButton();
|
||||
|
||||
void connect();
|
||||
void disconnect();
|
||||
|
||||
void initSound();
|
||||
void updateSound();
|
||||
void playSound(nw4hbm::snd::SoundArchivePlayer* pSoundArchivePlayer, int id);
|
||||
|
||||
void soundOn();
|
||||
void soundOff(int msec);
|
||||
|
||||
void startMotor();
|
||||
void stopMotor();
|
||||
|
||||
void initCallback();
|
||||
void clearCallback();
|
||||
|
||||
static RemoteSpk* GetInstance() { return sPInstance; }
|
||||
static void SetInstance(RemoteSpk* p) { sPInstance = p; }
|
||||
|
||||
private:
|
||||
static void wpadConnectCallback(s32 chan, s32 result);
|
||||
static void wpadExtensionCallback(s32 chan, s32 result);
|
||||
static void soundOnCallback(OSAlarm* alm, OSContext* context);
|
||||
static void ControllerCallback(s32 chan, s32 result);
|
||||
|
||||
private:
|
||||
/* 0x00 */ HBController mHBController;
|
||||
/* 0x20 */ nw4hbm::snd::SoundHandle mSoundHandle;
|
||||
/* 0x24 */ RemoteSpk* remotespk;
|
||||
/* 0x28 */ WPADConnectCallback mOldConnectCallback;
|
||||
/* 0x2C */ WPADExtensionCallback mOldExtensionCallback;
|
||||
/* 0x30 */ OSTime mPlaySoundTime;
|
||||
/* 0x38 */ OSTime mStopSoundTime;
|
||||
/* 0x40 */ bool mCallbackFlag;
|
||||
/* 0x41 */ bool mSoundOffFlag;
|
||||
/* 0x42 */ bool mCheckSoundTimeFlag;
|
||||
/* 0x43 */ bool mCheckSoundIntervalFlag;
|
||||
|
||||
private:
|
||||
static bool sBatteryFlag[WPAD_MAX_CONTROLLERS];
|
||||
static OSAlarm sAlarm[WPAD_MAX_CONTROLLERS];
|
||||
static OSAlarm sAlarmSoundOff[WPAD_MAX_CONTROLLERS];
|
||||
static Controller* sThis[WPAD_MAX_CONTROLLERS];
|
||||
static bool sSetInfoAsync[WPAD_MAX_CONTROLLERS];
|
||||
static RemoteSpk* sPInstance;
|
||||
static s32 lbl_8025DBBC;
|
||||
}; // size = 0x44
|
||||
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
|
||||
#include "HBMFrameController.h"
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
void FrameController::init(int anm_type, f32 max_frame, f32 min_frame, f32 delta) {
|
||||
mAnmType = anm_type;
|
||||
mMaxFrame = max_frame;
|
||||
mMinFrame = min_frame;
|
||||
|
||||
mDelta = delta;
|
||||
mState = ANIM_STATE_STOP;
|
||||
mbAlternateBack = false;
|
||||
|
||||
initFrame();
|
||||
}
|
||||
|
||||
void FrameController::initFrame() {
|
||||
mFrame = mAnmType == ANIM_TYPE_BACKWARD ? mMaxFrame : mMinFrame;
|
||||
}
|
||||
|
||||
void FrameController::calc() {
|
||||
if (mState != ANIM_STATE_PLAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mAnmType) {
|
||||
case ANIM_TYPE_FORWARD:
|
||||
if ((mFrame += mDelta) >= getLastFrame()) {
|
||||
mFrame = getLastFrame();
|
||||
stop();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ANIM_TYPE_BACKWARD:
|
||||
if ((mFrame -= mDelta) <= mMinFrame) {
|
||||
mFrame = mMinFrame;
|
||||
stop();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ANIM_TYPE_LOOP:
|
||||
if ((mFrame += mDelta) >= mMaxFrame) {
|
||||
mFrame -= mMaxFrame - mMinFrame;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ANIM_TYPE_ALTERNATE:
|
||||
if (!mbAlternateBack) {
|
||||
if ((mFrame += mDelta) >= getLastFrame()) {
|
||||
mFrame = getLastFrame();
|
||||
mbAlternateBack = true;
|
||||
}
|
||||
} else {
|
||||
if ((mFrame -= mDelta) <= mMinFrame) {
|
||||
mFrame = mMinFrame;
|
||||
mbAlternateBack = false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace homebutton
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef HOMEBUTTON_FRAME_CONTROLLER_H
|
||||
#define HOMEBUTTON_FRAME_CONTROLLER_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIM_TYPE_FORWARD = 0,
|
||||
/* 1 */ ANIM_TYPE_BACKWARD,
|
||||
/* 2 */ ANIM_TYPE_LOOP,
|
||||
/* 3 */ ANIM_TYPE_ALTERNATE
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIM_STATE_STOP = 0,
|
||||
/* 1 */ ANIM_STATE_PLAY,
|
||||
/* 2 */ ANIM_STATE_STOP_REQ,
|
||||
};
|
||||
|
||||
class FrameController {
|
||||
public:
|
||||
FrameController() {}
|
||||
|
||||
/* 0x08 */ virtual ~FrameController() {}
|
||||
/* 0x0C */ virtual void calc();
|
||||
|
||||
void init(int type, f32 maxFrame, f32 minFrame, f32 delta);
|
||||
void initFrame();
|
||||
|
||||
void setMaxFrame(f32 value) { mMaxFrame = value; }
|
||||
f32 getMaxFrame() const { return mMaxFrame; }
|
||||
|
||||
f32 getLastFrame() const { return mMaxFrame - 1.0f; }
|
||||
|
||||
void setMinFrame(f32 value) { mMinFrame = value; }
|
||||
f32 getMinFrame() const { return mMinFrame; }
|
||||
|
||||
void setCurrentFrame(f32 value) { mFrame = value; }
|
||||
f32 getCurrentFrame() const { return mFrame; }
|
||||
|
||||
void setDelta(f32 value) { mDelta = value; }
|
||||
f32 getDelta() const { return mDelta; }
|
||||
|
||||
void setState(int value) { mState = value; }
|
||||
int getState() const { return mState; }
|
||||
|
||||
void setAnimType(int value) { mAnmType = value; }
|
||||
int getAnimType() const { return mAnmType; }
|
||||
|
||||
bool isPlaying() const { return mState == ANIM_STATE_PLAY; }
|
||||
|
||||
void start() {
|
||||
initFrame();
|
||||
restart();
|
||||
}
|
||||
|
||||
void restart() { mState = ANIM_STATE_PLAY; }
|
||||
void stop() { mState = ANIM_STATE_STOP; }
|
||||
|
||||
protected:
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ f32 mMaxFrame;
|
||||
/* 0x08 */ f32 mMinFrame;
|
||||
/* 0x0C */ f32 mFrame;
|
||||
/* 0x10 */ f32 mDelta;
|
||||
/* 0x14 */ int mState;
|
||||
/* 0x18 */ int mAnmType;
|
||||
|
||||
private:
|
||||
/* 0x1C */ bool mbAlternateBack;
|
||||
};
|
||||
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,433 @@
|
||||
#include "HBMGUIManager.h"
|
||||
|
||||
#include "nw4hbm/lyt/bounding.h"
|
||||
#include "nw4hbm/lyt/layout.h"
|
||||
#include "nw4hbm/lyt/picture.h"
|
||||
#include "nw4hbm/lyt/window.h"
|
||||
|
||||
#include "new.h"
|
||||
|
||||
namespace homebutton {
|
||||
namespace gui {
|
||||
|
||||
u32 PaneManager::suIDCounter;
|
||||
|
||||
static void drawLine_(f32 x0, f32 y0, f32 x1, f32 y1, f32 z, u8 uWidth, GXColor& rColor);
|
||||
|
||||
static bool is_visible(nw4hbm::lyt::Pane* pPane);
|
||||
|
||||
static void drawLine_(f32 x0, f32 y0, f32 x1, f32 y1, f32 z, u8 uWidth, GXColor& rColor) {
|
||||
static const f32 cubeScale = 1.0f;
|
||||
|
||||
GXClearVtxDesc();
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
|
||||
GXSetCullMode(GX_CULL_NONE);
|
||||
|
||||
GXSetNumChans(1);
|
||||
GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE,
|
||||
GX_AF_NONE);
|
||||
|
||||
GXSetNumTexGens(0);
|
||||
GXSetNumTevStages(1);
|
||||
GXSetTevOp(GX_TEVSTAGE0, GX_BLEND);
|
||||
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
||||
GXSetBlendMode(GX_BM_NONE, GX_BL_ZERO, GX_BL_ZERO, GX_LO_NOOP);
|
||||
|
||||
Mtx modelMtx;
|
||||
PSMTXTrans(modelMtx, 0.0f, 0.0f, 0.0f);
|
||||
GXLoadPosMtxImm(modelMtx, 0);
|
||||
|
||||
GXSetLineWidth(uWidth, GX_TO_ZERO);
|
||||
|
||||
GXBegin(GX_LINES, GX_VTXFMT0, 2);
|
||||
GXPosition3f32(x0, y0, z);
|
||||
GXColor1u32(*reinterpret_cast<u32*>(&rColor));
|
||||
GXPosition3f32(x1, y1, z);
|
||||
GXColor1u32(*reinterpret_cast<u32*>(&rColor));
|
||||
GXEnd();
|
||||
}
|
||||
|
||||
bool Component::update(int i, f32 x, f32 y, u32, u32, u32, void* pData) {
|
||||
bool bTouched = false;
|
||||
|
||||
if (!isVisible()) {
|
||||
/* nothing */
|
||||
} else {
|
||||
if (contain(x, y)) {
|
||||
if (isPointed(i)) {
|
||||
onMove(x, y);
|
||||
mpManager->onEvent(getID(), 3, pData);
|
||||
} else {
|
||||
setPointed(i, true);
|
||||
onPoint();
|
||||
mpManager->onEvent(getID(), 1, pData);
|
||||
}
|
||||
|
||||
bTouched = true;
|
||||
} else {
|
||||
if (isPointed(i)) {
|
||||
setPointed(i, false);
|
||||
offPoint();
|
||||
mpManager->onEvent(getID(), 2, pData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bTouched;
|
||||
}
|
||||
|
||||
Manager::~Manager() {
|
||||
void* p = nw4hbm::ut::List_GetFirst(&mIDToComponent);
|
||||
|
||||
for (; p; p = nw4hbm::ut::List_GetFirst(&mIDToComponent)) {
|
||||
nw4hbm::ut::List_Remove(&mIDToComponent, p);
|
||||
|
||||
if (mpAllocator) {
|
||||
MEMFreeToAllocator(mpAllocator, p);
|
||||
} else {
|
||||
delete static_cast<IDToComponent*>(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::init() {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, i));
|
||||
|
||||
p->mpComponent->init();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::addComponent(Component* pComponent) {
|
||||
u32 uID = pComponent->getID();
|
||||
pComponent->setManager(this);
|
||||
|
||||
if (mpAllocator) {
|
||||
void* p = MEMAllocFromAllocator(mpAllocator, sizeof(IDToComponent));
|
||||
nw4hbm::ut::List_Append(&mIDToComponent, new (p) IDToComponent(uID, pComponent));
|
||||
} else {
|
||||
nw4hbm::ut::List_Append(&mIDToComponent, new IDToComponent(uID, pComponent));
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::delComponent(Component* pComponent) {
|
||||
IDToComponent* p =
|
||||
static_cast<IDToComponent*>(nw4hbm::ut::List_GetNext(&mIDToComponent, NULL));
|
||||
|
||||
while (p) {
|
||||
if (p->mpComponent == pComponent) {
|
||||
break;
|
||||
}
|
||||
|
||||
p = static_cast<IDToComponent*>(nw4hbm::ut::List_GetNext(&mIDToComponent, p));
|
||||
}
|
||||
|
||||
nw4hbm::ut::List_Remove(&mIDToComponent, p);
|
||||
|
||||
if (mpAllocator) {
|
||||
MEMFreeToAllocator(mpAllocator, p);
|
||||
} else {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
Component* Manager::getComponent(u32 uID) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, uID));
|
||||
|
||||
return p->mpComponent;
|
||||
}
|
||||
|
||||
bool Manager::update(int i, f32 x, f32 y, u32 uTrigFlag, u32 uHoldFlag, u32 uReleaseFlag,
|
||||
void* pData) {
|
||||
bool bTouched = false;
|
||||
Component* pLastContainedComponent = NULL;
|
||||
|
||||
for (u32 n = 0; n < nw4hbm::ut::List_GetSize(&mIDToComponent); n++) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, n));
|
||||
|
||||
if (p->mpComponent->update(i, x, y, uTrigFlag, uHoldFlag, uReleaseFlag, pData)) {
|
||||
if (p->mpComponent->isTriggerTarger()) {
|
||||
pLastContainedComponent = p->mpComponent;
|
||||
}
|
||||
|
||||
bTouched = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pLastContainedComponent) {
|
||||
if (uTrigFlag) {
|
||||
Vec pos;
|
||||
pLastContainedComponent->onTrig(uTrigFlag, pos);
|
||||
|
||||
onEvent(pLastContainedComponent->getID(), 0, pData);
|
||||
}
|
||||
|
||||
if (uReleaseFlag) {
|
||||
Vec pos;
|
||||
pLastContainedComponent->onTrig(uReleaseFlag, pos);
|
||||
|
||||
onEvent(pLastContainedComponent->getID(), 5, pData);
|
||||
}
|
||||
}
|
||||
|
||||
return bTouched;
|
||||
}
|
||||
|
||||
void Manager::calc() {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, i));
|
||||
|
||||
p->mpComponent->calc();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::draw() {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, i));
|
||||
|
||||
p->mpComponent->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::setAllComponentTriggerTarget(bool b) {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
const IDToComponent* p =
|
||||
static_cast<const IDToComponent*>(nw4hbm::ut::List_GetNth(&mIDToComponent, i));
|
||||
|
||||
p->mpComponent->setTriggerTarget(b);
|
||||
}
|
||||
}
|
||||
|
||||
PaneManager::~PaneManager() {
|
||||
PaneToComponent* pPaneToComponent =
|
||||
static_cast<PaneToComponent*>(nw4hbm::ut::List_GetFirst(&mPaneToComponent));
|
||||
|
||||
for (; pPaneToComponent; pPaneToComponent = static_cast<PaneToComponent*>(
|
||||
nw4hbm::ut::List_GetFirst(&mPaneToComponent)))
|
||||
{
|
||||
nw4hbm::ut::List_Remove(&mPaneToComponent, pPaneToComponent);
|
||||
|
||||
if (mpAllocator) {
|
||||
MEMFreeToAllocator(mpAllocator, pPaneToComponent->mpComponent);
|
||||
MEMFreeToAllocator(mpAllocator, pPaneToComponent);
|
||||
} else {
|
||||
delete pPaneToComponent->mpComponent;
|
||||
delete pPaneToComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PaneManager::createLayoutScene(const nw4hbm::lyt::Layout& rLayout) {
|
||||
suIDCounter = 0;
|
||||
|
||||
nw4hbm::lyt::Pane* pRootPane = rLayout.GetRootPane();
|
||||
|
||||
walkInChildren(pRootPane->GetChildList());
|
||||
}
|
||||
|
||||
void PaneManager::addLayoutScene(const nw4hbm::lyt::Layout& rLayout) {
|
||||
nw4hbm::lyt::Pane* pRootPane = rLayout.GetRootPane();
|
||||
|
||||
walkInChildren(pRootPane->GetChildList());
|
||||
}
|
||||
|
||||
void PaneManager::walkInChildren(nw4hbm::lyt::PaneList& rPaneList) {
|
||||
for (nw4hbm::lyt::PaneList::Iterator it = rPaneList.GetBeginIter();
|
||||
it != rPaneList.GetEndIter(); it++)
|
||||
{
|
||||
PaneComponent* pPaneComponent = NULL;
|
||||
PaneToComponent* pPaneToComponent = NULL;
|
||||
|
||||
if (mpAllocator) {
|
||||
void* p1 = MEMAllocFromAllocator(mpAllocator, sizeof(*pPaneComponent));
|
||||
void* p2 = MEMAllocFromAllocator(mpAllocator, sizeof(*pPaneToComponent));
|
||||
|
||||
pPaneComponent = new (p1) PaneComponent(suIDCounter);
|
||||
pPaneToComponent = new (p2) PaneToComponent(&(*it), pPaneComponent);
|
||||
} else {
|
||||
pPaneComponent = new PaneComponent(suIDCounter);
|
||||
pPaneToComponent = new PaneToComponent(&(*it), pPaneComponent);
|
||||
}
|
||||
|
||||
nw4hbm::ut::List_Append(&mPaneToComponent, pPaneToComponent);
|
||||
suIDCounter++;
|
||||
|
||||
pPaneComponent->setPane(&(*it));
|
||||
|
||||
if (nw4hbm::ut::DynamicCast<nw4hbm::lyt::Picture*>(&(*it))) {
|
||||
pPaneComponent->setTriggerTarget(true);
|
||||
}
|
||||
|
||||
if (nw4hbm::ut::DynamicCast<nw4hbm::lyt::Window*>(&(*it))) {
|
||||
pPaneComponent->setTriggerTarget(true);
|
||||
}
|
||||
|
||||
addComponent(pPaneComponent);
|
||||
walkInChildren(it->GetChildList());
|
||||
}
|
||||
}
|
||||
|
||||
void PaneManager::delLayoutScene(const nw4hbm::lyt::Layout& rLayout) {
|
||||
nw4hbm::lyt::Pane* pRootPane = rLayout.GetRootPane();
|
||||
|
||||
walkInChildrenDel(pRootPane->GetChildList());
|
||||
}
|
||||
|
||||
void PaneManager::walkInChildrenDel(nw4hbm::lyt::PaneList& rPaneList) {
|
||||
for (nw4hbm::lyt::PaneList::Iterator it = rPaneList.GetBeginIter();
|
||||
it != rPaneList.GetEndIter(); it++)
|
||||
{
|
||||
PaneToComponent* pPaneToComponent = static_cast<PaneToComponent*>(
|
||||
nw4hbm::ut::List_GetNext(&mPaneToComponent, NULL));
|
||||
|
||||
while (pPaneToComponent) {
|
||||
if (pPaneToComponent->mpPane == &(*it)) {
|
||||
break;
|
||||
}
|
||||
|
||||
pPaneToComponent = static_cast<PaneToComponent*>(
|
||||
nw4hbm::ut::List_GetNext(&mPaneToComponent, pPaneToComponent));
|
||||
}
|
||||
|
||||
delComponent(pPaneToComponent->mpComponent);
|
||||
nw4hbm::ut::List_Remove(&mPaneToComponent, pPaneToComponent);
|
||||
suIDCounter--;
|
||||
|
||||
if (mpAllocator) {
|
||||
MEMFreeToAllocator(mpAllocator, pPaneToComponent->mpComponent);
|
||||
MEMFreeToAllocator(mpAllocator, pPaneToComponent);
|
||||
} else {
|
||||
delete pPaneToComponent->mpComponent;
|
||||
delete pPaneToComponent;
|
||||
}
|
||||
|
||||
walkInChildrenDel(it->GetChildList());
|
||||
}
|
||||
}
|
||||
|
||||
PaneComponent* PaneManager::getPaneComponentByPane(nw4hbm::lyt::Pane* pPane) {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
PaneToComponent* p =
|
||||
static_cast<PaneToComponent*>(nw4hbm::ut::List_GetNth(&mPaneToComponent, i));
|
||||
|
||||
if (p->mpPane == pPane) {
|
||||
return p->mpComponent;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#pragma push
|
||||
#pragma opt_propagation off // ???
|
||||
|
||||
void PaneManager::setAllBoundingBoxComponentTriggerTarget(bool b) {
|
||||
for (u32 i = 0; i < nw4hbm::ut::List_GetSize(&mIDToComponent); i++) {
|
||||
PaneToComponent* p =
|
||||
static_cast<PaneToComponent*>(nw4hbm::ut::List_GetNth(&mPaneToComponent, i));
|
||||
|
||||
if (nw4hbm::ut::DynamicCast<nw4hbm::lyt::Bounding*>(p->mpPane)) {
|
||||
p->mpComponent->setTriggerTarget(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma pop
|
||||
|
||||
bool PaneComponent::contain(f32 x_, f32 y_) {
|
||||
if (!mpManager) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// goes into PaneManager vtable?
|
||||
const nw4hbm::lyt::DrawInfo* pDrawInfo =
|
||||
static_cast<PaneManager*>(mpManager)->getDrawInfo();
|
||||
|
||||
if (!pDrawInfo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nw4hbm::math::MTX34 invGlbMtx;
|
||||
PSMTXInverse(mpPane->GetGlobalMtx(), invGlbMtx);
|
||||
|
||||
nw4hbm::math::VEC3 lclPos;
|
||||
PSMTXMultVec(invGlbMtx, nw4hbm::math::VEC3(x_, y_, 0.0f), lclPos);
|
||||
|
||||
nw4hbm::ut::Rect rect = mpPane->GetPaneRect(*pDrawInfo);
|
||||
|
||||
if (rect.left <= lclPos.x && lclPos.x <= rect.right && rect.bottom <= lclPos.y &&
|
||||
lclPos.y <= rect.top)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void PaneComponent::draw() {
|
||||
const nw4hbm::lyt::DrawInfo* pDrawInfo =
|
||||
static_cast<PaneManager*>(mpManager)->getDrawInfo();
|
||||
|
||||
if (!pDrawInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// some stripped debug thing?
|
||||
const nw4hbm::math::VEC3& translate = mpPane->GetTranslate();
|
||||
|
||||
nw4hbm::lyt::Size size = mpPane->GetSize();
|
||||
|
||||
const nw4hbm::math::MTX34& gmtx = mpPane->GetGlobalMtx();
|
||||
|
||||
f32 x = gmtx.mtx[0][3];
|
||||
f32 y = gmtx.mtx[1][3];
|
||||
|
||||
GXColor color = {0xff, 0x00, 0x00, 0xff}; // red
|
||||
|
||||
if (mabPointed[0]) {
|
||||
color.r = 0x00;
|
||||
color.b = 0xff; // now blue
|
||||
}
|
||||
|
||||
// start at top left, go clockwise
|
||||
drawLine_(x - size.width / 2.0f, y - size.height / 2.0f, x + size.width / 2.0f,
|
||||
y - size.height / 2.0f, 0.0f, 8, color);
|
||||
drawLine_(x + size.width / 2.0f, y - size.height / 2.0f, x + size.width / 2.0f,
|
||||
y + size.height / 2.0f, 0.0f, 8, color);
|
||||
drawLine_(x + size.width / 2.0f, y + size.height / 2.0f, x - size.width / 2.0f,
|
||||
y + size.height / 2.0f, 0.0f, 8, color);
|
||||
drawLine_(x - size.width / 2.0f, y + size.height / 2.0f, x - size.width / 2.0f,
|
||||
y - size.height / 2.0f, 0.0f, 8, color);
|
||||
}
|
||||
|
||||
#pragma global_optimizer off // ...ok!
|
||||
|
||||
static bool is_visible(nw4hbm::lyt::Pane* pPane) {
|
||||
if (!pPane->IsVisible()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pPane->GetParent()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return is_visible(pPane->GetParent());
|
||||
}
|
||||
|
||||
bool PaneComponent::isVisible() {
|
||||
return is_visible(mpPane);
|
||||
}
|
||||
|
||||
#pragma global_optimizer reset
|
||||
|
||||
} // namespace gui
|
||||
} // namespace homebutton
|
||||
@@ -0,0 +1,234 @@
|
||||
#ifndef HOMEBUTTON_GUI_MANAGER_H
|
||||
#define HOMEBUTTON_GUI_MANAGER_H
|
||||
|
||||
#include <revolution/kpad.h>
|
||||
#include <revolution/mem.h>
|
||||
#include <revolution/mtx.h>
|
||||
#include "nw4hbm/lyt/pane.h"
|
||||
#include "nw4hbm/ut/list.h"
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
class DrawInfo;
|
||||
class Layout;
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace homebutton {
|
||||
namespace gui {
|
||||
|
||||
class Manager;
|
||||
class PaneComponent;
|
||||
|
||||
class Interface {
|
||||
public:
|
||||
Interface() {}
|
||||
|
||||
/* 0x08 */ virtual void create() {}
|
||||
/* 0x0C */ virtual void init() {}
|
||||
/* 0x10 */ virtual void calc() {}
|
||||
/* 0x14 */ virtual void draw(Mtx&) {}
|
||||
/* 0x18 */ virtual void draw() {}
|
||||
/* 0x1C */ virtual ~Interface() {}
|
||||
|
||||
private:
|
||||
/* 0x00 (vtable) */
|
||||
}; // size = 0x04
|
||||
|
||||
class EventHandler {
|
||||
public:
|
||||
EventHandler() {}
|
||||
|
||||
/* 0x08 */ virtual void onEvent(u32, u32, void*) {}
|
||||
/* 0x0C */ virtual void setManager(Manager* pManager) { mpManager = pManager; }
|
||||
|
||||
protected:
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ Manager* mpManager;
|
||||
}; // size = 0x08
|
||||
|
||||
class Component : public Interface {
|
||||
public:
|
||||
Component(u32 uID)
|
||||
: mDragStartPos(), mbDragging(), muDraggingButton(), muID(uID), mbTriggerTarger(),
|
||||
mpManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
/* 0x0C */ virtual void init() {
|
||||
mbDragging = false;
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mabPointed); i++) {
|
||||
mabPointed[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* 0x1C */ virtual ~Component() {}
|
||||
/* 0x20 */ virtual u32 getID() { return muID; }
|
||||
/* 0x24 */ virtual int isPointed(int n) { return mabPointed[n]; }
|
||||
/* 0x28 */ virtual void setPointed(int n, bool b) { mabPointed[n] = b; }
|
||||
/* 0x2C */ virtual void onPoint() {}
|
||||
/* 0x30 */ virtual void offPoint() {}
|
||||
/* 0x34 */ virtual void onDrag(f32, f32) {}
|
||||
/* 0x38 */ virtual void onMove(f32, f32) {}
|
||||
|
||||
/* 0x3C */ virtual void onTrig(u32 uFlag, Vec& vec) {
|
||||
if (uFlag & muDraggingButton) {
|
||||
mDragStartPos = vec;
|
||||
mbDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* 0x40 */ virtual void setDraggingButton(u32 uDraggingButton) {
|
||||
muDraggingButton = uDraggingButton;
|
||||
}
|
||||
/* 0x44 */ virtual bool update(int, const KPADStatus*, f32, f32, void*) {
|
||||
return false;
|
||||
}
|
||||
/* 0x48 */ virtual bool update(int i, f32 x, f32 y, u32 uTrigFlag, u32 uHoldFlag,
|
||||
u32 uReleaseFlag, void* pData);
|
||||
/* 0x4C */ virtual bool isTriggerTarger() { return mbTriggerTarger; }
|
||||
/* 0x50 */ virtual void setTriggerTarget(bool bTriggerTarget) {
|
||||
mbTriggerTarger = bTriggerTarget;
|
||||
}
|
||||
/* 0x54 */ virtual void setManager(Manager* pManager) { mpManager = pManager; }
|
||||
/* 0x58 */ virtual bool isVisible() { return true; }
|
||||
/* 0x5C */ virtual bool contain(f32 x_, f32 y_) = 0;
|
||||
|
||||
protected:
|
||||
/* 0x00 (base) */
|
||||
/* 0x04 */ bool mabPointed[8];
|
||||
/* 0x0C */ Vec mDragStartPos;
|
||||
/* 0x18 */ bool mbDragging;
|
||||
/* 0x1C */ u32 muDraggingButton;
|
||||
/* 0x20 */ u32 muID;
|
||||
/* 0x24 */ bool mbTriggerTarger;
|
||||
/* 0x28 */ Manager* mpManager;
|
||||
}; // size = 0x2C
|
||||
|
||||
class Manager : public Interface {
|
||||
// nested types
|
||||
private:
|
||||
struct IDToComponent {
|
||||
public:
|
||||
/* 0x00 */ u32 muID;
|
||||
/* 0x04 */ Component* mpComponent;
|
||||
/* 0x08 */ nw4hbm::ut::Link mLink;
|
||||
|
||||
IDToComponent(u32 uID, Component* pComponent)
|
||||
: muID(uID), mpComponent(pComponent) {}
|
||||
}; // size = 0x10
|
||||
|
||||
public:
|
||||
Manager(EventHandler* pEventHandler, MEMAllocator* pAllocator)
|
||||
: mpEventHandler(pEventHandler), mpAllocator(pAllocator) {
|
||||
if (mpEventHandler) {
|
||||
mpEventHandler->setManager(this);
|
||||
}
|
||||
|
||||
nw4hbm::ut::List_Init(&mIDToComponent, 8);
|
||||
}
|
||||
|
||||
/* 0x0C */ virtual void init();
|
||||
/* 0x10 */ virtual void calc();
|
||||
/* 0x18 */ virtual void draw();
|
||||
/* 0x1C */ virtual ~Manager();
|
||||
/* 0x20 */ virtual void addComponent(Component* pComponent);
|
||||
/* 0x24 */ virtual Component* getComponent(u32 uID);
|
||||
/* 0x28 */ virtual bool update(int, const KPADStatus*, f32, f32, void*) {
|
||||
return false;
|
||||
}
|
||||
/* 0x2C */ virtual bool update(int i, f32 x, f32 y, u32 uTrigFlag, u32 uHoldFlag,
|
||||
u32 uReleaseFlag, void* pData);
|
||||
|
||||
/* 0x30 */ virtual void onEvent(u32 uID, u32 uEvent, void* pData) {
|
||||
if (mpEventHandler) {
|
||||
mpEventHandler->onEvent(uID, uEvent, pData);
|
||||
}
|
||||
}
|
||||
|
||||
/* 0x34 */ virtual void setAllComponentTriggerTarget(bool b);
|
||||
|
||||
/* 0x38 */ virtual void setEventHandler(EventHandler* pEventHandler) {
|
||||
mpEventHandler = pEventHandler;
|
||||
|
||||
if (mpEventHandler) {
|
||||
mpEventHandler->setManager(this);
|
||||
}
|
||||
}
|
||||
|
||||
void delComponent(Component* pComponent);
|
||||
|
||||
protected:
|
||||
/* 0x00 (base) */
|
||||
/* 0x04 */ EventHandler* mpEventHandler;
|
||||
/* 0x08 */ nw4hbm::ut::List mIDToComponent;
|
||||
/* 0x14 */ MEMAllocator* mpAllocator;
|
||||
}; // size = 0x18
|
||||
|
||||
class PaneManager : public Manager {
|
||||
// nested types
|
||||
private:
|
||||
struct PaneToComponent {
|
||||
public:
|
||||
PaneToComponent(nw4hbm::lyt::Pane* pPane, PaneComponent* pComponent)
|
||||
: mpPane(pPane), mpComponent(pComponent) {}
|
||||
|
||||
public:
|
||||
/* 0x00 */ nw4hbm::lyt::Pane* mpPane;
|
||||
/* 0x04 */ PaneComponent* mpComponent;
|
||||
/* 0x08 */ nw4hbm::ut::Link mLink;
|
||||
}; // size = 0x10
|
||||
|
||||
public:
|
||||
PaneManager(EventHandler* pEventHandler, const nw4hbm::lyt::DrawInfo* pDrawInfo,
|
||||
MEMAllocator* pAllocator)
|
||||
: Manager(pEventHandler, pAllocator), mpDrawInfo(pDrawInfo) {
|
||||
nw4hbm::ut::List_Init(&mPaneToComponent, 8);
|
||||
}
|
||||
|
||||
/* 0x1C */ virtual ~PaneManager();
|
||||
/* 0x30 */ virtual void createLayoutScene(const nw4hbm::lyt::Layout& rLayout);
|
||||
/* 0x34 */ virtual PaneComponent* getPaneComponentByPane(nw4hbm::lyt::Pane* pPane);
|
||||
/* 0x38 */ virtual const nw4hbm::lyt::DrawInfo* getDrawInfo() { return mpDrawInfo; }
|
||||
/* 0x3C */ virtual void setDrawInfo(const nw4hbm::lyt::DrawInfo* pDrawInfo) {
|
||||
mpDrawInfo = pDrawInfo;
|
||||
}
|
||||
/* 0x40 */ virtual void setAllBoundingBoxComponentTriggerTarget(bool b);
|
||||
/* 0x44 */ virtual void walkInChildren(nw4hbm::lyt::PaneList& rPaneList);
|
||||
|
||||
void walkInChildrenDel(nw4hbm::lyt::PaneList& rPaneList);
|
||||
void delLayoutScene(const nw4hbm::lyt::Layout& rLayout);
|
||||
void addLayoutScene(const nw4hbm::lyt::Layout& rLayout);
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0x18 */ nw4hbm::ut::List mPaneToComponent;
|
||||
/* 0x24 */ const nw4hbm::lyt::DrawInfo* mpDrawInfo;
|
||||
/* 0x28 */ u16 muNumPoint;
|
||||
u16 muPadding;
|
||||
|
||||
// static members
|
||||
static u32 suIDCounter;
|
||||
}; // size = 0x2C
|
||||
|
||||
class PaneComponent : public Component {
|
||||
public:
|
||||
PaneComponent(u32 uID) : Component(uID), mpPane() {}
|
||||
|
||||
/* 0x18 */ virtual void draw();
|
||||
/* 0x1C */ virtual ~PaneComponent() {}
|
||||
/* 0x20 */ virtual bool isVisible();
|
||||
/* 0x24 */ virtual bool contain(f32 x_, f32 y_);
|
||||
/* 0x28 */ virtual void setPane(nw4hbm::lyt::Pane* pPane) { mpPane = pPane; }
|
||||
/* 0x2C */ virtual nw4hbm::lyt::Pane* getPane() { return mpPane; }
|
||||
|
||||
protected:
|
||||
/* 0x00 (base) */
|
||||
/* 0x2C */ nw4hbm::lyt::Pane* mpPane;
|
||||
}; // size = 0x30
|
||||
} // namespace gui
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,259 @@
|
||||
#include "HBMRemoteSpk.h"
|
||||
|
||||
#include "HBMController.h"
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
static bool MakeVolumeData(const s16* src, s16* dst, int vol, u32 size);
|
||||
|
||||
void RemoteSpk::SetInstance(RemoteSpk* pThis) {
|
||||
Controller::SetInstance(pThis);
|
||||
}
|
||||
|
||||
RemoteSpk* RemoteSpk::GetInstance(void) {
|
||||
return Controller::GetInstance();
|
||||
}
|
||||
|
||||
void RemoteSpk::GetPCMFromSeID(int in_ID, s16*& out_wave, int& out_length) {
|
||||
ARCFileInfo af;
|
||||
ARCFastOpen(&handle, in_ID, &af);
|
||||
|
||||
out_wave = static_cast<s16*>(ARCGetStartAddrInMem(&af));
|
||||
out_length = ARCGetLength(&af);
|
||||
|
||||
ARCClose(&af);
|
||||
}
|
||||
|
||||
static bool MakeVolumeData(const s16* src, s16* dst, int vol, u32 size) {
|
||||
u32 enc_size = size <= 40 ? size : 40;
|
||||
for (int i = 0; (u32)i < enc_size; i++) {
|
||||
*dst++ = static_cast<s16>(*src++ * vol / 10);
|
||||
}
|
||||
|
||||
if (size > 40) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 zero_size = 40 - size;
|
||||
for (int i = 0; (u32)i < zero_size; i++) {
|
||||
*dst++ = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteSpk::UpdateSpeaker(OSAlarm*, OSContext*) {
|
||||
s16 pcmBuffer[40];
|
||||
u8 adpcmBuffer[20];
|
||||
|
||||
if (!GetInstance()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ChanInfo* pinfo = GetInstance()->info;
|
||||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++, pinfo++) {
|
||||
if (pinfo->in_pcm && WPADIsSpeakerEnabled(i)) {
|
||||
int intrStatus = OSDisableInterrupts(); /* int intr */
|
||||
|
||||
if (WPADCanSendStreamData(i)) {
|
||||
MakeVolumeData(pinfo->in_pcm, pcmBuffer, pinfo->vol,
|
||||
static_cast<u32>(pinfo->length) / sizeof(s16));
|
||||
WENCGetEncodeData(&pinfo->wencinfo, pinfo->first ? 0 : 1, pcmBuffer, 40,
|
||||
adpcmBuffer);
|
||||
WPADSendStreamData(i, adpcmBuffer, 20);
|
||||
|
||||
pinfo->first = false;
|
||||
pinfo->cannotSendCnt = 0;
|
||||
pinfo->in_pcm += 40;
|
||||
pinfo->length -= 40 * sizeof(s16);
|
||||
|
||||
if (pinfo->length <= 0) {
|
||||
pinfo->seId = -1;
|
||||
pinfo->in_pcm = NULL;
|
||||
}
|
||||
} else {
|
||||
pinfo->cannotSendCnt++;
|
||||
|
||||
#if HBM_REVISION == 1
|
||||
if (pinfo->cannotSendCnt > 300) {
|
||||
pinfo->in_pcm = NULL;
|
||||
}
|
||||
#else
|
||||
if (pinfo->cannotSendCnt > 60) {
|
||||
pinfo->in_pcm = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(intrStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSpk::ClearPcm(void) {
|
||||
ChanInfo* info = GetInstance()->info;
|
||||
|
||||
info->seId = -1;
|
||||
info->in_pcm = NULL;
|
||||
}
|
||||
|
||||
RemoteSpk::RemoteSpk(void* spkSeBuf) {
|
||||
SetInstance(this);
|
||||
|
||||
if (spkSeBuf) {
|
||||
available = ARCInitHandle(spkSeBuf, &handle) ? TRUE : FALSE;
|
||||
} else {
|
||||
available = false;
|
||||
}
|
||||
|
||||
OSCreateAlarm(&speakerAlarm);
|
||||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
|
||||
OSCreateAlarm(&info[i].alarm);
|
||||
info[i].in_pcm = NULL;
|
||||
info[i].seId = -1;
|
||||
info[i].first = true;
|
||||
info[i].playReady = true;
|
||||
}
|
||||
}
|
||||
|
||||
RemoteSpk::~RemoteSpk(void) {
|
||||
#if HBM_REVISION > 1
|
||||
SetInstance(NULL);
|
||||
#endif
|
||||
|
||||
available = false;
|
||||
|
||||
OSCancelAlarm(&speakerAlarm);
|
||||
|
||||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
|
||||
#if HBM_REVISION == 1
|
||||
WPADControlSpeaker(i, WPAD_SPEAKER_OFF, NULL);
|
||||
#endif
|
||||
|
||||
OSCancelAlarm(&info[i].alarm);
|
||||
}
|
||||
|
||||
#if HBM_REVISION == 1
|
||||
SetInstance(NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RemoteSpk::Start(void) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
OSCreateAlarm(&speakerAlarm);
|
||||
OSSetPeriodicAlarm(&speakerAlarm, OSGetTime(), OSNanosecondsToTicks(6666667),
|
||||
&UpdateSpeaker);
|
||||
}
|
||||
|
||||
void RemoteSpk::Stop(void) {
|
||||
OSCancelAlarm(&speakerAlarm);
|
||||
}
|
||||
|
||||
void RemoteSpk::DelaySpeakerOnCallback(OSAlarm* alarm, OSContext*) {
|
||||
s32 chan = (s32)OSGetAlarmUserData(alarm);
|
||||
s32 result = WPADControlSpeaker(chan, WPAD_SPEAKER_ENABLE, SpeakerOnCallback);
|
||||
}
|
||||
|
||||
void RemoteSpk::SpeakerOnCallback(s32 chan, s32 result) {
|
||||
RemoteSpk* pRmtSpk = GetInstance();
|
||||
if (!pRmtSpk) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case WPAD_ESUCCESS:
|
||||
pRmtSpk->info[chan].first = true;
|
||||
result = WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, &SpeakerPlayCallback);
|
||||
break;
|
||||
|
||||
case WPAD_EBUSY:
|
||||
OSSetAlarmUserData(&pRmtSpk->info[chan].alarm, (void*)chan);
|
||||
OSCancelAlarm(&pRmtSpk->info[chan].alarm);
|
||||
OSSetAlarm(&pRmtSpk->info[chan].alarm, OSMillisecondsToTicks(50),
|
||||
&DelaySpeakerOnCallback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSpk::DelaySpeakerPlayCallback(OSAlarm* alarm, OSContext*) {
|
||||
s32 chan = (s32)OSGetAlarmUserData(alarm);
|
||||
s32 result = WPADControlSpeaker(chan, WPAD_SPEAKER_PLAY, &SpeakerPlayCallback);
|
||||
}
|
||||
|
||||
void RemoteSpk::SpeakerPlayCallback(s32 chan, s32 result) {
|
||||
RemoteSpk* pRmtSpk = GetInstance();
|
||||
if (!pRmtSpk) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case WPAD_ESUCCESS:
|
||||
pRmtSpk->info[chan].playReady = true;
|
||||
break;
|
||||
|
||||
case WPAD_ENODEV:
|
||||
pRmtSpk->info[chan].playReady = false;
|
||||
break;
|
||||
|
||||
case WPAD_EBUSY:
|
||||
OSSetAlarmUserData(&pRmtSpk->info[chan].alarm, (void*)chan);
|
||||
OSCancelAlarm(&pRmtSpk->info[chan].alarm);
|
||||
OSSetAlarm(&pRmtSpk->info[chan].alarm, OSMillisecondsToTicks(50),
|
||||
&DelaySpeakerPlayCallback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSpk::Connect(s32 chan) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
// int?
|
||||
int result = WPADControlSpeaker(chan, WPAD_SPEAKER_ENABLE, &SpeakerOnCallback);
|
||||
|
||||
u32* p = reinterpret_cast<u32*>(&info[chan].wencinfo);
|
||||
memset(p, 0, sizeof(WENCInfo));
|
||||
|
||||
info[chan].first = true;
|
||||
info[chan].playReady = false;
|
||||
}
|
||||
|
||||
void RemoteSpk::Play(s32 chan, int seID, s8 vol) {
|
||||
if (!available) {
|
||||
return;
|
||||
}
|
||||
|
||||
s16* pcm;
|
||||
int length;
|
||||
GetPCMFromSeID(seID, pcm, length);
|
||||
|
||||
info[chan].cannotSendCnt = 0;
|
||||
info[chan].seId = seID;
|
||||
info[chan].length = length;
|
||||
info[chan].vol = vol;
|
||||
info[chan].in_pcm = pcm;
|
||||
}
|
||||
|
||||
bool RemoteSpk::isPlaying(s32 chan) const {
|
||||
return info[chan].in_pcm != NULL;
|
||||
}
|
||||
|
||||
bool RemoteSpk::isPlayingId(s32 chan, int seId) const {
|
||||
if (isPlaying(chan) && info[chan].seId == seId) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteSpk::isPlayReady(s32 chan) const {
|
||||
return info[chan].playReady != false;
|
||||
}
|
||||
|
||||
} // namespace homebutton
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef HOMEBUTTON_REMOTE_SPK_H
|
||||
#define HOMEBUTTON_REMOTE_SPK_H
|
||||
|
||||
#include <revolution/arc.h>
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/wenc.h>
|
||||
#include <revolution/wpad.h>
|
||||
|
||||
namespace homebutton {
|
||||
|
||||
class RemoteSpk {
|
||||
private:
|
||||
struct ChanInfo {
|
||||
/* 0x00 */ OSAlarm alarm;
|
||||
/* 0x30 */ WENCInfo wencinfo;
|
||||
/* 0x50 */ const s16* in_pcm;
|
||||
/* 0x54 */ int length;
|
||||
/* 0x58 */ int seId;
|
||||
/* 0x5C */ bool first;
|
||||
/* 0x5D */ s8 vol;
|
||||
/* 0x5E */ s8 cannotSendCnt;
|
||||
/* 0x60 */ u16 pad_60;
|
||||
/* 0x62 */ bool playReady;
|
||||
}; // size = 0x68
|
||||
|
||||
public:
|
||||
RemoteSpk(void* spkSeBuf);
|
||||
|
||||
bool isPlayReady(s32 chan) const;
|
||||
bool isPlaying(s32 chan) const;
|
||||
bool isPlayingId(s32 chan, int seId) const;
|
||||
|
||||
void GetPCMFromSeID(int in_ID, s16*& out_wave, int& out_length);
|
||||
void ClearPcm();
|
||||
void Start();
|
||||
void Stop();
|
||||
void Connect(s32 chan);
|
||||
void Play(s32 chan, int seID, s8 vol);
|
||||
|
||||
static void SetInstance(RemoteSpk* pThis);
|
||||
static RemoteSpk* GetInstance();
|
||||
|
||||
private:
|
||||
static void UpdateSpeaker(OSAlarm* alarm, OSContext* context);
|
||||
|
||||
static void SpeakerOnCallback(s32 chan, s32 result);
|
||||
static void DelaySpeakerOnCallback(OSAlarm* alarm, OSContext* context);
|
||||
|
||||
static void SpeakerPlayCallback(s32 chan, s32 result);
|
||||
static void DelaySpeakerPlayCallback(OSAlarm* alarm, OSContext* context);
|
||||
|
||||
private:
|
||||
/* 0x000 */ ChanInfo info[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x1A0 */ OSAlarm speakerAlarm;
|
||||
/* 0x1D0 */ ARCHandle handle;
|
||||
/* 0x1EC */ bool available;
|
||||
/* 0x1F0 (vtable) */
|
||||
|
||||
public:
|
||||
/* 0x08 */ virtual ~RemoteSpk();
|
||||
}; // size = 0x1F8
|
||||
|
||||
} // namespace homebutton
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef NW4R_DB_DBG_PRINT_BASE_H
|
||||
#define NW4R_DB_DBG_PRINT_BASE_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
|
||||
}
|
||||
} // namespace nw4r
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
#ifndef NW4R_DB_ASSERT_H
|
||||
#define NW4R_DB_ASSERT_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
// Forward declarations
|
||||
namespace detail {
|
||||
class ConsoleHead;
|
||||
}
|
||||
|
||||
/* DECL_WEAK */ void VPanic(const char* file, int line, const char* fmt, std::va_list vlist);
|
||||
/* DECL_WEAK */ void VWarning(const char* file, int line, const char* fmt, std::va_list vlist);
|
||||
|
||||
namespace detail {
|
||||
void Log(const char* fmt, ...);
|
||||
/* DECL_WEAK */ void Panic(const char* file, int line, const char* fmt, ...);
|
||||
/* DECL_WEAK */ void Warning(const char* file, int line, const char* msg, ...);
|
||||
}
|
||||
|
||||
detail::ConsoleHead* Assertion_SetConsole(detail::ConsoleHead* console);
|
||||
detail::ConsoleHead* Assertion_GetConsole();
|
||||
void Assertion_ShowConsole(u32 time);
|
||||
void Assertion_HideConsole();
|
||||
void Assertion_SetWarningTime(u32 time);
|
||||
bool Assertion_SetAutoWarning(bool enable);
|
||||
} // namespace db
|
||||
} // namespace nw4r
|
||||
|
||||
#if NW4HBM_DEBUG
|
||||
#define NW4R_DB_WARNING(line, exp, ...) \
|
||||
(void)((exp) || (nw4hbm::db::detail::Warning(__FILE__, line, __VA_ARGS__), 0))
|
||||
#define NW4R_DB_ASSERTMSG(line, exp, ...) \
|
||||
(void)((exp) || (nw4hbm::db::detail::Panic(__FILE__, line, __VA_ARGS__), 0))
|
||||
#else
|
||||
#define NW4R_DB_WARNING(line, exp, ...) (void)0
|
||||
#define NW4R_DB_ASSERTMSG(line, exp, ...) (void)0
|
||||
#endif
|
||||
|
||||
#define NW4R_ASSERT(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, (exp), "Failed assertion " #exp)
|
||||
|
||||
#define NW4R_ASSERT_CHECK_NULL(line, ptr) \
|
||||
NW4R_DB_ASSERTMSG(line, (ptr != NULL), "Pointer must not be NULL ("#ptr")")
|
||||
|
||||
#define POINTER_VALID_TEST(ptr_) \
|
||||
(((unsigned long)ptr_ & 0xFF000000) == 0x80000000 || ((unsigned long)ptr_ & 0xFF800000) == 0x81000000 || \
|
||||
((unsigned long)ptr_ & 0xF8000000) == 0x90000000 || ((unsigned long)ptr_ & 0xFF000000) == 0xC0000000 || \
|
||||
((unsigned long)ptr_ & 0xFF800000) == 0xC1000000 || ((unsigned long)ptr_ & 0xF8000000) == 0xD0000000 || \
|
||||
((unsigned long)ptr_ & 0xFFFFC000) == 0xE0000000)
|
||||
|
||||
#define NW4R_ASSERT_VALID_PTR(line, ptr) \
|
||||
NW4R_DB_ASSERTMSG(line, POINTER_VALID_TEST(ptr), "Pointer Error\n" #ptr "(=%p) is not valid pointer.", ptr)
|
||||
|
||||
#define NW4R_ASSERT_MIN(line_, var_, minValue_) \
|
||||
NW4R_DB_ASSERTMSG(line_, minValue_ <= var_, \
|
||||
#var_ " is out of bounds(%d)\n%d <= " #var_ " not satisfied.", (int)(var_), \
|
||||
(int)(minValue_))
|
||||
|
||||
#define NW4R_ASSERT_MINMAX(line_, var_, minValue_, maxValue_) \
|
||||
NW4R_DB_ASSERTMSG(line_, (var_) >= (minValue_) && (var_) < (maxValue_), \
|
||||
#var_ " is out of bounds(%d)\n%d <= " #var_ " < %d not satisfied.", (int)(var_), \
|
||||
(int)(minValue_), (int)(maxValue_))
|
||||
|
||||
#define NW4R_ASSERT_MINMAXLT(line_, var_, minValue_, maxValue_) \
|
||||
NW4R_DB_ASSERTMSG(line_, (var_) >= (minValue_) && (var_) <= (maxValue_), \
|
||||
#var_ " is out of bounds(%d)\n%d <= " #var_ " <= %d not satisfied.", (int)(var_), \
|
||||
(int)(minValue_), (int)(maxValue_))
|
||||
|
||||
#define NW4R_IS_ALIGNED_(x, align) \
|
||||
(((unsigned long)(x) & ((align) - 1)) == 0)
|
||||
|
||||
#define NW4R_ASSERT_ALIGN2(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, NW4R_IS_ALIGNED_(exp, 2), \
|
||||
"Alignment Error(0x%x)\n" #exp " must be aligned to 2 bytes boundary.", \
|
||||
exp)
|
||||
|
||||
#define NW4R_ASSERT_ALIGN32(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, NW4R_IS_ALIGNED_(exp, 32), \
|
||||
"Alignment Error(0x%x)\n" #exp " must be aligned to 32 bytes boundary.", \
|
||||
exp)
|
||||
|
||||
// NW4HBM variants
|
||||
#define NW4HBM_ASSERT_CHECK_NULL(line, ptr) \
|
||||
NW4R_DB_ASSERTMSG(line, (ptr != NULL), "NW4HBM:Pointer must not be NULL ("#ptr")")
|
||||
|
||||
#define NW4HBM_ASSERT(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, (exp), "NW4HBM:Failed assertion " #exp)
|
||||
|
||||
#define NW4HBM_ASSERT_VALID_PTR(line, ptr) \
|
||||
NW4R_DB_ASSERTMSG(line, POINTER_VALID_TEST(ptr), "NW4HBM:Pointer Error\n" #ptr "(=%p) is not valid pointer.", ptr)
|
||||
|
||||
#define NW4HBM_ASSERT_ALIGN2(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, NW4R_IS_ALIGNED_(exp, 2), \
|
||||
"NW4HBM:Alignment Error(0x%x)\n" #exp " must be aligned to 2 bytes boundary.", \
|
||||
exp)
|
||||
|
||||
#define NW4HBM_ASSERT_ALIGN32(line, exp) \
|
||||
NW4R_DB_ASSERTMSG(line, NW4R_IS_ALIGNED_(exp, 32), \
|
||||
"NW4HBM:Alignment Error(0x%x)\n" #exp " must be aligned to 32 bytes boundary.", \
|
||||
exp)
|
||||
|
||||
#define NW4HBM_ASSERT_ALIGNED(line, exp, align) \
|
||||
NW4R_DB_ASSERTMSG(line, NW4R_IS_ALIGNED_(exp, align), \
|
||||
"NW4HBM:Alignment Error(0x%x)\n" #exp " must be aligned to " #align " bytes boundary.", \
|
||||
exp)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef NW4R_DB_CONSOLE_H
|
||||
#define NW4R_DB_CONSOLE_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "../ut/CharWriter.h"
|
||||
#include "../ut/TextWriterBase.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
namespace detail {
|
||||
struct ConsoleHead {
|
||||
/* 0x00 */ u8* textBuf;
|
||||
/* 0x04 */ u16 width;
|
||||
/* 0x06 */ u16 height;
|
||||
/* 0x08 */ u16 priority;
|
||||
/* 0x0A */ u16 attr;
|
||||
/* 0x0C */ u16 printTop;
|
||||
/* 0x0E */ u16 printXPos;
|
||||
/* 0x10 */ u16 printTopUsed;
|
||||
/* 0x12 */ u16 ringTop;
|
||||
/* 0x14 */ s32 ringTopLineCnt;
|
||||
/* 0x18 */ s32 viewTopLine;
|
||||
/* 0x1C */ s16 viewPosX;
|
||||
/* 0x1E */ s16 viewPosY;
|
||||
/* 0x20 */ u16 viewLines;
|
||||
/* 0x22 */ bool isVisible;
|
||||
/* 0x23 */ u8 padding_[1];
|
||||
/* 0x24 */ ut::TextWriterBase<char>* writer;
|
||||
/* 0x28 */ ConsoleHead* next;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
enum ConsoleOutputType {
|
||||
CONSOLE_OUTPUT_NONE,
|
||||
CONSOLE_OUTPUT_TERMINAL,
|
||||
CONSOLE_OUTPUT_DISPLAY,
|
||||
CONSOLE_OUTPUT_ALL,
|
||||
};
|
||||
|
||||
typedef detail::ConsoleHead* ConsoleHandle;
|
||||
|
||||
typedef void (*VisitStringCallback)(detail::ConsoleHead* console, u8* r4, long r5, u32 r6);
|
||||
|
||||
detail::ConsoleHead* Console_Create(void* buffer, u16 width, u16 height, u16 viewHeight,
|
||||
u16 priority, u16 attr);
|
||||
void Console_Destroy(detail::ConsoleHead* console);
|
||||
void Console_Clear(detail::ConsoleHead* console);
|
||||
void Console_Draw(detail::ConsoleHead* console, ut::TextWriterBase<char>& writer);
|
||||
void Console_DrawDirect(detail::ConsoleHead* console);
|
||||
void Console_DrawAll();
|
||||
void Console_DrawDirectAll();
|
||||
void Console_VFPrintf(ConsoleOutputType type, detail::ConsoleHead* console,
|
||||
const char* format, std::va_list vlist);
|
||||
void Console_FPrintf(ConsoleOutputType type, detail::ConsoleHead* console,
|
||||
const char* format);
|
||||
void Console_Printf(detail::ConsoleHead* console, const char* format, ...);
|
||||
void Console_PrintfD(detail::ConsoleHead* console, const char* format, ...);
|
||||
void Console_PrintfT(detail::ConsoleHead* console, const char* format, ...);
|
||||
u16 Console_ChangePriority(detail::ConsoleHead* console, u16 r4);
|
||||
void Console_VisitString(detail::ConsoleHead* console, VisitStringCallback visitor);
|
||||
long Console_GetTotalLines(detail::ConsoleHead* console);
|
||||
|
||||
static long Console_SetViewBaseLine(detail::ConsoleHead* console, long line);
|
||||
static u16 Console_GetViewHeight(detail::ConsoleHead* console);
|
||||
|
||||
static void Console_VPrintf(detail::ConsoleHead* console, const char* format, std::va_list vlist);
|
||||
|
||||
static long Console_ShowLatestLine(detail::ConsoleHead* console) {
|
||||
long baseLine = Console_GetTotalLines(console) - Console_GetViewHeight(console);
|
||||
|
||||
if (baseLine < 0)
|
||||
baseLine = 0;
|
||||
|
||||
Console_SetViewBaseLine(console, baseLine);
|
||||
|
||||
return baseLine;
|
||||
}
|
||||
|
||||
static u16 Console_GetViewHeight(detail::ConsoleHead* console) {
|
||||
NW4R_ASSERT_CHECK_NULL(434, console);
|
||||
return console->viewLines;
|
||||
}
|
||||
|
||||
static bool Console_SetVisible(detail::ConsoleHead* console, bool isVisible) {
|
||||
NW4R_ASSERT_CHECK_NULL(497, console);
|
||||
|
||||
bool before = console->isVisible;
|
||||
console->isVisible = isVisible;
|
||||
return before;
|
||||
}
|
||||
|
||||
static long Console_SetViewBaseLine(detail::ConsoleHead* console, long line) {
|
||||
NW4R_ASSERT_CHECK_NULL(557, console);
|
||||
long before = console->viewTopLine;
|
||||
console->viewTopLine = line;
|
||||
return before;
|
||||
}
|
||||
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "DbgPrintBase.h"
|
||||
|
||||
#include "../ut/Color.h"
|
||||
#include "../ut/CharWriter.h"
|
||||
|
||||
// Unused file. Only here to force the function CharWriter::SetTextColor(ut::Color&)
|
||||
// into the right place.
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
// Dummy function
|
||||
void dummy(ut::CharWriter* pCharWriter) {
|
||||
ut::Color color;
|
||||
pCharWriter->SetTextColor(color);
|
||||
}
|
||||
} // namespace db
|
||||
} // namespace nw4r
|
||||
@@ -0,0 +1,191 @@
|
||||
#include "assert.h"
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/base/PPCArch.h>
|
||||
#include <revolution/vi.h>
|
||||
#include "console.h"
|
||||
#include "mapFile.h"
|
||||
#include "directPrint.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
using namespace detail;
|
||||
|
||||
static OSAlarm sWarningAlarm;
|
||||
static u32 sWarningTime;
|
||||
static ConsoleHead* sAssertionConsole;
|
||||
static bool sDispWarningAuto;
|
||||
|
||||
static void Assertion_Printf_(const char* fmt, ...) {
|
||||
va_list vlist;
|
||||
va_start(vlist, fmt);
|
||||
|
||||
if (sAssertionConsole) {
|
||||
Console_VFPrintf(CONSOLE_OUTPUT_ALL, sAssertionConsole, fmt, vlist);
|
||||
} else {
|
||||
OSVReport(fmt, vlist);
|
||||
}
|
||||
|
||||
va_end(vlist);
|
||||
}
|
||||
|
||||
static bool ShowMapInfoSubroutine_(u32 address, u8 preCRFlag) {
|
||||
u8 strBuf[260];
|
||||
|
||||
if (!MapFile_Exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address < 0x80000000 || address > 0x82FFFFFF) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MapFile_QuerySymbol(address, strBuf, sizeof(strBuf))) {
|
||||
Assertion_Printf_("%s\n", strBuf);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowStack_(u32 sp) NO_INLINE {
|
||||
Assertion_Printf_("-------------------------------- TRACE\n");
|
||||
Assertion_Printf_("Address: BackChain LR save\n");
|
||||
|
||||
u32* p = (u32*)sp;
|
||||
|
||||
for (u32 i = 0; i < 16; i++, p = (u32*)*p) {
|
||||
if (p == NULL || p == (u32*)0xFFFFFFFF || !((u32)p & 0x80000000))
|
||||
break;
|
||||
|
||||
Assertion_Printf_("%08X: %08X %08X ", p, p[0], p[1]);
|
||||
|
||||
if (!ShowMapInfoSubroutine_(p[1], false)) {
|
||||
Assertion_Printf_("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DECL_WEAK void VPanic(const char* file, int line, const char* fmt, std::va_list vlist) {
|
||||
register u32 stackPointer;
|
||||
|
||||
asm {
|
||||
lwz stackPointer, 0(r1)
|
||||
}
|
||||
|
||||
OSDisableInterrupts();
|
||||
VISetPreRetraceCallback(NULL);
|
||||
VISetPostRetraceCallback(NULL);
|
||||
|
||||
if (sAssertionConsole) {
|
||||
detail::DirectPrint_SetupFB(NULL);
|
||||
}
|
||||
|
||||
ShowStack_(stackPointer);
|
||||
|
||||
if (sAssertionConsole != NULL) {
|
||||
Console_Printf(sAssertionConsole, "%s:%d Panic:", file, line);
|
||||
Console_VFPrintf(CONSOLE_OUTPUT_ALL, sAssertionConsole, fmt, vlist);
|
||||
Console_Printf(sAssertionConsole, "\n");
|
||||
|
||||
Console_ShowLatestLine(sAssertionConsole);
|
||||
Console_SetVisible(sAssertionConsole, true);
|
||||
Console_DrawDirect(sAssertionConsole);
|
||||
} else {
|
||||
OSReport("%s:%d Panic:", file, line);
|
||||
OSVReport(fmt, vlist);
|
||||
OSReport("\n");
|
||||
}
|
||||
|
||||
PPCHalt();
|
||||
}
|
||||
|
||||
DECL_WEAK void detail::Panic(const char* file, int line, const char* fmt, ...) {
|
||||
va_list vlist;
|
||||
va_start(vlist, fmt);
|
||||
VPanic(file, line, fmt, vlist);
|
||||
}
|
||||
|
||||
static OSAlarm& GetWarningAlarm_();
|
||||
static void WarningAlarmFunc_(OSAlarm* alarm, OSContext* context);
|
||||
|
||||
DECL_WEAK void VWarning(const char* file, int line, const char* fmt, std::va_list vlist) {
|
||||
if (sAssertionConsole != NULL) {
|
||||
Console_Printf(sAssertionConsole, "%s:%d Warning:", file, line);
|
||||
Console_VFPrintf(CONSOLE_OUTPUT_ALL, sAssertionConsole, fmt, vlist);
|
||||
Console_Printf(sAssertionConsole, "\n");
|
||||
Console_ShowLatestLine(sAssertionConsole);
|
||||
Console_SetVisible(sAssertionConsole, true);
|
||||
} else {
|
||||
OSReport("%s:%d Warning:", file, line);
|
||||
OSVReport(fmt, vlist);
|
||||
OSReport("\n");
|
||||
}
|
||||
}
|
||||
|
||||
DECL_WEAK void detail::Warning(const char* file, int line, const char* fmt, ...) {
|
||||
OSAlarm& alarm = GetWarningAlarm_();
|
||||
|
||||
va_list vlist;
|
||||
va_start(vlist, fmt);
|
||||
|
||||
VWarning(file, line, fmt, vlist);
|
||||
|
||||
va_end(vlist);
|
||||
|
||||
if (sWarningTime > 0) {
|
||||
OSCancelAlarm(&sWarningAlarm);
|
||||
OSSetAlarm(&sWarningAlarm, sWarningTime, WarningAlarmFunc_);
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
void Log(const char* fmt, ...) {
|
||||
va_list vlist;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
ConsoleHead* Assertion_SetConsole(ConsoleHead* console) {
|
||||
ConsoleHead* before = sAssertionConsole;
|
||||
sAssertionConsole = console;
|
||||
return before;
|
||||
}
|
||||
|
||||
ConsoleHead* Assertion_GetConsole() {
|
||||
return sAssertionConsole;
|
||||
}
|
||||
|
||||
void Assertion_ShowConsole(u32 time) {
|
||||
if (sAssertionConsole != NULL) {
|
||||
OSAlarm& alarm = GetWarningAlarm_();
|
||||
OSCancelAlarm(&alarm);
|
||||
Console_SetVisible(sAssertionConsole, true);
|
||||
if (time != 0) {
|
||||
OSSetAlarm(&alarm, time, WarningAlarmFunc_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Assertion_HideConsole() {
|
||||
// OSAlarm& alarm;
|
||||
}
|
||||
|
||||
void Assertion_SetWarningTime(u32 time) {}
|
||||
|
||||
static OSAlarm& GetWarningAlarm_() {
|
||||
static bool sInitializedAlarm;
|
||||
|
||||
if (!sInitializedAlarm) {
|
||||
OSCreateAlarm(&sWarningAlarm);
|
||||
sInitializedAlarm = true;
|
||||
}
|
||||
|
||||
return sWarningAlarm;
|
||||
}
|
||||
|
||||
static void WarningAlarmFunc_(OSAlarm* alarm, OSContext* context) {
|
||||
Console_SetVisible(sAssertionConsole, false);
|
||||
}
|
||||
} // namespace db
|
||||
} // namespace nw4r
|
||||
@@ -0,0 +1,315 @@
|
||||
#include <revolution/os.h>
|
||||
#include "assert.h"
|
||||
#include "console.h"
|
||||
#include "directPrint.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
|
||||
static OSMutex sMutex;
|
||||
static u8 sStrBuf[1024];
|
||||
|
||||
static inline u8* GetTextPtr_(ConsoleHandle console, u16 line, u16 xPos) {
|
||||
return console->textBuf + xPos + (console->width + 1) * line;
|
||||
}
|
||||
|
||||
static inline u32 CodeWidth_(u8 const* p) {
|
||||
return *p >= 0x81 ? sizeof(wchar_t) : sizeof(char);
|
||||
}
|
||||
|
||||
static inline u32 GetTabSize_(ConsoleHandle console) {
|
||||
s32 tab = (console->attr & 0xC) >> 2;
|
||||
return static_cast<u32>(2 << tab);
|
||||
}
|
||||
|
||||
static inline u8 const* SearchEndOfLine_(u8 const* str) {
|
||||
while (*str != '\n' && *str != '\0') {
|
||||
str++;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline u16 GetRingUsedLines_(ConsoleHandle console) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(112, console);
|
||||
{
|
||||
s32 lines = console->printTop - console->ringTop;
|
||||
|
||||
if (lines < 0) {
|
||||
lines += console->height;
|
||||
}
|
||||
|
||||
return static_cast<u16>(lines);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u16 GetActiveLines_(ConsoleHandle console) {
|
||||
u16 lines = GetRingUsedLines_(console);
|
||||
|
||||
if (console->printTopUsed) {
|
||||
lines++;
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
static void TerminateLine_(ConsoleHandle console) {
|
||||
*GetTextPtr_(console, console->printTop, console->printXPos) = '\0';
|
||||
}
|
||||
|
||||
static u8* NextLine_(ConsoleHandle console) {
|
||||
*GetTextPtr_(console, console->printTop, console->printXPos) = '\0';
|
||||
console->printXPos = 0;
|
||||
console->printTop++;
|
||||
console->printTopUsed = 0;
|
||||
|
||||
if (console->printTop == console->height && !(console->attr & 2)) {
|
||||
console->printTop = 0;
|
||||
}
|
||||
|
||||
if (console->printTop == console->ringTop) {
|
||||
console->ringTopLineCnt++;
|
||||
|
||||
if (++console->ringTop == console->height) {
|
||||
console->ringTop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return GetTextPtr_(console, console->printTop, 0);
|
||||
}
|
||||
|
||||
static u8* PutTab_(ConsoleHandle console, u8* dstPtr) {
|
||||
u32 tabWidth = GetTabSize_(console);
|
||||
|
||||
do {
|
||||
*dstPtr++ = ' ';
|
||||
console->printXPos++;
|
||||
|
||||
if (console->printXPos >= console->width) {
|
||||
break;
|
||||
}
|
||||
} while (console->printXPos & (tabWidth - 1));
|
||||
|
||||
return dstPtr;
|
||||
}
|
||||
|
||||
static u32 PutChar_(ConsoleHandle console, u8 const* str, u8* dstPtr) {
|
||||
u32 codeWidth = CodeWidth_(str);
|
||||
u32 cnt;
|
||||
|
||||
if (console->printXPos + codeWidth <= console->width == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
console->printXPos += codeWidth;
|
||||
|
||||
for (cnt = codeWidth; cnt; cnt--) {
|
||||
*dstPtr++ = *str++;
|
||||
}
|
||||
|
||||
return codeWidth;
|
||||
}
|
||||
|
||||
static void UnlockMutex_(OSMutex* mutex) {
|
||||
OSUnlockMutex(mutex);
|
||||
}
|
||||
|
||||
static bool TryLockMutex_(OSMutex* mutex) {
|
||||
OSLockMutex(mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void DoDrawString_(ConsoleHandle console, u32 printLine, u8 const* str,
|
||||
ut::TextWriterBase<char>* writer) {
|
||||
if (writer) {
|
||||
writer->Printf("%s\n", str);
|
||||
} else {
|
||||
s32 height = (s32)((u32)console->viewPosY + printLine * 10);
|
||||
|
||||
DirectPrint_DrawString(console->viewPosX, height, false, "%s\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
static void DoDrawConsole_(ConsoleHandle console, ut::TextWriterBase<char>* writer) {
|
||||
s32 viewOffset;
|
||||
u16 line;
|
||||
u16 printLines;
|
||||
|
||||
viewOffset = console->viewTopLine - console->ringTopLineCnt;
|
||||
printLines = 0;
|
||||
|
||||
if (viewOffset < 0) {
|
||||
viewOffset = 0;
|
||||
} else if (viewOffset > GetActiveLines_(console)) {
|
||||
return;
|
||||
}
|
||||
|
||||
line = static_cast<u16>(console->ringTop + viewOffset);
|
||||
|
||||
if (line >= console->height) {
|
||||
line -= console->height;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (line == console->printTop && console->printTopUsed == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
DoDrawString_(console, printLines, GetTextPtr_(console, line, 0), writer);
|
||||
|
||||
printLines++;
|
||||
|
||||
if (line == console->printTop) {
|
||||
break;
|
||||
}
|
||||
|
||||
line++;
|
||||
|
||||
if (line == console->height) {
|
||||
if (console->attr & 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
line = 0;
|
||||
}
|
||||
|
||||
if (printLines >= console->viewLines) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Console_DrawDirect(ConsoleHandle console) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(621, console);
|
||||
|
||||
if (DirectPrint_IsActive() && console->isVisible) {
|
||||
TryLockMutex_(&sMutex);
|
||||
int width = console->width * 6 + 12, height = console->viewLines * 10 + 4;
|
||||
|
||||
DirectPrint_EraseXfb(console->viewPosX - 6, console->viewPosY - 3, width, height);
|
||||
DoDrawConsole_(console, NULL);
|
||||
DirectPrint_StoreCache();
|
||||
UnlockMutex_(&sMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void dummyString(ConsoleHandle pConsole) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, pConsole);
|
||||
OSReport("illegal console handle");
|
||||
u8* buffer;
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, buffer);
|
||||
OSReport("NW4HBM:Alignment Error(0x%x)\nbuffer must be aligned to 4 bytes boundary.");
|
||||
}
|
||||
|
||||
static void PrintToBuffer_(ConsoleHandle console, u8 const* str) {
|
||||
u8* storePtr;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(747, console);
|
||||
NW4HBM_ASSERT_CHECK_NULL(748, str);
|
||||
|
||||
storePtr = GetTextPtr_(console, console->printTop, console->printXPos);
|
||||
|
||||
while (*str) {
|
||||
if (console->attr & 2 && console->printTop == console->height) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (*str) // ? just use continue? am i missing something?
|
||||
{
|
||||
bool newLineFlag = false;
|
||||
|
||||
if (*str == '\n') {
|
||||
str++;
|
||||
storePtr = NextLine_(console);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*str == '\t') {
|
||||
str++;
|
||||
storePtr = PutTab_(console, storePtr);
|
||||
console->printTopUsed = 1;
|
||||
} else {
|
||||
u32 bytes = PutChar_(console, str, storePtr);
|
||||
|
||||
if (bytes) {
|
||||
console->printTopUsed = 1;
|
||||
str += bytes;
|
||||
storePtr += bytes;
|
||||
} else {
|
||||
newLineFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (console->printXPos >= console->width) {
|
||||
newLineFlag = true;
|
||||
}
|
||||
|
||||
if (newLineFlag) {
|
||||
if (console->attr & 1) {
|
||||
str = SearchEndOfLine_(str);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*str == '\n') {
|
||||
str++;
|
||||
}
|
||||
|
||||
storePtr = NextLine_(console);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Console_PrintString_(ConsoleOutputType type, ConsoleHandle console,
|
||||
u8 const* str) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(843, console);
|
||||
|
||||
if (type & CONSOLE_OUTPUT_DISPLAY) {
|
||||
OSReport("%s", str);
|
||||
}
|
||||
|
||||
if (type & CONSOLE_OUTPUT_TERMINAL) {
|
||||
PrintToBuffer_(console, str);
|
||||
}
|
||||
}
|
||||
|
||||
void Console_VFPrintf(ConsoleOutputType type, ConsoleHandle console, char const* format,
|
||||
std::va_list vlist) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(872, console);
|
||||
|
||||
if (TryLockMutex_(&sMutex)) {
|
||||
std::vsnprintf(reinterpret_cast<char*>(sStrBuf), sizeof(sStrBuf), format, vlist);
|
||||
|
||||
Console_PrintString_(type, console, sStrBuf);
|
||||
|
||||
UnlockMutex_(&sMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void Console_Printf(ConsoleHandle console, char const* format, ...) {
|
||||
std::va_list vlist;
|
||||
va_start(vlist, format);
|
||||
Console_VFPrintf(CONSOLE_OUTPUT_ALL, console, format, vlist);
|
||||
va_end(vlist);
|
||||
}
|
||||
|
||||
s32 Console_GetTotalLines(ConsoleHandle console) {
|
||||
s32 count;
|
||||
|
||||
// this is not part of this function but it's required to generate the dtor
|
||||
// (`nw4hbm::ut::Color::~Color()`) it was probably part of a function that got stripped
|
||||
// by the linker
|
||||
::nw4hbm::ut::Color unused;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(1050, console);
|
||||
|
||||
TryLockMutex_(&sMutex);
|
||||
count = GetActiveLines_(console) + console->ringTopLineCnt;
|
||||
UnlockMutex_(&sMutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,464 @@
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/vi.h>
|
||||
#include "assert.h"
|
||||
#include "directPrint.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define ROUND_UP(x, align) (((x) + (align)-1) & (-(align)))
|
||||
#define ROUND_DOWN(x, align) ((x) & (~((align) - 1)))
|
||||
|
||||
typedef struct FrameBufferInfo {
|
||||
/* 0x00 */ u8* frameMemory;
|
||||
/* 0x04 */ u32 frameSize;
|
||||
/* 0x08 */ u16 frameWidth;
|
||||
/* 0x0A */ u16 frameHeight;
|
||||
/* 0x0C */ u16 frameRow;
|
||||
/* 0x0E */ u16 reserved;
|
||||
} FrameBufferInfo;
|
||||
|
||||
typedef struct YUVColorInfo {
|
||||
/* 0x00 */ GXColor colorRGBA;
|
||||
/* 0x04 */ u16 colorY256;
|
||||
/* 0x06 */ u16 colorU;
|
||||
/* 0x08 */ u16 colorU2;
|
||||
/* 0x0A */ u16 colorU4;
|
||||
/* 0x0C */ u16 colorV;
|
||||
/* 0x0E */ u16 colorV2;
|
||||
/* 0x10 */ u16 colorV4;
|
||||
/* 0x12 */ u16 reserved;
|
||||
} YUVColorInfo;
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
|
||||
static void DrawStringToXfb_(int posh, int posv, char const* str, bool turnOver,
|
||||
bool backErase);
|
||||
static char const* DrawStringLineToXfb_(int posh, int posv, char const* str, int width);
|
||||
static void DrawCharToXfb_(int posh, int posv, int code);
|
||||
|
||||
namespace detail {
|
||||
static void WaitVIRetrace_();
|
||||
static void* CreateFB_(GXRenderModeObj const* rmode);
|
||||
} // namespace detail
|
||||
|
||||
static inline int StrLineWidth_(char const* str) {
|
||||
int len = 0;
|
||||
char c;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(306, str);
|
||||
|
||||
while (true) {
|
||||
c = *str++;
|
||||
|
||||
if (c == '\0' || c == '\n') {
|
||||
return len;
|
||||
}
|
||||
|
||||
if (c == '\t') {
|
||||
len = (len + 4) & -4;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const u8 sAsciiTable[128] = {
|
||||
0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0xFD, 0xFE, 0x7A, 0x7A,
|
||||
0x7A, 0x7A, 0x7A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x64, 0x65, 0x66, 0x2B, 0x67,
|
||||
0x68, 0x25, 0x26, 0x69, 0x2A, 0x6A, 0x27, 0x2C, 0x6B, 0x00, 0x01, 0x02, 0x03,
|
||||
0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x24, 0x6C, 0x6D, 0x6E, 0x6F, 0x28, 0x70,
|
||||
0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23,
|
||||
0x71, 0x72, 0x73, 0x74, 0x75, 0xFF, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83,
|
||||
0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90,
|
||||
0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x76, 0x77, 0x78, 0x79, 0x7A,
|
||||
};
|
||||
|
||||
static const u32 sFontData[64] = {
|
||||
0x70871C30, 0x8988A250, 0x88808290, 0x88830C90, 0x888402F8, 0x88882210, 0x71CF9C10,
|
||||
0xF9CF9C70, 0x8208A288, 0xF200A288, 0x0BC11C78, 0x0A222208, 0x8A222208, 0x71C21C70,
|
||||
0x23C738F8, 0x5228A480, 0x8A282280, 0x8BC822F0, 0xFA282280, 0x8A28A480, 0x8BC738F8,
|
||||
0xF9C89C08, 0x82288808, 0x82088808, 0xF2EF8808, 0x82288888, 0x82288888, 0x81C89C70,
|
||||
0x8A08A270, 0x920DA288, 0xA20AB288, 0xC20AAA88, 0xA208A688, 0x9208A288, 0x8BE8A270,
|
||||
0xF1CF1CF8, 0x8A28A220, 0x8A28A020, 0xF22F1C20, 0x82AA0220, 0x82492220, 0x81A89C20,
|
||||
0x8A28A288, 0x8A28A288, 0x8A289488, 0x8A2A8850, 0x894A9420, 0x894AA220, 0x70852220,
|
||||
0xF8011000, 0x08020800, 0x10840400, 0x20040470, 0x40840400, 0x80020800, 0xF8011000,
|
||||
0x70800000, 0x88822200, 0x08820400, 0x108F8800, 0x20821000, 0x00022200, 0x20800020,
|
||||
0x00000000,
|
||||
};
|
||||
|
||||
static const u32 sFontData2[77] = {
|
||||
0x51421820, 0x53E7A420, 0x014A2C40, 0x01471000, 0x0142AA00, 0x03EAA400, 0x01471A78,
|
||||
0x00000000, 0x50008010, 0x20010820, 0xF8020040, 0x20420820, 0x50441010, 0x00880000,
|
||||
0x00070E00, 0x01088840, 0x78898820, 0x004A8810, 0x788A8810, 0x01098808, 0x00040E04,
|
||||
0x70800620, 0x11400820, 0x12200820, 0x10001020, 0x10000820, 0x100F8820, 0x70000620,
|
||||
0x60070000, 0x110F82A0, 0x12AA8AE0, 0x084F92A0, 0x100FBE1C, 0x10089008, 0x60070808,
|
||||
0x00000000, 0x02000200, 0x7A078270, 0x8BC81E88, 0x8A2822F8, 0x9A282280, 0x6BC79E78,
|
||||
0x30000000, 0x48080810, 0x41E80000, 0x422F1830, 0xFBE88810, 0x40288890, 0x43C89C60,
|
||||
0x81000000, 0x81000000, 0x990F3C70, 0xA10AA288, 0xE10AA288, 0xA10AA288, 0x98CAA270,
|
||||
0x00000000, 0x00000020, 0xF1EF1E20, 0x8A28A0F8, 0x8A281C20, 0xF1E80220, 0x80283C38,
|
||||
0x00000000, 0x00000000, 0x8A28B688, 0x8A2A8888, 0x8A2A8878, 0x894A8808, 0x788536F0,
|
||||
0x00000000, 0x00000000, 0xF8000000, 0x10000000, 0x20000000, 0x40000000, 0xF8000000,
|
||||
};
|
||||
|
||||
static FrameBufferInfo sFrameBufferInfo;
|
||||
static YUVColorInfo sFrameBufferColor;
|
||||
static int sInitialized = false;
|
||||
|
||||
static inline int GetDotWidth_() {
|
||||
return sFrameBufferInfo.frameWidth < 400 ? 1 : 2;
|
||||
}
|
||||
static inline int GetDotHeight_() {
|
||||
return sFrameBufferInfo.frameHeight < 300 ? 1 : 2;
|
||||
}
|
||||
|
||||
void DirectPrint_Init() {
|
||||
if (!sInitialized) {
|
||||
DirectPrint_ChangeXfb(NULL, 640, 480);
|
||||
DirectPrint_SetColor(0xff, 0xff, 0xff);
|
||||
|
||||
sInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectPrint_IsActive() {
|
||||
return sInitialized && sFrameBufferInfo.frameMemory;
|
||||
}
|
||||
|
||||
void DirectPrint_EraseXfb(int posh, int posv, int sizeh, int sizev) {
|
||||
int posEndH, posEndV;
|
||||
|
||||
if (sFrameBufferInfo.frameMemory == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetDotWidth_() == 2) {
|
||||
posh *= 2;
|
||||
sizeh *= 2;
|
||||
}
|
||||
|
||||
posEndH = posh + sizeh;
|
||||
posh = posh >= 0 ? posh : 0;
|
||||
|
||||
posEndH = posEndH <= sFrameBufferInfo.frameWidth ? posEndH : sFrameBufferInfo.frameWidth;
|
||||
sizeh = posEndH - posh;
|
||||
|
||||
if (GetDotHeight_() == 2) {
|
||||
posv *= 2;
|
||||
sizev *= 2;
|
||||
}
|
||||
|
||||
posEndV = posv + sizev;
|
||||
posv = posv >= 0 ? posv : 0;
|
||||
|
||||
posEndV = posEndV <= sFrameBufferInfo.frameHeight ? posEndV : sFrameBufferInfo.frameHeight;
|
||||
sizev = posEndV - posv;
|
||||
|
||||
u16* pixel = reinterpret_cast<u16*>(sFrameBufferInfo.frameMemory) +
|
||||
sFrameBufferInfo.frameRow * posv + posh;
|
||||
|
||||
for (int cntv = 0; cntv < sizev; cntv++) {
|
||||
for (int cnth = 0; cnth < sizeh; cnth++) {
|
||||
*pixel++ = 0x1080; // some sort of white or black?
|
||||
}
|
||||
|
||||
pixel += sFrameBufferInfo.frameRow - sizeh;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectPrint_ChangeXfb(void* framebuf, u16 width, u16 height) {
|
||||
sFrameBufferInfo.frameMemory = static_cast<u8*>(framebuf);
|
||||
sFrameBufferInfo.frameWidth = width;
|
||||
sFrameBufferInfo.frameHeight = height;
|
||||
|
||||
sFrameBufferInfo.frameRow = ROUND_UP(static_cast<u16>(width), 16);
|
||||
sFrameBufferInfo.frameSize =
|
||||
sFrameBufferInfo.frameRow * sFrameBufferInfo.frameHeight * 2;
|
||||
}
|
||||
|
||||
void DirectPrint_ChangeXfb(void* framebuf) {
|
||||
sFrameBufferInfo.frameMemory = static_cast<u8*>(framebuf);
|
||||
}
|
||||
|
||||
void DirectPrint_StoreCache(void) {
|
||||
DCStoreRange(sFrameBufferInfo.frameMemory, sFrameBufferInfo.frameSize);
|
||||
}
|
||||
|
||||
void DirectPrint_DrawString(int posh, int posv, bool turnOver, char const* format, ...) {
|
||||
if (sFrameBufferInfo.frameMemory) {
|
||||
std::va_list vargs;
|
||||
|
||||
va_start(vargs, format);
|
||||
detail::DirectPrint_DrawStringToXfb(posh, posv, format, vargs, turnOver, false);
|
||||
va_end(vargs);
|
||||
}
|
||||
}
|
||||
|
||||
// Intel IPP RGBToYCbCr algorithm, same as OSFatal.c::RGB2YUV
|
||||
void DirectPrint_SetColor(u8 r, u8 g, u8 b) {
|
||||
int y = (int)(0.257f * (int)r + 0.504f * (int)g + 0.098f * (int)b + 16.0f);
|
||||
int u = (int)(-0.148f * (int)r - 0.291f * (int)g + 0.439f * (int)b + 128.0f);
|
||||
int v = (int)(0.439f * (int)r - 0.368f * (int)g - 0.071f * (int)b + 128.0f);
|
||||
|
||||
sFrameBufferColor.colorRGBA.r = r;
|
||||
sFrameBufferColor.colorRGBA.g = g;
|
||||
sFrameBufferColor.colorRGBA.b = b;
|
||||
sFrameBufferColor.colorRGBA.a = 0xff;
|
||||
|
||||
sFrameBufferColor.colorY256 = static_cast<u16>(y << 8);
|
||||
|
||||
sFrameBufferColor.colorU = static_cast<u16>(u);
|
||||
sFrameBufferColor.colorU2 = static_cast<u16>(u / 2);
|
||||
sFrameBufferColor.colorU4 = static_cast<u16>(u / 4);
|
||||
|
||||
sFrameBufferColor.colorV = static_cast<u16>(v);
|
||||
sFrameBufferColor.colorV2 = static_cast<u16>(v / 2);
|
||||
sFrameBufferColor.colorV4 = static_cast<u16>(v / 4);
|
||||
}
|
||||
|
||||
void detail::DirectPrint_DrawStringToXfb(int posh, int posv, char const* format,
|
||||
std::va_list vargs, bool turnOver,
|
||||
bool backErase) {
|
||||
char string[256];
|
||||
|
||||
NW4HBM_ASSERT(647, sFrameBufferInfo.frameMemory != NULL);
|
||||
|
||||
int length = std::vsnprintf(string, sizeof(string), format, vargs);
|
||||
int posLeftStart = posh;
|
||||
|
||||
if (length > 0) {
|
||||
DrawStringToXfb_(posh, posv, string, turnOver, backErase);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawStringToXfb_(int posh, int posv, char const* str, bool turnOver,
|
||||
bool backErase) {
|
||||
int basePosH = posh;
|
||||
int width;
|
||||
int frameWidth = sFrameBufferInfo.frameWidth / GetDotWidth_();
|
||||
|
||||
while (*str != '\0') {
|
||||
int len;
|
||||
|
||||
if (backErase) {
|
||||
len = StrLineWidth_(str);
|
||||
|
||||
DirectPrint_EraseXfb(posh - 6, posv - 3, (len + 2) * 6, 13);
|
||||
}
|
||||
|
||||
width = (frameWidth - posh) / 6;
|
||||
str = DrawStringLineToXfb_(posh, posv, str, width);
|
||||
posv += 10;
|
||||
|
||||
if (*str == '\n') {
|
||||
str++;
|
||||
posh = basePosH;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*str == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
str++;
|
||||
|
||||
if (!turnOver) {
|
||||
str = strchr(str, '\n');
|
||||
|
||||
if (str) {
|
||||
str++;
|
||||
posh = basePosH;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
posh = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char const* DrawStringLineToXfb_(int posh, int posv, char const* str, int width) {
|
||||
char c;
|
||||
int code;
|
||||
int cnt = 0;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(745, str);
|
||||
NW4HBM_ASSERT(746, width > 0);
|
||||
|
||||
for (; (c = *str) != '\0'; str++) {
|
||||
if (c == '\n' || c == '\0') { // another check against null character?
|
||||
return str;
|
||||
}
|
||||
|
||||
code = sAsciiTable[c % sizeof(sAsciiTable)];
|
||||
|
||||
if (code == 0xfd) {
|
||||
int tab_size = 4 - (cnt & 3);
|
||||
|
||||
posh += tab_size * 6;
|
||||
cnt += tab_size;
|
||||
} else {
|
||||
if (code != 0xff) {
|
||||
DrawCharToXfb_(posh, posv, code);
|
||||
}
|
||||
|
||||
posh += 6;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (cnt >= width) {
|
||||
if (str[1] == '\n') {
|
||||
str++;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static void DrawCharToXfb_(int posh, int posv, int code) {
|
||||
static u32 twiceBit[4] = {0, 3, 12, 15};
|
||||
|
||||
int ncode = code >= 100 ? code - 100 : code;
|
||||
int fonth = ncode % 5 * 6;
|
||||
int fontv = ncode / 5 * 7;
|
||||
const u32* fontLine = code < 100 ? &sFontData[fontv] : &sFontData2[fontv];
|
||||
|
||||
int wH = GetDotWidth_();
|
||||
int wV = GetDotHeight_();
|
||||
|
||||
u16* pixel = reinterpret_cast<u16*>(sFrameBufferInfo.frameMemory) +
|
||||
sFrameBufferInfo.frameRow * posv * wV + posh * wH;
|
||||
|
||||
if (posv < 0 || posh < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sFrameBufferInfo.frameWidth <= wH * (posh + 6) ||
|
||||
sFrameBufferInfo.frameHeight <= wV * (posv + 7))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int cntv = 0; cntv < 7; cntv++) {
|
||||
u32 fontBits = *fontLine++ << fonth;
|
||||
|
||||
if (wH == 1) {
|
||||
fontBits = (fontBits & 0xfc000000) >> 1;
|
||||
} else {
|
||||
fontBits =
|
||||
(twiceBit[(fontBits >> 26) & 3] | twiceBit[(fontBits >> 28) & 3] << 4 |
|
||||
twiceBit[(fontBits >> 30) & 3] << 8)
|
||||
<< 19;
|
||||
}
|
||||
|
||||
for (int cnth = 0; cnth < wH * 6;) {
|
||||
u16 pixColor = (fontBits & (1u << 30) ? sFrameBufferColor.colorY256 : 0x00) |
|
||||
((fontBits & (1u << 31) ? sFrameBufferColor.colorU4 : 0x20) +
|
||||
(fontBits & (1u << 30) ? sFrameBufferColor.colorU2 : 0x40) +
|
||||
(fontBits & (1u << 29) ? sFrameBufferColor.colorU4 : 0x20));
|
||||
|
||||
*pixel = pixColor;
|
||||
|
||||
if (wV > 1) {
|
||||
pixel[sFrameBufferInfo.frameRow] = pixColor;
|
||||
}
|
||||
|
||||
pixel++;
|
||||
|
||||
pixColor = (fontBits & (1u << 29) ? sFrameBufferColor.colorY256 : 0x00) |
|
||||
((fontBits & (1u << 30) ? sFrameBufferColor.colorV4 : 0x20) +
|
||||
(fontBits & (1u << 29) ? sFrameBufferColor.colorV2 : 0x40) +
|
||||
(fontBits & (1u << 28) ? sFrameBufferColor.colorV4 : 0x20));
|
||||
|
||||
*pixel = pixColor;
|
||||
|
||||
if (wV > 1) {
|
||||
pixel[sFrameBufferInfo.frameRow] = pixColor;
|
||||
}
|
||||
|
||||
pixel++;
|
||||
|
||||
fontBits <<= 2;
|
||||
cnth += 2;
|
||||
}
|
||||
|
||||
pixel += sFrameBufferInfo.frameRow * wV - 6 * wH;
|
||||
}
|
||||
}
|
||||
|
||||
static void detail::WaitVIRetrace_(void) {
|
||||
int intrStatus = OSEnableInterrupts(); /* int enabled; */
|
||||
u32 preCnt = VIGetRetraceCount();
|
||||
|
||||
while (preCnt == VIGetRetraceCount()) { /* ... */
|
||||
}
|
||||
|
||||
OSRestoreInterrupts(intrStatus);
|
||||
}
|
||||
|
||||
static void* detail::CreateFB_(GXRenderModeObj const* rmode) {
|
||||
u32 arenaHi = (u32)OSGetArenaHi();
|
||||
u32 memSize = (u16)ROUND_UP((u16)rmode->fbWidth, 16) * rmode->xfbHeight * 2;
|
||||
u32 frameBuf = ROUND_DOWN(arenaHi - memSize, 32);
|
||||
|
||||
VIConfigure(rmode);
|
||||
VISetNextFrameBuffer(reinterpret_cast<void*>(frameBuf));
|
||||
|
||||
return reinterpret_cast<void*>(frameBuf);
|
||||
}
|
||||
|
||||
void* detail::DirectPrint_SetupFB(GXRenderModeObj const* rmode) {
|
||||
void* frameMemory;
|
||||
|
||||
DirectPrint_Init();
|
||||
|
||||
frameMemory = VIGetCurrentFrameBuffer();
|
||||
if (!frameMemory) {
|
||||
if (!rmode) {
|
||||
switch (VIGetTvFormat()) {
|
||||
case VI_TVMODE_NTSC_INT:
|
||||
rmode = &GXNtsc480IntDf;
|
||||
break;
|
||||
|
||||
case VI_TVMODE_NTSC_DS:
|
||||
rmode = &GXPal528IntDf;
|
||||
break;
|
||||
|
||||
case VI_TVMODE_PAL_DS:
|
||||
rmode = &GXEurgb60Hz480IntDf;
|
||||
break;
|
||||
|
||||
case VI_TVMODE_NTSC_PROG:
|
||||
rmode = &GXMpal480IntDf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
frameMemory = CreateFB_(rmode);
|
||||
}
|
||||
|
||||
VISetBlack(false);
|
||||
VIFlush();
|
||||
WaitVIRetrace_();
|
||||
|
||||
if (rmode) {
|
||||
DirectPrint_ChangeXfb(frameMemory, rmode->fbWidth, rmode->xfbHeight);
|
||||
} else {
|
||||
DirectPrint_ChangeXfb(frameMemory);
|
||||
}
|
||||
|
||||
return frameMemory;
|
||||
}
|
||||
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,367 @@
|
||||
#include <revolution/dvd.h>
|
||||
#include <revolution/os.h>
|
||||
#include "assert.h"
|
||||
#include "mapFile.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
typedef u8 GetCharFunc(u8 const* buf);
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
static u8 GetCharOnMem_(const u8* buf);
|
||||
static u8 GetCharOnDvd_(u8 const* buf);
|
||||
|
||||
static u8* SearchNextLine_(u8* buf, s32 lines);
|
||||
static u8* SearchNextSection_(u8* buf);
|
||||
static u8* SearchParam_(u8* lineTop, u32 argNum, u8 splitter);
|
||||
|
||||
static u32 XStrToU32_(u8 const* str);
|
||||
static u32 CopySymbol_(u8 const* buf, u8* str, u32 strLenMax, u8 splitter);
|
||||
|
||||
static bool QuerySymbolToMapFile_(u8* buf, OSModuleInfo const* moduleInfo, u32 address,
|
||||
u8* strBuf, u32 strBufSize);
|
||||
static bool QuerySymbolToSingleMapFile_(MapFile* pMapFile, u32 address, u8* strBuf,
|
||||
u32 strBufSize) NO_INLINE;
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
static u8 sMapBuf[0x200];
|
||||
static s32 sMapBufOffset = -1;
|
||||
static DVDFileInfo sFileInfo;
|
||||
static u32 sFileLength;
|
||||
static MapFile* sMapFileList;
|
||||
static GetCharFunc* GetCharPtr_;
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
bool MapFile_Exists(void) {
|
||||
return sMapFileList ? true : false;
|
||||
}
|
||||
|
||||
static u8 GetCharOnMem_(u8 const* buf) {
|
||||
return *buf;
|
||||
}
|
||||
|
||||
static s32 GetSize(s32 offset, u32 length) {
|
||||
if (offset + ARRAY_SIZE(sMapBuf) >= length) {
|
||||
return OSRoundUp32B(length - offset);
|
||||
}
|
||||
|
||||
return ARRAY_SIZE(sMapBuf);
|
||||
}
|
||||
|
||||
static u8 GetCharOnDvd_(u8 const* buf) {
|
||||
s32 address = (u32)buf & ~0x80000000;
|
||||
s32 offset = address - sMapBufOffset;
|
||||
|
||||
if (address >= sFileLength) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sMapBufOffset < 0 || offset < 0 || ARRAY_SIZE(sMapBuf) <= offset) {
|
||||
s32 len;
|
||||
s32 size;
|
||||
|
||||
sMapBufOffset = OSRoundDown32B(address);
|
||||
offset = address - sMapBufOffset;
|
||||
size = GetSize(sMapBufOffset, sFileLength);
|
||||
|
||||
BOOL enabled = OSEnableInterrupts();
|
||||
|
||||
len = DVDReadAsyncPrio(&sFileInfo, sMapBuf, size, sMapBufOffset, NULL, 2);
|
||||
|
||||
while (DVDGetCommandBlockStatus(&sFileInfo.cb)) {}
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sMapBuf[offset];
|
||||
}
|
||||
|
||||
void dummyString() {
|
||||
u8* buffer;
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, buffer);
|
||||
|
||||
u8* mapDataBuf;
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, mapDataBuf);
|
||||
|
||||
MapFile* pMapFile;
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, pMapFile);
|
||||
|
||||
NW4HBM_ASSERT(0, sMapFileList->moduleInfo != NULL);
|
||||
|
||||
u8* filePath;
|
||||
NW4HBM_ASSERT_CHECK_NULL(0, filePath);
|
||||
|
||||
NW4HBM_ASSERT(0, pMapFile->fileEntry >= 0);
|
||||
}
|
||||
|
||||
static u8* SearchNextLine_(u8* buf, s32 lines) {
|
||||
u8 c;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(361, GetCharPtr_);
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (; (c = (*GetCharPtr_)(buf)) != '\0'; buf++) {
|
||||
if (c == '\n') {
|
||||
if (--lines <= 0) {
|
||||
return buf + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static u8* SearchNextSection_(u8* buf) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(397, GetCharPtr_);
|
||||
|
||||
do {
|
||||
buf = SearchNextLine_(buf, 1);
|
||||
|
||||
if (!buf) {
|
||||
return NULL;
|
||||
}
|
||||
} while ((*GetCharPtr_)(buf) != '.');
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static u8* SearchParam_(u8* lineTop, u32 argNum, u8 splitter) {
|
||||
int inArg = 0;
|
||||
u8* buf = lineTop;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(432, GetCharPtr_);
|
||||
|
||||
if (buf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
u8 c = (*GetCharPtr_)(buf);
|
||||
|
||||
if (c == '\0' || c == '\n') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inArg) {
|
||||
if (c == splitter) {
|
||||
inArg = 0;
|
||||
}
|
||||
} else if (c != splitter) {
|
||||
if (!argNum--) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
inArg = 1;
|
||||
}
|
||||
|
||||
buf++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 XStrToU32_(u8 const* str) {
|
||||
u32 val = 0;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(486, str);
|
||||
NW4HBM_ASSERT_CHECK_NULL(487, GetCharPtr_);
|
||||
|
||||
while (true) {
|
||||
u32 num;
|
||||
u8 c;
|
||||
|
||||
c = (*GetCharPtr_)(str);
|
||||
|
||||
if ('0' <= c && c <= '9') {
|
||||
num = static_cast<u32>(c - '0');
|
||||
} else if ('a' <= c && c <= 'z') {
|
||||
num = static_cast<u32>(c - ('a' - 10)); // ?
|
||||
} else if ('A' <= c && c <= 'Z') {
|
||||
num = static_cast<u32>(c - ('A' - 10)); // What's the - 10 for
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
|
||||
if (val >= 0x10000000) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = num + (val << 4);
|
||||
str++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 CopySymbol_(const u8* buf, u8* str, u32 strLenMax, u8 splitter) {
|
||||
u32 cnt = 0;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(544, buf);
|
||||
NW4HBM_ASSERT_CHECK_NULL(545, str);
|
||||
NW4HBM_ASSERT_CHECK_NULL(546, GetCharPtr_);
|
||||
|
||||
while (true) {
|
||||
u8 c = (*GetCharPtr_)(buf++);
|
||||
|
||||
if (c == splitter || c == '\0' || c == '\n') {
|
||||
*str = '\0';
|
||||
return cnt;
|
||||
}
|
||||
|
||||
*str = c;
|
||||
str++;
|
||||
cnt++;
|
||||
|
||||
if (cnt >= strLenMax - 1) {
|
||||
*str = '\0';
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool QuerySymbolToMapFile_(u8* buf, OSModuleInfo const* moduleInfo, u32 address,
|
||||
u8* strBuf, u32 strBufSize) {
|
||||
OSSectionInfo* sectionInfo = NULL;
|
||||
u32 sectionCnt;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(602, strBuf);
|
||||
NW4HBM_ASSERT(603, strBufSize > 0);
|
||||
|
||||
if (moduleInfo) {
|
||||
sectionInfo = reinterpret_cast<OSSectionInfo*>(moduleInfo->sectionInfoOffset);
|
||||
sectionCnt = moduleInfo->numSections;
|
||||
}
|
||||
|
||||
do {
|
||||
u32 offset = 0;
|
||||
|
||||
buf = SearchNextSection_(buf);
|
||||
buf = SearchNextLine_(buf, 3);
|
||||
|
||||
if (sectionInfo) {
|
||||
offset = sectionInfo->offset;
|
||||
|
||||
if (address < offset) {
|
||||
goto get_next_section_info;
|
||||
}
|
||||
|
||||
if (address >= offset + sectionInfo->size) {
|
||||
goto get_next_section_info;
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
u8* param;
|
||||
u32 startAddr;
|
||||
u32 size;
|
||||
|
||||
buf = SearchNextLine_(buf, 1);
|
||||
if (!buf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
param = SearchParam_(buf, 1, ' ');
|
||||
if (!param) {
|
||||
break;
|
||||
}
|
||||
|
||||
size = XStrToU32_(param);
|
||||
param = SearchParam_(buf, 2, ' ');
|
||||
if (!param) {
|
||||
break;
|
||||
}
|
||||
|
||||
startAddr = XStrToU32_(param);
|
||||
if (!startAddr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
startAddr = startAddr + offset;
|
||||
if (address < startAddr || startAddr + size <= address) {
|
||||
continue;
|
||||
}
|
||||
|
||||
param = SearchParam_(buf, 5, ' ');
|
||||
if (!param) {
|
||||
*strBuf = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((*GetCharPtr_)(param) == '.') {
|
||||
continue;
|
||||
}
|
||||
|
||||
CopySymbol_(param, strBuf, strBufSize, ' ');
|
||||
return true;
|
||||
}
|
||||
|
||||
get_next_section_info:
|
||||
if (sectionInfo) {
|
||||
if (!--sectionCnt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sectionInfo++;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool QuerySymbolToSingleMapFile_(MapFile* pMapFile, u32 address, u8* strBuf,
|
||||
u32 strBufSize) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(723, pMapFile);
|
||||
NW4HBM_ASSERT_CHECK_NULL(724, strBuf);
|
||||
|
||||
if (pMapFile->mapBuf) {
|
||||
GetCharPtr_ = &GetCharOnMem_;
|
||||
return QuerySymbolToMapFile_(pMapFile->mapBuf, pMapFile->moduleInfo, address,
|
||||
strBuf, strBufSize);
|
||||
}
|
||||
|
||||
if (pMapFile->fileEntry >= 0) {
|
||||
bool ret;
|
||||
|
||||
if (DVDFastOpen(pMapFile->fileEntry, &sFileInfo)) {
|
||||
sFileLength = sFileInfo.length;
|
||||
GetCharPtr_ = &GetCharOnDvd_;
|
||||
ret = QuerySymbolToMapFile_((u8*)(0x80000000), pMapFile->moduleInfo, address, strBuf, strBufSize);
|
||||
|
||||
DVDClose(&sFileInfo);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
*strBuf = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MapFile_QuerySymbol(u32 address, u8* strBuf, u32 strBufSize) {
|
||||
MapFile* pMap;
|
||||
for (pMap = sMapFileList; pMap; pMap = pMap->next) {
|
||||
if (QuerySymbolToSingleMapFile_(pMap, address, strBuf, strBufSize)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace db
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef NW4R_DB_DIRECTPRINT_H
|
||||
#define NW4R_DB_DIRECTPRINT_H
|
||||
|
||||
#include <revolution/gx.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
void DirectPrint_Init();
|
||||
bool DirectPrint_IsActive();
|
||||
void DirectPrint_EraseXfb(int posh, int posv, int sizeh, int sizev);
|
||||
void DirectPrint_ChangeXfb(void* framebuf, u16 width, u16 height);
|
||||
void DirectPrint_StoreCache();
|
||||
void DirectPrint_DrawString(int posh, int posv, bool turnOver, const char* format, ...);
|
||||
void DirectPrint_SetColor(u8 r, u8 g, u8 b);
|
||||
|
||||
namespace detail {
|
||||
void DirectPrint_DrawStringToXfb(int posh, int posv, const char* format, va_list vargs, bool turnOver, bool backErase);
|
||||
void* DirectPrint_SetupFB(const GXRenderModeObj* rmode);
|
||||
}
|
||||
} // namespace db
|
||||
} // namespace nw4r
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef NW4R_DB_MAPFILE_H
|
||||
#define NW4R_DB_MAPFILE_H
|
||||
|
||||
#include <revolution/os.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace db {
|
||||
struct MapFile {
|
||||
/* 0x00 */ u8* mapBuf;
|
||||
/* 0x04 */ OSModuleInfo* moduleInfo;
|
||||
/* 0x08 */ s32 fileEntry;
|
||||
/* 0x0C */ MapFile* next;
|
||||
}; // size = 0x10
|
||||
|
||||
bool MapFile_Exists();
|
||||
bool MapFile_QuerySymbol(u32 address, u8* strBuf, u32 strBufSize);
|
||||
} // namespace db
|
||||
} // namespace nw4r
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,209 @@
|
||||
#ifndef NW4HBM_LYT_ANIMATION_H
|
||||
#define NW4HBM_LYT_ANIMATION_H
|
||||
|
||||
#include "lyt_types.h"
|
||||
#include "resourceAccessor.h"
|
||||
#include "resources.h"
|
||||
|
||||
|
||||
#define TexMtxMax 10
|
||||
#define IndTexMtxMax 3
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class Pane;
|
||||
class Material;
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMTARGET_PANE_TRANSX = 0,
|
||||
/* 1 */ ANIMTARGET_PANE_TRANSY,
|
||||
/* 2 */ ANIMTARGET_PANE_TRANSZ,
|
||||
|
||||
/* 3 */ ANIMTARGET_PANE_ROTX,
|
||||
/* 4 */ ANIMTARGET_PANE_ROTY,
|
||||
/* 5 */ ANIMTARGET_PANE_ROTZ,
|
||||
|
||||
/* 6 */ ANIMTARGET_PANE_SCALEX,
|
||||
/* 7 */ ANIMTARGET_PANE_SCALEY,
|
||||
|
||||
/* 8 */ ANIMTARGET_PANE_SIZEX,
|
||||
/* 9 */ ANIMTARGET_PANE_SIZEY,
|
||||
|
||||
/* 10 */ ANIMTARGET_PANE_MAX,
|
||||
/* 16 */ ANIMTARGET_PANE_COLOR_ALPHA = 16,
|
||||
/* 17 */ ANIMTARGET_PANE_COLOR_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMTARGET_VERTEXCOLOR_LT_RED = 0,
|
||||
/* 1 */ ANIMTARGET_VERTEXCOLOR_LT_GREEN,
|
||||
/* 2 */ ANIMTARGET_VERTEXCOLOR_LT_BLUE,
|
||||
/* 3 */ ANIMTARGET_VERTEXCOLOR_LT_ALPHA,
|
||||
|
||||
/* 4 */ ANIMTARGET_VERTEXCOLOR_RT_RED,
|
||||
/* 5 */ ANIMTARGET_VERTEXCOLOR_RT_GREEN,
|
||||
/* 6 */ ANIMTARGET_VERTEXCOLOR_RT_BLUE,
|
||||
/* 7 */ ANIMTARGET_VERTEXCOLOR_RT_ALPHA,
|
||||
|
||||
/* 8 */ ANIMTARGET_VERTEXCOLOR_LB_RED,
|
||||
/* 9 */ ANIMTARGET_VERTEXCOLOR_LB_GREEN,
|
||||
/* 10 */ ANIMTARGET_VERTEXCOLOR_LB_BLUE,
|
||||
/* 11 */ ANIMTARGET_VERTEXCOLOR_LB_ALPHA,
|
||||
|
||||
/* 12 */ ANIMTARGET_VERTEXCOLOR_RB_RED,
|
||||
/* 13 */ ANIMTARGET_VERTEXCOLOR_RB_GREEN,
|
||||
/* 14 */ ANIMTARGET_VERTEXCOLOR_RB_BLUE,
|
||||
/* 15 */ ANIMTARGET_VERTEXCOLOR_RB_ALPHA,
|
||||
|
||||
/* 16 */ ANIMTARGET_VERTEXCOLOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMTARGET_MATCOLOR_MATR = 0,
|
||||
/* 1 */ ANIMTARGET_MATCOLOR_MATG,
|
||||
/* 2 */ ANIMTARGET_MATCOLOR_MATB,
|
||||
/* 3 */ ANIMTARGET_MATCOLOR_MATA,
|
||||
|
||||
/* 4 */ ANIMTARGET_MATCOLOR_TEV0R,
|
||||
/* 5 */ ANIMTARGET_MATCOLOR_TEV0G,
|
||||
/* 6 */ ANIMTARGET_MATCOLOR_TEV0B,
|
||||
/* 7 */ ANIMTARGET_MATCOLOR_TEV0A,
|
||||
|
||||
/* 8 */ ANIMTARGET_MATCOLOR_TEV1R,
|
||||
/* 9 */ ANIMTARGET_MATCOLOR_TEV1G,
|
||||
/* 10 */ ANIMTARGET_MATCOLOR_TEV1B,
|
||||
/* 11 */ ANIMTARGET_MATCOLOR_TEV1A,
|
||||
|
||||
/* 12 */ ANIMTARGET_MATCOLOR_TEV2R,
|
||||
/* 13 */ ANIMTARGET_MATCOLOR_TEV2G,
|
||||
/* 14 */ ANIMTARGET_MATCOLOR_TEV2B,
|
||||
/* 15 */ ANIMTARGET_MATCOLOR_TEV2A,
|
||||
|
||||
/* 16 */ ANIMTARGET_MATCOLOR_TEVK0R,
|
||||
/* 17 */ ANIMTARGET_MATCOLOR_TEVK0G,
|
||||
/* 18 */ ANIMTARGET_MATCOLOR_TEVK0B,
|
||||
/* 19 */ ANIMTARGET_MATCOLOR_TEVK0A,
|
||||
|
||||
/* 20 */ ANIMTARGET_MATCOLOR_TEVK1R,
|
||||
/* 21 */ ANIMTARGET_MATCOLOR_TEVK1G,
|
||||
/* 22 */ ANIMTARGET_MATCOLOR_TEVK1B,
|
||||
/* 23 */ ANIMTARGET_MATCOLOR_TEVK1A,
|
||||
|
||||
/* 24 */ ANIMTARGET_MATCOLOR_TEVK2R,
|
||||
/* 25 */ ANIMTARGET_MATCOLOR_TEVK2G,
|
||||
/* 26 */ ANIMTARGET_MATCOLOR_TEVK2B,
|
||||
/* 27 */ ANIMTARGET_MATCOLOR_TEVK2A,
|
||||
|
||||
/* 28 */ ANIMTARGET_MATCOLOR_TEVK3R,
|
||||
/* 29 */ ANIMTARGET_MATCOLOR_TEVK3G,
|
||||
/* 30 */ ANIMTARGET_MATCOLOR_TEVK3B,
|
||||
/* 31 */ ANIMTARGET_MATCOLOR_TEVK3A,
|
||||
|
||||
/* 32 */ ANIMTARGET_MATCOLOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMTARGET_TEXSRT_TRANSX = 0,
|
||||
/* 1 */ ANIMTARGET_TEXSRT_TRANSY,
|
||||
/* 2 */ ANIMTARGET_TEXSRT_ROT,
|
||||
/* 3 */ ANIMTARGET_TEXSRT_SCALEX,
|
||||
/* 4 */ ANIMTARGET_TEXSRT_SCALEY,
|
||||
/* 5 */ ANIMTARGET_TEXSRT_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMTARGET_TEXPATTURN_IMAGE = 0,
|
||||
/* 1 */ ANIMTARGET_TEXPATTURN_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
/* 0 */ ANIMCURVE_NONE = 0,
|
||||
/* 1 */ ANIMCURVE_STEP,
|
||||
/* 2 */ ANIMCURVE_HERMITE,
|
||||
/* 3 */ ANIMCURVE_MAX
|
||||
};
|
||||
|
||||
class AnimTransform {
|
||||
public:
|
||||
AnimTransform();
|
||||
|
||||
/* 0x08 */ virtual ~AnimTransform();
|
||||
/* 0x0C */ virtual void SetResource(const res::AnimationBlock* pRes,
|
||||
ResourceAccessor* pResAccessor) = 0;
|
||||
/* 0x10 */ virtual void Bind(Pane* pane, bool bRecursive) = 0;
|
||||
/* 0x14 */ virtual void Bind(Material* pMaterial) = 0;
|
||||
/* 0x18 */ virtual void Animate(u32 idx, Pane* pane) = 0;
|
||||
/* 0x1C */ virtual void Animate(u32 idx, Material* pMaterial) = 0;
|
||||
|
||||
f32 GetFrameMax() const { return GetFrameSize(); }
|
||||
u16 GetFrameSize() const;
|
||||
|
||||
void SetFrame(f32 frame) { mFrame = frame; }
|
||||
|
||||
bool IsLoopData() const;
|
||||
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ ut::LinkListNode mLink;
|
||||
|
||||
protected:
|
||||
/* 0x0C */ const res::AnimationBlock* mpRes;
|
||||
/* 0x10 */ f32 mFrame;
|
||||
}; // size = 0x14
|
||||
typedef ut::LinkList<AnimTransform, offsetof(AnimTransform, mLink)> AnimTransformList;
|
||||
|
||||
class AnimationLink {
|
||||
public:
|
||||
AnimationLink() : mLink(), mbDisable(false) { Reset(); }
|
||||
~AnimationLink() {}
|
||||
|
||||
AnimTransform* GetAnimTransform() const { return mAnimTrans; }
|
||||
|
||||
u16 GetIndex() const { return mIdx; }
|
||||
bool IsEnable() const { return !mbDisable; }
|
||||
|
||||
void SetEnable(bool bEnable) { mbDisable = !bEnable; }
|
||||
|
||||
void Reset() { SetAnimTransform(NULL, 0); }
|
||||
|
||||
void SetAnimTransform(AnimTransform* animTrans, u16 idx) {
|
||||
mAnimTrans = animTrans;
|
||||
mIdx = idx;
|
||||
}
|
||||
|
||||
/* 0x00 */ ut::LinkListNode mLink;
|
||||
|
||||
private:
|
||||
/* 0x08 */ AnimTransform* mAnimTrans;
|
||||
/* 0x0C */ u16 mIdx;
|
||||
/* 0x0E */ bool mbDisable;
|
||||
}; // size = 0x10
|
||||
typedef ut::LinkList<AnimationLink, offsetof(AnimationLink, mLink)> AnimationLinkList;
|
||||
|
||||
class AnimTransformBasic : public AnimTransform {
|
||||
public:
|
||||
AnimTransformBasic();
|
||||
|
||||
/* 0x08 */ virtual ~AnimTransformBasic();
|
||||
/* 0x0C */ virtual void SetResource(const res::AnimationBlock* pRes,
|
||||
ResourceAccessor* pResAccessor);
|
||||
/* 0x10 */ virtual void Bind(Pane* pane, bool bRecursive);
|
||||
/* 0x14 */ virtual void Bind(Material* pMaterial);
|
||||
/* 0x18 */ virtual void Animate(u32 idx, Pane* pane);
|
||||
/* 0x1C */ virtual void Animate(u32 idx, Material* pMaterial);
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0x14 */ void** mpFileResAry;
|
||||
/* 0x18 */ AnimationLink* mAnimLinkAry;
|
||||
/* 0x1C */ u16 mAnimLinkNum;
|
||||
}; // size = 0x20
|
||||
|
||||
namespace detail {
|
||||
AnimationLink* FindAnimationLink(AnimationLinkList* animList, AnimTransform* animTrans);
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
#ifndef NW4HBM_LYT_ARC_RESOURCE_ACCESSOR_H
|
||||
#define NW4HBM_LYT_ARC_RESOURCE_ACCESSOR_H
|
||||
|
||||
#include "revolution/types.h"
|
||||
|
||||
#include "revolution/arc.h"
|
||||
|
||||
#include "../ut/Font.h"
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
#include "resourceAccessor.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
static const int RESOURCE_NAME_MAX = 128;
|
||||
|
||||
class FontRefLink {
|
||||
public:
|
||||
FontRefLink();
|
||||
|
||||
void Set(const char* name, ut::Font* pFont);
|
||||
|
||||
const char* GetFontName() const { return mFontName; }
|
||||
ut::Font* GetFont() const { return mpFont; }
|
||||
|
||||
/* 0x00 */ ut::LinkListNode mLink;
|
||||
|
||||
protected:
|
||||
/* 0x08 */ char mFontName[RESOURCE_NAME_MAX];
|
||||
/* 0x88 */ ut::Font* mpFont;
|
||||
};
|
||||
typedef ut::LinkList<FontRefLink, offsetof(FontRefLink, mLink)> FontRefLinkList;
|
||||
|
||||
class ArcResourceLink {
|
||||
public:
|
||||
ArcResourceLink() {}
|
||||
|
||||
bool Set(void* archiveStart, const char* resRootDirectory);
|
||||
|
||||
char* GetResRootDir() { return mResRootDir; }
|
||||
ARCHandle* GetArcHandle() { return &mArcHandle; }
|
||||
|
||||
/* 0x00 */ ut::LinkListNode mLink;
|
||||
|
||||
protected:
|
||||
/* 0x08 */ ARCHandle mArcHandle;
|
||||
|
||||
/* 0x24 */ char mResRootDir[RESOURCE_NAME_MAX];
|
||||
};
|
||||
typedef ut::LinkList<ArcResourceLink, offsetof(ArcResourceLink, mLink)> ArcResourceLinkList;
|
||||
|
||||
class ArcResourceAccessor : public ResourceAccessor {
|
||||
public:
|
||||
ArcResourceAccessor();
|
||||
|
||||
/* 0x08 */ virtual ~ArcResourceAccessor() {}
|
||||
/* 0x0C */ virtual void* GetResource(u32 resType, const char* name, u32* pSize = NULL);
|
||||
/* 0x10 */ virtual ut::Font* GetFont(const char* name);
|
||||
|
||||
bool Attach(void* archiveStart, const char* resourceRootDirectory);
|
||||
|
||||
bool IsAttached(void) { return this->mArcBuf != NULL; }
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0x04 */ ARCHandle mArcHandle;
|
||||
/* 0x20 */ void* mArcBuf;
|
||||
/* 0x24 */ FontRefLinkList mFontList;
|
||||
/* 0x30 */ char mResRootDir[RESOURCE_NAME_MAX];
|
||||
};
|
||||
|
||||
class MultiArcResourceAccessor : public ResourceAccessor {
|
||||
public:
|
||||
MultiArcResourceAccessor();
|
||||
|
||||
/* 0x08 */ virtual ~MultiArcResourceAccessor();
|
||||
/* 0x0C */ virtual void* GetResource(u32 resType, const char* name, u32* pSize = NULL);
|
||||
/* 0x10 */ virtual ut::Font* GetFont(const char* name);
|
||||
|
||||
void Attach(ArcResourceLink* pLink);
|
||||
void DetachAll() { reinterpret_cast<ut::detail::LinkListImpl*>(&mArcList)->Clear(); }
|
||||
void RegistFont(FontRefLink* pLink);
|
||||
|
||||
protected:
|
||||
/* 0x00 (base) */
|
||||
/* 0x04 */ ArcResourceLinkList mArcList;
|
||||
/* 0x10 */ FontRefLinkList mFontList;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
ut::Font* FindFont(FontRefLinkList* pFontRefList, const char* name);
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef NW4HBM_LYT_BOUNDING_H
|
||||
#define NW4HBM_LYT_BOUNDING_H
|
||||
|
||||
#include "pane.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class Bounding : public Pane {
|
||||
public:
|
||||
Bounding(const res::Bounding* pBlock, const ResBlockSet& resBlockSet);
|
||||
|
||||
/* 0x08 */ virtual ~Bounding();
|
||||
/* 0x0C */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x18 */ virtual void DrawSelf(const DrawInfo& drawInfo);
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
#ifndef NW4HBM_LYT_COMMON_H
|
||||
#define NW4HBM_LYT_COMMON_H
|
||||
|
||||
#include "revolution/tpl.h"
|
||||
#include "revolution/types.h"
|
||||
|
||||
#include "../ut/Color.h"
|
||||
|
||||
#include "animation.h"
|
||||
#include "resources.h"
|
||||
|
||||
#include "../db/assert.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
namespace detail {
|
||||
|
||||
typedef math::VEC2 TexCoords[4];
|
||||
|
||||
class TexCoordAry {
|
||||
public:
|
||||
TexCoordAry();
|
||||
|
||||
u8 GetSize() const { return mNum; }
|
||||
const TexCoords* GetArray() const { return mpData; }
|
||||
|
||||
void SetSize(u8 num);
|
||||
|
||||
bool IsEmpty() const { return mCap == 0; }
|
||||
|
||||
void Reserve(u8 num);
|
||||
|
||||
void Free();
|
||||
void Copy(const void* pResTexCoord, u8 texCoordNum);
|
||||
|
||||
void SetCoord(u32 idx, const math::VEC2* vec);
|
||||
void GetCoord(u32 idx, math::VEC2* vec) const;
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 mCap;
|
||||
/* 0x01 */ u8 mNum;
|
||||
/* 0x04 */ TexCoords* mpData;
|
||||
};
|
||||
|
||||
bool EqualsPaneName(const char* name1, const char* name2);
|
||||
bool EqualsMaterialName(const char* name1, const char* name2);
|
||||
|
||||
bool TestFileHeader(const res::BinaryFileHeader& fileHeader);
|
||||
bool TestFileHeader(const res::BinaryFileHeader& fileHeader, u32 testSig);
|
||||
|
||||
bool IsModulateVertexColor(ut::Color* vtxColors, u8 glbAlpha);
|
||||
|
||||
ut::Color MultipleAlpha(const ut::Color col, u8 alpha);
|
||||
void MultipleAlpha(ut::Color* dst, const ut::Color* src, u8 alpha);
|
||||
|
||||
void SetVertexFormat(bool bModulate, u8 texCoordNum);
|
||||
|
||||
void DrawQuad(const math::VEC2& basePt, const Size& size, u8 texCoordNum,
|
||||
const TexCoords* texCoords, const ut::Color* vtxColors);
|
||||
void DrawQuad(const math::VEC2& basePt, const Size& size, u8 texCoordNum,
|
||||
const TexCoords* texCoords, const ut::Color* vtxColors, u8 alpha);
|
||||
|
||||
void DrawLine(const math::VEC2& pos, const Size& size, ut::Color color);
|
||||
|
||||
void InitGXTexObjFromTPL(GXTexObj* to, TPLPalette* pal, u32 id);
|
||||
|
||||
inline s32 GetSignatureInt(const char* sig) {
|
||||
return *reinterpret_cast<const s32*>(sig);
|
||||
}
|
||||
|
||||
inline const char* GetStrTableStr(const void* pStrTable, int index) {
|
||||
const u32* offsets = static_cast<const u32*>(pStrTable);
|
||||
const char* stringPool = static_cast<const char*>(pStrTable);
|
||||
|
||||
return &stringPool[offsets[index]];
|
||||
}
|
||||
|
||||
inline u8 GetVtxColorElement(const ut::Color* cols, u32 idx) {
|
||||
NW4HBM_ASSERT(199, idx < ANIMTARGET_VERTEXCOLOR_MAX);
|
||||
return reinterpret_cast<const u8*>(cols + idx / 4)[idx % 4];
|
||||
}
|
||||
|
||||
inline void SetVtxColorElement(ut::Color* cols, u32 idx, u8 value) {
|
||||
NW4HBM_ASSERT(212, idx < ANIMTARGET_VERTEXCOLOR_MAX);
|
||||
reinterpret_cast<u8*>(cols + idx / 4)[idx % 4] = value;
|
||||
}
|
||||
|
||||
inline u8 GetHorizontalPosition(u8 var) {
|
||||
return var % HORIZONTALPOSITION_MAX;
|
||||
}
|
||||
|
||||
inline u8 GetVerticalPosition(u8 var) {
|
||||
return var / VERTICALPOSITION_MAX;
|
||||
}
|
||||
|
||||
inline void SetHorizontalPosition(u8* pVar, u8 newVal) {
|
||||
*pVar = GetVerticalPosition(*pVar) * HORIZONTALPOSITION_MAX + newVal;
|
||||
}
|
||||
|
||||
inline void SetVerticalPosition(u8* pVar, u8 newVal) {
|
||||
*pVar = newVal * VERTICALPOSITION_MAX + GetHorizontalPosition(*pVar);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef NW4HBM_LYT_DRAW_INFO_H
|
||||
#define NW4HBM_LYT_DRAW_INFO_H
|
||||
|
||||
#include <revolution/gx.h>
|
||||
|
||||
#include "../math/types.h"
|
||||
|
||||
#include "../ut/Rect.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class DrawInfo {
|
||||
public:
|
||||
DrawInfo();
|
||||
|
||||
/* 0x08 */ virtual ~DrawInfo();
|
||||
|
||||
void SetViewRect(const ut::Rect& rect) { mViewRect = rect; }
|
||||
|
||||
const math::MTX34& GetViewMtx() const { return mViewMtx; }
|
||||
void SetViewMtx(const math::MTX34& value) { mViewMtx = value; }
|
||||
|
||||
const math::VEC2& GetLocationAdjustScale() const { return mLocationAdjustScale; }
|
||||
void SetLocationAdjustScale(const math::VEC2& scale) { mLocationAdjustScale = scale; }
|
||||
|
||||
bool IsMultipleViewMtxOnDraw() const { return mFlag.mulViewDraw; }
|
||||
void SetMultipleViewMtxOnDraw(bool bEnable) { mFlag.mulViewDraw = bEnable; }
|
||||
|
||||
bool IsInfluencedAlpha() const { return mFlag.influencedAlpha; }
|
||||
void SetInfluencedAlpha(bool bEnable) { mFlag.influencedAlpha = bEnable; }
|
||||
|
||||
bool IsLocationAdjust() const { return mFlag.locationAdjust; }
|
||||
void SetLocationAdjust(bool bEnable) { mFlag.locationAdjust = bEnable; }
|
||||
|
||||
bool IsInvisiblePaneCalculateMtx() const { return mFlag.invisiblePaneCalculateMtx; }
|
||||
void SetInvisiblePaneCalculateMtx(bool bEnable) {
|
||||
mFlag.invisiblePaneCalculateMtx = bEnable;
|
||||
}
|
||||
|
||||
bool IsDebugDrawMode() const { return mFlag.debugDrawMode; }
|
||||
void SetDebugDrawMode(bool bEnable) { mFlag.debugDrawMode = bEnable; }
|
||||
|
||||
bool IsYAxisUp() const { return mViewRect.bottom - mViewRect.top < 0.0f; }
|
||||
|
||||
f32 GetGlobalAlpha() const { return mGlobalAlpha; }
|
||||
void SetGlobalAlpha(f32 alpha) { mGlobalAlpha = alpha; }
|
||||
|
||||
protected:
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ math::MTX34 mViewMtx;
|
||||
/* 0x34 */ ut::Rect mViewRect;
|
||||
/* 0x44 */ math::VEC2 mLocationAdjustScale;
|
||||
/* 0x4C */ f32 mGlobalAlpha;
|
||||
/* 0x50 */ struct {
|
||||
u8 mulViewDraw : 1; // 10000000
|
||||
u8 influencedAlpha : 1; // 01000000
|
||||
u8 locationAdjust : 1; // 00100000
|
||||
u8 invisiblePaneCalculateMtx : 1; // 00010000
|
||||
u8 debugDrawMode : 1; // 00001000
|
||||
} mFlag;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef NW4HBM_LYT_GROUP_H
|
||||
#define NW4HBM_LYT_GROUP_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "pane.h"
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
namespace detail {
|
||||
typedef struct PaneLink {
|
||||
ut::LinkListNode mLink;
|
||||
|
||||
/* 0x08 */ Pane* mTarget;
|
||||
} PaneLink;
|
||||
} // namespace detail
|
||||
typedef ut::LinkList<detail::PaneLink, offsetof(detail::PaneLink, mLink)> PaneLinkList;
|
||||
|
||||
class Group {
|
||||
public:
|
||||
Group();
|
||||
Group(const res::Group* pResGroup, Pane* pRootPane);
|
||||
|
||||
/* 0x08 */ virtual ~Group();
|
||||
|
||||
const char* GetName() const { return mName; }
|
||||
bool IsUserAllocated() const { return mbUserAllocated; }
|
||||
|
||||
PaneLinkList& GetPaneList() { return mPaneLinkList; };
|
||||
|
||||
void Init();
|
||||
void AppendPane(Pane* pane);
|
||||
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ ut::LinkListNode mLink;
|
||||
|
||||
protected:
|
||||
/* 0x0C */ PaneLinkList mPaneLinkList;
|
||||
/* 0x18 */ char mName[16];
|
||||
/* 0x29 */ bool mbUserAllocated;
|
||||
/* 0x2A */ u8 mPadding[2];
|
||||
};
|
||||
typedef ut::LinkList<Group, offsetof(Group, mLink)> GroupList;
|
||||
|
||||
class GroupContainer {
|
||||
public:
|
||||
GroupContainer() {}
|
||||
~GroupContainer();
|
||||
|
||||
GroupList& GetGroupList() { return mGroupList; }
|
||||
|
||||
void AppendGroup(Group* pGroup);
|
||||
Group* FindGroupByName(const char* findName);
|
||||
|
||||
protected:
|
||||
/* 0x00 */ GroupList mGroupList;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef NW4HBM_LYT_LAYOUT_H
|
||||
#define NW4HBM_LYT_LAYOUT_H
|
||||
|
||||
#include <revolution/mem.h>
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "drawInfo.h"
|
||||
#include "group.h"
|
||||
#include "lyt_types.h"
|
||||
#include "resourceAccessor.h"
|
||||
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
#include "../ut/TagProcessorBase.h"
|
||||
#include "../ut/WideTagProcessor.h"
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class Layout {
|
||||
public:
|
||||
Layout();
|
||||
|
||||
/* 0x08 */ virtual ~Layout();
|
||||
/* 0x0C */ virtual bool Build(const void* lytResBuf, ResourceAccessor* pResAcsr);
|
||||
/* 0x10 */ virtual AnimTransform* CreateAnimTransform(const void* anmResBuf,
|
||||
ResourceAccessor* pResAcsr);
|
||||
/* 0x14 */ virtual void BindAnimation(AnimTransform* animTrans);
|
||||
/* 0x18 */ virtual void UnbindAnimation(AnimTransform* animTrans);
|
||||
/* 0x1C */ virtual void UnbindAllAnimation();
|
||||
/* 0x20 */ virtual void SetAnimationEnable(AnimTransform* animTrans,
|
||||
bool bEnable = true);
|
||||
/* 0x24 */ virtual void CalculateMtx(const DrawInfo& drawInfo);
|
||||
/* 0x28 */ virtual void Draw(const DrawInfo& drawInfo);
|
||||
/* 0x2C */ virtual void Animate(u32 option = 0);
|
||||
/* 0x30 */ virtual void SetTagProcessor(ut::WideTagProcessor* pTagProcessor) NO_INLINE;
|
||||
|
||||
const ut::Rect GetLayoutRect() const;
|
||||
Pane* GetRootPane() const { return mpRootPane; }
|
||||
GroupContainer* GetGroupContainer() const { return mpGroupContainer; }
|
||||
|
||||
static MEMAllocator* GetAllocator() { return mspAllocator; }
|
||||
static void SetAllocator(MEMAllocator* allocator) { mspAllocator = allocator; }
|
||||
|
||||
static void* AllocMemory(u32 size) { return MEMAllocFromAllocator(mspAllocator, size); }
|
||||
static void FreeMemory(void* ptr) { MEMFreeToAllocator(mspAllocator, ptr); }
|
||||
|
||||
static Pane* BuildPaneObj(s32 kind, const void* dataPtr,
|
||||
const ResBlockSet& resBlockSet) NO_INLINE;
|
||||
|
||||
private:
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ AnimTransformList mAnimTransList;
|
||||
/* 0x10 */ Pane* mpRootPane;
|
||||
/* 0x14 */ GroupContainer* mpGroupContainer;
|
||||
/* 0x18 */ Size mLayoutSize;
|
||||
/* 0x20 */ u8 mOriginType;
|
||||
|
||||
static MEMAllocator* mspAllocator;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,466 @@
|
||||
#include "animation.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "layout.h"
|
||||
#include "pane.h"
|
||||
|
||||
#include "new.h"
|
||||
#include <cstring.h>
|
||||
|
||||
namespace {
|
||||
// pretend this is nw4hbm::lyt
|
||||
using namespace nw4hbm;
|
||||
using namespace nw4hbm::lyt;
|
||||
|
||||
inline bool RIsSame(const f32 a, const f32 b, const f32 tolerance) {
|
||||
f32 c = a - b;
|
||||
|
||||
return -tolerance < c && c < tolerance;
|
||||
}
|
||||
|
||||
u16 GetStepCurveValue(f32 frame, const res::StepKey* keyArray, u32 keySize);
|
||||
f32 GetHermiteCurveValue(f32 frame, const res::HermiteKey* keyArray, u32 keySize);
|
||||
|
||||
void AnimatePainSRT(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
void AnimateVisibility(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
void AnimateVertexColor(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
void AnimateMaterialColor(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
void AnimateTextureSRT(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
void AnimateTexturePattern(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame, void** tpls);
|
||||
void AnimateIndTexSRT(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame);
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
||||
u16 GetStepCurveValue(f32 frame, const res::StepKey* keyArray, u32 keySize) {
|
||||
if (keySize == 1 || frame <= keyArray[0].frame) {
|
||||
return keyArray[0].value;
|
||||
}
|
||||
|
||||
if (frame >= keyArray[keySize - 1].frame) {
|
||||
return keyArray[keySize - 1].value;
|
||||
}
|
||||
|
||||
int ikeyL = 0;
|
||||
int ikeyR = keySize - 1;
|
||||
|
||||
while (ikeyL != ikeyR - 1 && ikeyL != ikeyR) {
|
||||
int ikeyCenter = (ikeyL + ikeyR) / 2;
|
||||
const res::StepKey& centerKey = keyArray[ikeyCenter];
|
||||
|
||||
if (frame < centerKey.frame) {
|
||||
ikeyR = ikeyCenter;
|
||||
} else {
|
||||
ikeyL = ikeyCenter;
|
||||
}
|
||||
}
|
||||
|
||||
if (RIsSame(frame, keyArray[ikeyR].frame, 0.001f)) {
|
||||
return keyArray[ikeyR].value;
|
||||
} else {
|
||||
return keyArray[ikeyL].value;
|
||||
}
|
||||
}
|
||||
|
||||
f32 GetHermiteCurveValue(f32 frame, const res::HermiteKey* keyArray, u32 keySize) {
|
||||
if (keySize == 1 || frame <= keyArray[0].frame) {
|
||||
return keyArray[0].value;
|
||||
}
|
||||
|
||||
if (frame >= keyArray[keySize - 1].frame) {
|
||||
return keyArray[keySize - 1].value;
|
||||
}
|
||||
|
||||
int ikeyL = 0;
|
||||
int ikeyR = keySize - 1;
|
||||
|
||||
while (ikeyL != ikeyR - 1 && ikeyL != ikeyR) {
|
||||
int ikeyCenter = (ikeyL + ikeyR) / 2;
|
||||
|
||||
if (frame <= keyArray[ikeyCenter].frame) {
|
||||
ikeyR = ikeyCenter;
|
||||
} else {
|
||||
ikeyL = ikeyCenter;
|
||||
}
|
||||
}
|
||||
|
||||
const res::HermiteKey& key0 = keyArray[ikeyL];
|
||||
const res::HermiteKey& key1 = keyArray[ikeyR];
|
||||
|
||||
if (RIsSame(frame, key1.frame, 0.001f)) {
|
||||
if (ikeyR < keySize - 1 && keyArray[ikeyR + 1].frame == key1.frame) {
|
||||
return keyArray[ikeyR + 1].value;
|
||||
} else {
|
||||
return key1.value;
|
||||
}
|
||||
}
|
||||
|
||||
f32 t1 = frame - key0.frame;
|
||||
f32 t2 = 1.0f / (key1.frame - key0.frame);
|
||||
f32 v0 = key0.value;
|
||||
f32 v1 = key1.value;
|
||||
f32 s0 = key0.slope;
|
||||
f32 s1 = key1.slope;
|
||||
|
||||
f32 t1t1t2 = t1 * t1 * t2;
|
||||
f32 t1t1t2t2 = t1t1t2 * t2;
|
||||
f32 t1t1t1t2t2 = t1 * t1t1t2t2;
|
||||
f32 t1t1t1t2t2t2 = t1t1t1t2t2 * t2;
|
||||
|
||||
// Does anyone know what this means? Because I don't
|
||||
|
||||
// clang-format off
|
||||
return v0 * (( 2.0f * t1t1t1t2t2t2) - (3.0f * t1t1t2t2) + 1.0f)
|
||||
+ v1 * ((-2.0f * t1t1t1t2t2t2) + (3.0f * t1t1t2t2) )
|
||||
+ s0 * (( t1t1t1t2t2 ) - (2.0f * t1t1t2 ) + t1 )
|
||||
+ s1 * (( t1t1t1t2t2 ) - ( t1t1t2 ) );
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void AnimatePainSRT(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(197, pAnimTarget->target < ANIMTARGET_PANE_MAX);
|
||||
NW4HBM_ASSERT(198, pAnimTarget->curveType == ANIMCURVE_HERMITE);
|
||||
|
||||
const res::HermiteKey* keys =
|
||||
detail::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
|
||||
pPane->SetSRTElement(pAnimTarget->target,
|
||||
GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateVisibility(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(217, pAnimTarget->target < ANIMTARGET_PANE_MAX);
|
||||
NW4HBM_ASSERT(218, pAnimTarget->curveType == ANIMCURVE_STEP);
|
||||
|
||||
const res::StepKey* keys =
|
||||
detail::ConvertOffsToPtr<res::StepKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
|
||||
pPane->SetVisible(GetStepCurveValue(frame, keys, pAnimTarget->keyNum) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateVertexColor(Pane* pPane, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(237, pAnimTarget->target < ANIMTARGET_PANE_COLOR_MAX);
|
||||
NW4HBM_ASSERT(238, pAnimTarget->curveType == ANIMCURVE_HERMITE);
|
||||
|
||||
const res::HermiteKey* keys =
|
||||
detail::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
|
||||
f32 value = GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum);
|
||||
value += 0.5f;
|
||||
|
||||
u8 u8Val;
|
||||
OSf32tou8(&value, &u8Val);
|
||||
|
||||
// What
|
||||
pPane->SetColorElement(pAnimTarget->target, *static_cast<u8*>(&u8Val));
|
||||
}
|
||||
}
|
||||
|
||||
inline void AnimateMaterialColor(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(262, pAnimTarget->target < ANIMTARGET_MATCOLOR_MAX);
|
||||
NW4HBM_ASSERT(263, pAnimTarget->curveType == ANIMCURVE_HERMITE);
|
||||
|
||||
const res::HermiteKey* keys =
|
||||
detail::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
|
||||
f32 value = GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum);
|
||||
value += 0.5f;
|
||||
|
||||
s16 s16Val;
|
||||
OSf32tos16(&value, &s16Val);
|
||||
s16Val = ut::Min<s16>(ut::Max<s16>(s16Val, -1024), 1023);
|
||||
|
||||
pMaterial->SetColorElement(pAnimTarget->target, s16Val);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateTextureSRT(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(287, pAnimTarget->id < TexMtxMax);
|
||||
|
||||
if (pAnimTarget->id < pMaterial->GetTexSRTCap()) {
|
||||
NW4HBM_ASSERT(290, pAnimTarget->target < ANIMTARGET_TEXSRT_MAX);
|
||||
NW4HBM_ASSERT(291, pAnimTarget->curveType == ANIMCURVE_HERMITE);
|
||||
|
||||
const res::HermiteKey* keys =
|
||||
detail::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
pMaterial->SetTexSRTElement(pAnimTarget->id, pAnimTarget->target,
|
||||
GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateTexturePattern(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame, void** tpls) {
|
||||
for (int j = 0; j < pAnimInfo->num; j++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[j]);
|
||||
|
||||
NW4HBM_ASSERT(311, pAnimTarget->id < GX_MAX_TEXMAP);
|
||||
|
||||
if (pAnimTarget->id < pMaterial->GetTextureNum()) {
|
||||
NW4HBM_ASSERT(314, pAnimTarget->curveType == ANIMCURVE_STEP);
|
||||
|
||||
if (!pAnimTarget->target) {
|
||||
const res::StepKey* keys = detail::ConvertOffsToPtr<res::StepKey>(
|
||||
pAnimTarget, pAnimTarget->keysOffset);
|
||||
u16 fileIdx = GetStepCurveValue(frame, keys, pAnimTarget->keyNum);
|
||||
pMaterial->SetTextureNoWrap(pAnimTarget->id,
|
||||
static_cast<TPLPalette*>(tpls[fileIdx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimateIndTexSRT(Material* pMaterial, const res::AnimationInfo* pAnimInfo,
|
||||
const u32* animTargetOffsets, f32 frame) {
|
||||
for (int i = 0; i < pAnimInfo->num; i++) {
|
||||
const res::AnimationTarget* pAnimTarget =
|
||||
detail::ConvertOffsToPtr<res::AnimationTarget>(pAnimInfo, animTargetOffsets[i]);
|
||||
|
||||
NW4HBM_ASSERT(337, pAnimTarget->id < IndTexMtxMax);
|
||||
|
||||
if (pAnimTarget->id < pMaterial->GetIndTexSRTCap()) {
|
||||
NW4HBM_ASSERT(340, pAnimTarget->target < ANIMTARGET_TEXSRT_MAX);
|
||||
NW4HBM_ASSERT(341, pAnimTarget->curveType == ANIMCURVE_HERMITE);
|
||||
|
||||
const res::HermiteKey* keys =
|
||||
detail::ConvertOffsToPtr<res::HermiteKey>(pAnimTarget, pAnimTarget->keysOffset);
|
||||
pMaterial->SetIndTexSRTElement(
|
||||
pAnimTarget->id, pAnimTarget->target,
|
||||
GetHermiteCurveValue(frame, keys, pAnimTarget->keyNum));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
AnimTransform::AnimTransform() : mLink(), mpRes(NULL), mFrame(0.0f) {}
|
||||
|
||||
AnimTransform::~AnimTransform() {}
|
||||
|
||||
u16 AnimTransform::GetFrameSize() const {
|
||||
return mpRes->frameSize;
|
||||
}
|
||||
|
||||
AnimTransformBasic::AnimTransformBasic()
|
||||
: mpFileResAry(NULL), mAnimLinkAry(NULL), mAnimLinkNum(0) {}
|
||||
|
||||
AnimTransformBasic::~AnimTransformBasic() {
|
||||
if (mAnimLinkAry) {
|
||||
Layout::FreeMemory(mAnimLinkAry);
|
||||
}
|
||||
|
||||
if (mpFileResAry) {
|
||||
Layout::FreeMemory(mpFileResAry);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTransformBasic::SetResource(const res::AnimationBlock* pRes,
|
||||
ResourceAccessor* pResAccessor) {
|
||||
NW4HBM_ASSERT(422, mpFileResAry == 0);
|
||||
NW4HBM_ASSERT(423, mAnimLinkAry == 0);
|
||||
|
||||
mpRes = pRes;
|
||||
mpFileResAry = NULL;
|
||||
|
||||
if (pRes->fileNum) {
|
||||
mpFileResAry =
|
||||
static_cast<void**>(Layout::AllocMemory(sizeof(*mpFileResAry) * pRes->fileNum));
|
||||
|
||||
if (mpFileResAry) {
|
||||
const u32* fileNameOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(mpRes, sizeof(*mpRes));
|
||||
|
||||
for (int i = 0; i < mpRes->fileNum; i++) {
|
||||
mpFileResAry[i] = pResAccessor->GetResource(
|
||||
'timg', detail::GetStrTableStr(fileNameOffsets, i), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAnimLinkAry = static_cast<AnimationLink*>(
|
||||
Layout::AllocMemory(sizeof(*mAnimLinkAry) * pRes->animContNum));
|
||||
|
||||
if (mAnimLinkAry) {
|
||||
mAnimLinkNum = pRes->animContNum;
|
||||
std::memset(mAnimLinkAry, 0, sizeof(*mAnimLinkAry) * pRes->animContNum);
|
||||
|
||||
for (u16 i = 0; i < pRes->animContNum; i++) {
|
||||
new (&mAnimLinkAry[i]) AnimationLink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTransformBasic::Bind(Pane* pPane, bool bRecursive) {
|
||||
const u32* animContOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(mpRes, mpRes->animContOffsetsOffset);
|
||||
|
||||
for (u16 i = 0; i < mpRes->animContNum; i++) {
|
||||
const res::AnimationContent* pAnimCont =
|
||||
detail::ConvertOffsToPtr<res::AnimationContent>(mpRes, animContOffsets[i]);
|
||||
|
||||
if (pAnimCont->type == res::AnimationContent::ACType_Pane) {
|
||||
Pane* pFindPane = pPane->FindPaneByName(pAnimCont->name, bRecursive);
|
||||
|
||||
if (pFindPane) {
|
||||
mAnimLinkAry[i].SetAnimTransform(this, i);
|
||||
pFindPane->AddAnimationLink(&mAnimLinkAry[i]);
|
||||
}
|
||||
} else {
|
||||
Material* pFindMat = pPane->FindMaterialByName(pAnimCont->name, bRecursive);
|
||||
|
||||
if (pFindMat) {
|
||||
mAnimLinkAry[i].SetAnimTransform(this, i);
|
||||
pFindMat->AddAnimationLink(&mAnimLinkAry[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTransformBasic::Bind(Material* pMaterial) {
|
||||
const u32* animContOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(mpRes, mpRes->animContOffsetsOffset);
|
||||
|
||||
for (u16 i = 0; i < mpRes->animContNum; i++) {
|
||||
const res::AnimationContent* pAnimCont =
|
||||
detail::ConvertOffsToPtr<res::AnimationContent>(mpRes, animContOffsets[i]);
|
||||
|
||||
if (pAnimCont->type != res::AnimationContent::ACType_Material) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (detail::EqualsMaterialName(pMaterial->GetName(), pAnimCont->name)) {
|
||||
mAnimLinkAry[i].SetAnimTransform(this, i);
|
||||
pMaterial->AddAnimationLink(&mAnimLinkAry[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTransformBasic::Animate(u32 idx, Pane* pPane) {
|
||||
u32 animContOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(mpRes, mpRes->animContOffsetsOffset)[idx];
|
||||
|
||||
const res::AnimationContent* pAnimCont =
|
||||
detail::ConvertOffsToPtr<res::AnimationContent>(mpRes, animContOffsets);
|
||||
|
||||
const u32* animInfoOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
|
||||
|
||||
for (int i = 0; i < pAnimCont->num; i++) {
|
||||
const res::AnimationInfo* pAnimInfo =
|
||||
detail::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
|
||||
|
||||
const u32* animTargetOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
|
||||
|
||||
switch (pAnimInfo->kind) {
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_PAIN_SRT:
|
||||
AnimatePainSRT(pPane, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_VISIBILITY:
|
||||
AnimateVisibility(pPane, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_VERTEX_COLOR:
|
||||
AnimateVertexColor(pPane, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimTransformBasic::Animate(u32 idx, Material* pMaterial) {
|
||||
u32 animContOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(mpRes, mpRes->animContOffsetsOffset)[idx];
|
||||
|
||||
const res::AnimationContent* pAnimCont =
|
||||
detail::ConvertOffsToPtr<res::AnimationContent>(mpRes, animContOffsets);
|
||||
|
||||
const u32* animInfoOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(pAnimCont, sizeof(*pAnimCont));
|
||||
|
||||
for (int i = 0; i < pAnimCont->num; i++) {
|
||||
const res::AnimationInfo* pAnimInfo =
|
||||
detail::ConvertOffsToPtr<res::AnimationInfo>(pAnimCont, animInfoOffsets[i]);
|
||||
|
||||
const u32* animTargetOffsets =
|
||||
detail::ConvertOffsToPtr<u32>(pAnimInfo, sizeof(*pAnimInfo));
|
||||
|
||||
switch (pAnimInfo->kind) {
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_COLOR:
|
||||
AnimateMaterialColor(pMaterial, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_TEXTURE_SRT:
|
||||
AnimateTextureSRT(pMaterial, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_TEXTURE_PATTERN:
|
||||
if (mpFileResAry) {
|
||||
AnimateTexturePattern(pMaterial, pAnimInfo, animTargetOffsets, mFrame,
|
||||
mpFileResAry);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_IND_TEX_SRT:
|
||||
AnimateIndTexSRT(pMaterial, pAnimInfo, animTargetOffsets, mFrame);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimationLink* detail::FindAnimationLink(AnimationLinkList* pAnimList,
|
||||
AnimTransform* pAnimTrans) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(559, pAnimList);
|
||||
NW4HBM_ASSERT_CHECK_NULL(560, pAnimTrans);
|
||||
for (AnimationLinkList::Iterator it = pAnimList->GetBeginIter();
|
||||
it != pAnimList->GetEndIter(); it++)
|
||||
{
|
||||
if (pAnimTrans == it->GetAnimTransform()) {
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,197 @@
|
||||
#include "arcResourceAccessor.h"
|
||||
|
||||
#include <revolution/arc.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
namespace {
|
||||
|
||||
s32 FindNameResource(ARCHandle* pArcHandle, const char* resName) NO_INLINE {
|
||||
s32 entryNum = -1;
|
||||
|
||||
ARCDir dir;
|
||||
BOOL bSuccess = ARCOpenDir(pArcHandle, ".", &dir);
|
||||
NW4HBM_ASSERT(48, bSuccess);
|
||||
|
||||
ARCDirEntry dirEntry;
|
||||
|
||||
while (ARCReadDir(&dir, &dirEntry)) {
|
||||
if (dirEntry.isDir != 0) {
|
||||
bSuccess = ARCChangeDir(pArcHandle, dirEntry.name);
|
||||
NW4HBM_ASSERT(57, bSuccess);
|
||||
|
||||
entryNum = FindNameResource(pArcHandle, resName);
|
||||
bSuccess = ARCChangeDir(pArcHandle, "..");
|
||||
NW4HBM_ASSERT(60, bSuccess);
|
||||
|
||||
if (entryNum != -1) {
|
||||
break;
|
||||
}
|
||||
} else if (stricmp(resName, dirEntry.name) == 0) {
|
||||
entryNum = dirEntry.entryNum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bSuccess = ARCCloseDir(&dir);
|
||||
NW4HBM_ASSERT(77, bSuccess);
|
||||
return entryNum;
|
||||
}
|
||||
|
||||
void* GetResourceSub(ARCHandle* pArcHandle, const char* resRootDir, u32 resType,
|
||||
const char* name, u32* pSize) {
|
||||
s32 entryNum = -1;
|
||||
|
||||
if (ARCConvertPathToEntrynum(pArcHandle, resRootDir) != -1 &&
|
||||
ARCChangeDir(pArcHandle, resRootDir))
|
||||
{
|
||||
if (!resType) {
|
||||
entryNum = FindNameResource(pArcHandle, name);
|
||||
} else {
|
||||
char resTypeStr[5];
|
||||
resTypeStr[0] = resType >> 24;
|
||||
resTypeStr[1] = resType >> 16;
|
||||
resTypeStr[2] = resType >> 8;
|
||||
resTypeStr[3] = resType;
|
||||
resTypeStr[4] = '\0';
|
||||
|
||||
if (ARCConvertPathToEntrynum(pArcHandle, resTypeStr) != -1 &&
|
||||
ARCChangeDir(pArcHandle, resTypeStr))
|
||||
{
|
||||
entryNum = ARCConvertPathToEntrynum(pArcHandle, name);
|
||||
BOOL bSuccess = ARCChangeDir(pArcHandle, "..");
|
||||
NW4HBM_ASSERT(117, bSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL bSuccess = ARCChangeDir(pArcHandle, "..");
|
||||
NW4HBM_ASSERT(123, bSuccess);
|
||||
}
|
||||
|
||||
if (entryNum != -1) {
|
||||
ARCFileInfo arcFileInfo;
|
||||
BOOL bSuccess = ARCFastOpen(pArcHandle, entryNum, &arcFileInfo);
|
||||
NW4HBM_ASSERT(131, bSuccess);
|
||||
|
||||
void* resPtr = ARCGetStartAddrInMem(&arcFileInfo);
|
||||
|
||||
if (pSize) {
|
||||
*pSize = ARCGetLength(&arcFileInfo);
|
||||
}
|
||||
|
||||
ARCClose(&arcFileInfo);
|
||||
|
||||
return resPtr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
ut::Font* detail::FindFont(FontRefLinkList* pFontRefList, const char* name) {
|
||||
for (FontRefLinkList::Iterator it = pFontRefList->GetBeginIter();
|
||||
it != pFontRefList->GetEndIter(); it++)
|
||||
{
|
||||
if (strcmp(name, it->GetFontName()) == 0) {
|
||||
return it->GetFont();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FontRefLink::FontRefLink() : mpFont(NULL) {}
|
||||
|
||||
void FontRefLink::Set(const char* name, ut::Font* pFont) {
|
||||
strcpy(mFontName, name);
|
||||
mpFont = pFont;
|
||||
}
|
||||
|
||||
ArcResourceAccessor::ArcResourceAccessor() : mArcBuf(NULL) {}
|
||||
|
||||
void dummyString() {
|
||||
OSReport("NW4HBM:Failed assertion std::strlen(name) < FONTNAMEBUF_MAX");
|
||||
}
|
||||
|
||||
bool ArcResourceAccessor::Attach(void* archiveStart, const char* resourceRootDirectory) {
|
||||
// clang-format off
|
||||
NW4HBM_ASSERT(220, ! IsAttached());
|
||||
NW4HBM_ASSERT_CHECK_NULL(221, archiveStart);
|
||||
NW4HBM_ASSERT_CHECK_NULL(222, resourceRootDirectory);
|
||||
// clang-format on
|
||||
|
||||
BOOL bSuccess = ARCInitHandle(archiveStart, &mArcHandle);
|
||||
|
||||
if (!bSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mArcBuf = archiveStart;
|
||||
|
||||
strncpy(mResRootDir, resourceRootDirectory, ARRAY_SIZE(mResRootDir) - 1);
|
||||
mResRootDir[ARRAY_SIZE(mResRootDir) - 1] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dummyString2() {
|
||||
OSReport("NW4HBM:Failed assertion IsAttached()");
|
||||
OSReport("NW4HBM:Pointer must not be NULL (pLink)");
|
||||
}
|
||||
|
||||
void* ArcResourceAccessor::GetResource(u32 resType, const char* name, u32* pSize) {
|
||||
return GetResourceSub(&mArcHandle, mResRootDir, resType, name, pSize);
|
||||
}
|
||||
|
||||
bool ArcResourceLink::Set(void* archiveStart, const char* resRootDirectory) {
|
||||
BOOL bSuccess = ARCInitHandle(archiveStart, &mArcHandle);
|
||||
|
||||
if (!bSuccess) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strncpy(mResRootDir, resRootDirectory, ARRAY_SIZE(mResRootDir) - 1);
|
||||
mResRootDir[ARRAY_SIZE(mResRootDir) - 1] = '\0';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ut::Font* ArcResourceAccessor::GetFont(const char* name) {
|
||||
return detail::FindFont(&mFontList, name);
|
||||
}
|
||||
|
||||
MultiArcResourceAccessor::MultiArcResourceAccessor() {}
|
||||
|
||||
MultiArcResourceAccessor::~MultiArcResourceAccessor() {
|
||||
DetachAll();
|
||||
}
|
||||
|
||||
void MultiArcResourceAccessor::Attach(ArcResourceLink* pLink) {
|
||||
mArcList.PushBack(pLink);
|
||||
}
|
||||
|
||||
void* MultiArcResourceAccessor::GetResource(u32 resType, const char* name, u32* pSize) {
|
||||
for (ArcResourceLinkList::Iterator it = mArcList.GetBeginIter();
|
||||
it != mArcList.GetEndIter(); it++)
|
||||
{
|
||||
ARCHandle* pArcHandle = it->GetArcHandle();
|
||||
if (void* resPtr =
|
||||
GetResourceSub(pArcHandle, it->GetResRootDir(), resType, name, pSize))
|
||||
{
|
||||
return resPtr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MultiArcResourceAccessor::RegistFont(FontRefLink* pLink) {
|
||||
mFontList.PushBack(pLink);
|
||||
}
|
||||
|
||||
ut::Font* MultiArcResourceAccessor::GetFont(const char* name) {
|
||||
return detail::FindFont(&mFontList, name);
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "bounding.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "drawInfo.h"
|
||||
#include "pane.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
NW4HBM_UT_GET_DERIVED_RUNTIME_TYPEINFO(Bounding, Pane);
|
||||
|
||||
Bounding::Bounding(const res::Bounding* pBlock, const ResBlockSet&) : Pane(pBlock) {}
|
||||
|
||||
Bounding::~Bounding() {}
|
||||
|
||||
void Bounding::DrawSelf(const DrawInfo& drawInfo) {
|
||||
if (drawInfo.IsDebugDrawMode()) {
|
||||
LoadMtx(drawInfo);
|
||||
detail::DrawLine(GetVtxPos(), mSize, ut::Color(0x00ff00ff));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,279 @@
|
||||
#include "common.h"
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
#include <cstring.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
namespace detail {
|
||||
|
||||
// sizeof(Pane::mName) == 16
|
||||
bool EqualsPaneName(const char* name1, const char* name2) {
|
||||
return std::strncmp(name1, name2, 16) == 0;
|
||||
}
|
||||
|
||||
// sizeof(Material::mName) == 20
|
||||
bool EqualsMaterialName(const char* name1, const char* name2) {
|
||||
return std::strncmp(name1, name2, 20) == 0;
|
||||
}
|
||||
|
||||
// U+FEFF * BYTE ORDER MARK
|
||||
bool TestFileHeader(const res::BinaryFileHeader& fileHeader) {
|
||||
return fileHeader.byteOrder == 0xFEFF && fileHeader.version == 8;
|
||||
}
|
||||
|
||||
bool TestFileHeader(const res::BinaryFileHeader& fileHeader, u32 testSig) {
|
||||
return static_cast<u32>(GetSignatureInt(fileHeader.signature)) == testSig &&
|
||||
TestFileHeader(fileHeader);
|
||||
}
|
||||
|
||||
TexCoordAry::TexCoordAry() : mCap(0), mNum(0), mpData(NULL) {}
|
||||
|
||||
void TexCoordAry::Free() {
|
||||
if (mpData) {
|
||||
Layout::FreeMemory(mpData);
|
||||
mpData = NULL;
|
||||
|
||||
mCap = 0;
|
||||
mNum = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TexCoordAry::Reserve(u8 num) {
|
||||
NW4HBM_ASSERT(93, num <= GX_MAX_TEXMAP);
|
||||
if (mCap < num) {
|
||||
Free();
|
||||
mpData = static_cast<TexCoords*>(Layout::AllocMemory(sizeof(*mpData) * num));
|
||||
|
||||
if (mpData) {
|
||||
mCap = num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TexCoordAry::SetSize(u8 num) {
|
||||
if (!mpData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (num > mCap) {
|
||||
return;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
static TexCoords texCoords =
|
||||
{
|
||||
math::VEC2(0.0f, 0.0f),
|
||||
math::VEC2(1.0f, 0.0f),
|
||||
math::VEC2(0.0f, 1.0f),
|
||||
math::VEC2(1.0f, 1.0f)
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
for (int j = mNum; j < num; j++) {
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mpData[j]); i++) {
|
||||
mpData[j][i] = texCoords[i];
|
||||
}
|
||||
}
|
||||
|
||||
mNum = num;
|
||||
}
|
||||
|
||||
void TexCoordAry::Copy(const void* pResTexCoord, u8 texCoordNum) {
|
||||
NW4HBM_ASSERT(161, texCoordNum <= mCap);
|
||||
mNum = ut::Max(mNum, texCoordNum);
|
||||
const TexCoords* src = static_cast<const TexCoords*>(pResTexCoord);
|
||||
|
||||
for (int j = 0; j < texCoordNum; j++) {
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mpData[j]); i++) {
|
||||
mpData[j][i] = src[j][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsModulateVertexColor(ut::Color* vtxColors, u8 glbAlpha) {
|
||||
if (glbAlpha != 0xff) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vtxColors) {
|
||||
if (vtxColors[0] != 0xffffffff || vtxColors[1] != 0xffffffff ||
|
||||
vtxColors[2] != 0xffffffff || vtxColors[3] != 0xffffffff)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ut::Color MultipleAlpha(const ut::Color col, u8 alpha) {
|
||||
ut::Color ret = col;
|
||||
|
||||
if (alpha != 0xff) {
|
||||
ret.a = col.a * alpha / 255;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MultipleAlpha(ut::Color* dst, const ut::Color* src, u8 alpha) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
dst[i] = MultipleAlpha(src[i], alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVertexFormat(bool bModulate, u8 texCoordNum) {
|
||||
GXClearVtxDesc();
|
||||
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
|
||||
if (bModulate) {
|
||||
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < texCoordNum; i++) {
|
||||
GXSetVtxDesc(static_cast<GXAttr>(GX_VA_TEX0 + i), GX_DIRECT);
|
||||
}
|
||||
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_F32, 0);
|
||||
|
||||
if (bModulate) {
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < texCoordNum; i++) {
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, static_cast<GXAttr>(GX_VA_TEX0 + i), GX_CLR_RGBA,
|
||||
GX_F32, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void __deadstrip1();
|
||||
static void __deadstrip1() {
|
||||
// Force instantiation of GXEnd here on debug build
|
||||
GXEnd();
|
||||
}
|
||||
|
||||
void DrawQuad(const math::VEC2& basePt, const Size& size, u8 texCoordNum,
|
||||
const TexCoords* texCoords, const ut::Color* vtxColors) {
|
||||
// start at top left, go clockwise
|
||||
|
||||
// clang-format off
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
|
||||
GXPosition2f32(basePt.x, basePt.y);
|
||||
if (vtxColors)
|
||||
GXColor1u32(vtxColors[0]);
|
||||
for (int i = 0; i < texCoordNum; i++)
|
||||
GXTexCoord2f32(texCoords[i][0].x, texCoords[i][0].y);
|
||||
|
||||
GXPosition2f32(basePt.x + size.width, basePt.y);
|
||||
if (vtxColors)
|
||||
GXColor1u32(vtxColors[1]);
|
||||
for (int i = 0; i < texCoordNum; i++)
|
||||
GXTexCoord2f32(texCoords[i][1].x, texCoords[i][1].y);
|
||||
|
||||
GXPosition2f32(basePt.x + size.width, basePt.y + size.height);
|
||||
if (vtxColors)
|
||||
GXColor1u32(vtxColors[3]);
|
||||
for (int i = 0; i < texCoordNum; i++)
|
||||
GXTexCoord2f32(texCoords[i][3].x, texCoords[i][3].y);
|
||||
|
||||
GXPosition2f32(basePt.x, basePt.y + size.height);
|
||||
if (vtxColors)
|
||||
GXColor1u32(vtxColors[2]);
|
||||
for (int i = 0; i < texCoordNum; i++)
|
||||
GXTexCoord2f32(texCoords[i][2].x, texCoords[i][2].y);
|
||||
|
||||
GXEnd();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void DrawQuad(const math::VEC2& basePt, const Size& size, u8 texCoordNum,
|
||||
const TexCoords* texCoords, const ut::Color* vtxColors, u8 alpha) {
|
||||
ut::Color wkVtxColors[4];
|
||||
|
||||
if (vtxColors) {
|
||||
MultipleAlpha(wkVtxColors, vtxColors, alpha);
|
||||
}
|
||||
|
||||
DrawQuad(basePt, size, texCoordNum, texCoords, vtxColors ? wkVtxColors : NULL);
|
||||
}
|
||||
|
||||
void DrawLine(const math::VEC2& pos, const Size& size, ut::Color color) {
|
||||
GXClearVtxDesc();
|
||||
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_F32, 0);
|
||||
|
||||
GXSetNumChans(1);
|
||||
GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE,
|
||||
GX_AF_NONE);
|
||||
|
||||
GXSetChanMatColor(GX_COLOR0A0, color);
|
||||
GXSetNumTexGens(0);
|
||||
GXSetNumTevStages(1);
|
||||
GXSetNumIndStages(0);
|
||||
|
||||
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
||||
GXSetTevOp(GX_TEVSTAGE0, GX_BLEND);
|
||||
GXSetTevDirect(GX_TEVSTAGE0);
|
||||
|
||||
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
||||
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE,
|
||||
GX_CH_ALPHA);
|
||||
|
||||
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
||||
GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET);
|
||||
|
||||
GXSetLineWidth(6, GX_TO_ZERO);
|
||||
|
||||
// start at top left, go clockwise
|
||||
|
||||
// clang-format off
|
||||
GXBegin(GX_LINESTRIP, GX_VTXFMT0, 5);
|
||||
GXPosition2f32(pos.x , pos.y );
|
||||
GXPosition2f32(pos.x + size.width, pos.y );
|
||||
GXPosition2f32(pos.x + size.width, pos.y + size.height);
|
||||
GXPosition2f32(pos.x , pos.y + size.height);
|
||||
GXPosition2f32(pos.x , pos.y );
|
||||
GXEnd();
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void InitGXTexObjFromTPL(GXTexObj* to, TPLPalette* pal, u32 id) {
|
||||
// Is there some sort of macro for this
|
||||
if (pal->descriptorArray < (TPLDescriptor*)0x80000000) { // ?
|
||||
TPLBind(pal);
|
||||
}
|
||||
|
||||
TPLDescriptor* tdp = TPLGet(pal, id);
|
||||
|
||||
GXBool mipMap = tdp->textureHeader->minLOD != tdp->textureHeader->maxLOD ? GX_TRUE : GX_FALSE;
|
||||
|
||||
if (tdp->CLUTHeader) {
|
||||
// NOTE: explicit recast of mipMap necessary for debug
|
||||
GXInitTexObjCI(
|
||||
to, tdp->textureHeader->data, tdp->textureHeader->width, tdp->textureHeader->height,
|
||||
static_cast<GXCITexFmt>(tdp->textureHeader->format), tdp->textureHeader->wrapS,
|
||||
tdp->textureHeader->wrapT, static_cast<GXBool>(mipMap), 0);
|
||||
|
||||
GXInitTexObjUserData(to, tdp->CLUTHeader);
|
||||
} else {
|
||||
// NOTE: explicit recast of mipMap necessary for debug
|
||||
GXInitTexObj(
|
||||
to, tdp->textureHeader->data, tdp->textureHeader->width, tdp->textureHeader->height,
|
||||
static_cast<GXTexFmt>(tdp->textureHeader->format), tdp->textureHeader->wrapS,
|
||||
tdp->textureHeader->wrapT, static_cast<GXBool>(mipMap));
|
||||
}
|
||||
|
||||
GXInitTexObjLOD(to, tdp->textureHeader->minFilter, tdp->textureHeader->magFilter,
|
||||
tdp->textureHeader->minLOD, tdp->textureHeader->maxLOD,
|
||||
tdp->textureHeader->LODBias, false, tdp->textureHeader->edgeLODEnable,
|
||||
GX_ANISO_1);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "drawInfo.h"
|
||||
|
||||
#include <cstring.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
DrawInfo::DrawInfo() : mLocationAdjustScale(1.0f, 1.0f), mGlobalAlpha(1.0f) {
|
||||
std::memset(&mFlag, 0, sizeof(mFlag));
|
||||
|
||||
math::MTX34Identity(&mViewMtx);
|
||||
}
|
||||
|
||||
DrawInfo::~DrawInfo() {}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "group.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "layout.h"
|
||||
|
||||
#include <cstring.h>
|
||||
#include <new.h>
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
Group::Group() {}
|
||||
|
||||
Group::Group(const res::Group* pResGroup, Pane* pRootPane) {
|
||||
Init();
|
||||
std::memcpy(mName, pResGroup->name, sizeof(mName));
|
||||
|
||||
const char* paneName = detail::ConvertOffsToPtr<char>(pResGroup, sizeof(*pResGroup));
|
||||
|
||||
for (int i = 0; i < pResGroup->paneNum; i++) {
|
||||
Pane* pFindPane =
|
||||
pRootPane->FindPaneByName(paneName + (int)sizeof(pResGroup)->name * i, true);
|
||||
|
||||
if (pFindPane) {
|
||||
AppendPane(pFindPane);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Group::Init() {
|
||||
mbUserAllocated = false;
|
||||
}
|
||||
|
||||
Group::~Group() {
|
||||
for (PaneLinkList::Iterator it = mPaneLinkList.GetBeginIter();
|
||||
it != mPaneLinkList.GetEndIter();)
|
||||
{
|
||||
PaneLinkList::Iterator currIt = it++;
|
||||
|
||||
mPaneLinkList.Erase(currIt);
|
||||
Layout::FreeMemory(&*currIt);
|
||||
}
|
||||
}
|
||||
|
||||
void Group::AppendPane(Pane* pPane) {
|
||||
if (void* pMem = Layout::AllocMemory(sizeof(detail::PaneLink))) {
|
||||
detail::PaneLink* pPaneLink = new (pMem) detail::PaneLink();
|
||||
|
||||
pPaneLink->mTarget = pPane;
|
||||
mPaneLinkList.PushBack(pPaneLink);
|
||||
}
|
||||
}
|
||||
|
||||
GroupContainer::~GroupContainer() {
|
||||
for (GroupList::Iterator it = mGroupList.GetBeginIter(); it != mGroupList.GetEndIter();)
|
||||
{
|
||||
GroupList::Iterator currIt = it++;
|
||||
|
||||
mGroupList.Erase(currIt);
|
||||
|
||||
if (!currIt->IsUserAllocated()) {
|
||||
currIt->~Group();
|
||||
Layout::FreeMemory(&*currIt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupContainer::AppendGroup(Group* pGroup) {
|
||||
mGroupList.PushBack(pGroup);
|
||||
}
|
||||
|
||||
Group* GroupContainer::FindGroupByName(const char* findName) {
|
||||
for (GroupList::Iterator it = mGroupList.GetBeginIter(); it != mGroupList.GetEndIter();
|
||||
it++)
|
||||
{
|
||||
if (detail::EqualsPaneName(it->GetName(), findName)) {
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,368 @@
|
||||
#include "layout.h"
|
||||
|
||||
#include "bounding.h"
|
||||
#include "picture.h"
|
||||
#include "textBox.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <new.h>
|
||||
|
||||
#define CONVERT_OFFSET_TO_PTR(type_, ptr_, offset_) \
|
||||
reinterpret_cast<type_*>(reinterpret_cast<u32>(ptr_) + offset_)
|
||||
|
||||
namespace {
|
||||
// pretend this is nw4hbm::lyt
|
||||
using namespace nw4hbm;
|
||||
using namespace nw4hbm::lyt;
|
||||
|
||||
void SetTagProcessorImpl(Pane* pPane, ut::TagProcessorBase<wchar_t>* pTagProcesssor);
|
||||
|
||||
// wait until these guys hear about c++11
|
||||
template <class T>
|
||||
T* CreateObject() {
|
||||
void* pMem = Layout::AllocMemory(sizeof(T));
|
||||
|
||||
if (pMem) {
|
||||
return new (pMem) T();
|
||||
} else {
|
||||
NW4R_DB_WARNING(47, false, "can't alloc memory.");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, typename Param1>
|
||||
T* CreateObject(Param1 p1) {
|
||||
void* pMem = Layout::AllocMemory(sizeof(T));
|
||||
|
||||
if (pMem) {
|
||||
return new (pMem) T(p1);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, typename Param1, typename Param2>
|
||||
T* CreateObject(Param1 p1, Param2 p2) {
|
||||
void* pMem = Layout::AllocMemory(sizeof(T));
|
||||
|
||||
if (pMem) {
|
||||
return new (pMem) T(p1, p2);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
MEMAllocator* Layout::mspAllocator;
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace {
|
||||
|
||||
void SetTagProcessorImpl(Pane* pPane, ut::TagProcessorBase<wchar_t>* pTagProcessor) {
|
||||
if (TextBox* pTextBox = ut::DynamicCast<TextBox*>(pPane)) {
|
||||
pTextBox->SetTagProcessor(pTagProcessor);
|
||||
}
|
||||
|
||||
for (PaneList::Iterator it = pPane->GetChildList().GetBeginIter();
|
||||
it != pPane->GetChildList().GetEndIter(); ++it)
|
||||
{
|
||||
SetTagProcessorImpl(&(*it), pTagProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
Layout::Layout()
|
||||
: mpRootPane(NULL), mpGroupContainer(NULL), mLayoutSize(0.0f, 0.0f), mOriginType(0) {}
|
||||
|
||||
Layout::~Layout() {
|
||||
if (mpGroupContainer) {
|
||||
mpGroupContainer->~GroupContainer();
|
||||
FreeMemory(mpGroupContainer);
|
||||
}
|
||||
|
||||
if (mpRootPane && !mpRootPane->IsUserAllocated()) {
|
||||
mpRootPane->~Pane();
|
||||
FreeMemory(mpRootPane);
|
||||
}
|
||||
|
||||
for (AnimTransformList::Iterator it = mAnimTransList.GetBeginIter();
|
||||
it != mAnimTransList.GetEndIter();)
|
||||
{
|
||||
AnimTransformList::Iterator currIt = it++;
|
||||
|
||||
mAnimTransList.Erase(currIt);
|
||||
currIt->~AnimTransform();
|
||||
FreeMemory(&*currIt);
|
||||
}
|
||||
}
|
||||
|
||||
bool Layout::Build(const void* lytResBuf, ResourceAccessor* pResAcsr) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(171, mspAllocator);
|
||||
NW4HBM_ASSERT_CHECK_NULL(172, lytResBuf);
|
||||
|
||||
const res::BinaryFileHeader* fileHead =
|
||||
static_cast<const res::BinaryFileHeader*>(lytResBuf);
|
||||
|
||||
if (!detail::TestFileHeader(*fileHead, res::FILE_HEADER_SIGNATURE_LAYOUT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileHead->version != 8) {
|
||||
NW4R_DB_ASSERTMSG(187, false, "Version check faild ('%d.%d' must be '%d.%d').",
|
||||
(fileHead->version >> 8) & 0xFF, fileHead->version & 0xFF, 0, 8);
|
||||
}
|
||||
|
||||
ResBlockSet resBlockSet = {};
|
||||
resBlockSet.pResAccessor = pResAcsr;
|
||||
|
||||
Pane* pParentPane = NULL;
|
||||
Pane* pLastPane = NULL;
|
||||
bool bReadRootGroup = false;
|
||||
int groupNestLevel = 0;
|
||||
void* dataPtr = CONVERT_OFFSET_TO_PTR(void, lytResBuf, fileHead->headerSize);
|
||||
|
||||
for (int i = 0; i < fileHead->dataBlocks; i++) {
|
||||
res::DataBlockHeader* pDataBlockHead = static_cast<res::DataBlockHeader*>(dataPtr);
|
||||
|
||||
switch (detail::GetSignatureInt(pDataBlockHead->kind)) {
|
||||
case 'lyt1': {
|
||||
res::Layout* pResLyt = static_cast<res::Layout*>(dataPtr);
|
||||
|
||||
mOriginType = pResLyt->originType != 0; // ?
|
||||
mLayoutSize = pResLyt->layoutSize;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'txl1':
|
||||
resBlockSet.pTextureList = static_cast<res::TextureList*>(dataPtr);
|
||||
break;
|
||||
|
||||
case 'fnl1':
|
||||
resBlockSet.pFontList = static_cast<res::FontList*>(dataPtr);
|
||||
break;
|
||||
|
||||
case 'mat1':
|
||||
resBlockSet.pMaterialList = static_cast<res::MaterialList*>(dataPtr);
|
||||
break;
|
||||
|
||||
case 'pan1':
|
||||
case 'bnd1':
|
||||
case 'pic1':
|
||||
case 'txt1':
|
||||
case 'wnd1':
|
||||
if (Pane* pPane = BuildPaneObj(detail::GetSignatureInt(pDataBlockHead->kind),
|
||||
dataPtr, resBlockSet))
|
||||
{
|
||||
if (!mpRootPane) {
|
||||
mpRootPane = pPane;
|
||||
}
|
||||
|
||||
if (pParentPane) {
|
||||
pParentPane->AppendChild(pPane);
|
||||
}
|
||||
|
||||
pLastPane = pPane;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'pas1': // pane start?
|
||||
NW4HBM_ASSERT_CHECK_NULL(249, pLastPane);
|
||||
pParentPane = pLastPane;
|
||||
break;
|
||||
|
||||
case 'pae1': // pane end?
|
||||
pLastPane = pParentPane;
|
||||
pParentPane = pLastPane->GetParent();
|
||||
break;
|
||||
|
||||
case 'grp1':
|
||||
if (!bReadRootGroup) {
|
||||
bReadRootGroup = true;
|
||||
mpGroupContainer = CreateObject<GroupContainer>();
|
||||
} else if (mpGroupContainer && groupNestLevel == 1) {
|
||||
if (Group* pGroup = CreateObject<Group>(
|
||||
reinterpret_cast<const res::Group*>(pDataBlockHead), mpRootPane))
|
||||
{
|
||||
mpGroupContainer->AppendGroup(pGroup);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'grs1': // group start?
|
||||
groupNestLevel++;
|
||||
break;
|
||||
|
||||
case 'gre1': // group end?
|
||||
groupNestLevel--;
|
||||
break;
|
||||
}
|
||||
|
||||
dataPtr = CONVERT_OFFSET_TO_PTR(void, dataPtr, pDataBlockHead->size);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AnimTransform* Layout::CreateAnimTransform(const void* anmResBuf,
|
||||
ResourceAccessor* pResAcsr) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(295, mspAllocator);
|
||||
NW4HBM_ASSERT_CHECK_NULL(296, anmResBuf);
|
||||
|
||||
const res::BinaryFileHeader* pFileHead =
|
||||
static_cast<const res::BinaryFileHeader*>(anmResBuf);
|
||||
|
||||
if (!detail::TestFileHeader(*pFileHead)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pFileHead->version != 8) {
|
||||
NW4R_DB_ASSERTMSG(311, false, "Version check faild ('%d.%d' must be '%d.%d').",
|
||||
(pFileHead->version >> 8) & 0xFF, pFileHead->version & 0xFF, 0,
|
||||
8);
|
||||
}
|
||||
|
||||
const res::AnimationBlock* pInfoBlock = NULL;
|
||||
const res::DataBlockHeader* pDataBlockHead =
|
||||
detail::ConvertOffsToPtr<res::DataBlockHeader>(pFileHead, pFileHead->headerSize);
|
||||
|
||||
AnimTransform* ret = NULL;
|
||||
|
||||
for (int i = 0; i < pFileHead->dataBlocks; i++) {
|
||||
switch (detail::GetSignatureInt(pDataBlockHead->kind)) {
|
||||
case 'pai1': // painting? idk
|
||||
NW4HBM_ASSERT(321, ret == 0);
|
||||
|
||||
switch (detail::GetSignatureInt(pFileHead->signature)) {
|
||||
case 'RLAN':
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_PAIN_SRT:
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_VISIBILITY:
|
||||
case res::AnimationInfo::ANIM_INFO_PANE_VERTEX_COLOR:
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_COLOR:
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_TEXTURE_SRT:
|
||||
case res::AnimationInfo::ANIM_INFO_MATERIAL_TEXTURE_PATTERN:
|
||||
if (AnimTransformBasic* pAnimTrans = CreateObject<AnimTransformBasic>()) {
|
||||
pInfoBlock =
|
||||
reinterpret_cast<const res::AnimationBlock*>(pDataBlockHead);
|
||||
|
||||
pAnimTrans->SetResource(pInfoBlock, pResAcsr);
|
||||
ret = pAnimTrans;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
mAnimTransList.PushBack(ret);
|
||||
}
|
||||
}
|
||||
|
||||
pDataBlockHead = detail::ConvertOffsToPtr<res::DataBlockHeader>(
|
||||
pDataBlockHead, pDataBlockHead->size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Layout::BindAnimation(AnimTransform* pAnimTrans) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->BindAnimation(pAnimTrans, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::UnbindAnimation(AnimTransform* pAnimTrans) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->UnbindAnimation(pAnimTrans, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::UnbindAllAnimation() {
|
||||
UnbindAnimation(NULL);
|
||||
}
|
||||
|
||||
void Layout::SetAnimationEnable(AnimTransform* pAnimTrans, bool bEnable) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->SetAnimationEnable(pAnimTrans, bEnable, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::CalculateMtx(const DrawInfo& drawInfo) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->CalculateMtx(drawInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::Draw(const DrawInfo& drawInfo) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->Draw(drawInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::Animate(u32 option) {
|
||||
if (mpRootPane) {
|
||||
mpRootPane->Animate(option);
|
||||
}
|
||||
}
|
||||
|
||||
const ut::Rect Layout::GetLayoutRect() const {
|
||||
if (mOriginType == 1) {
|
||||
return ut::Rect(-mLayoutSize.width / 2.0f, mLayoutSize.height / 2.0f,
|
||||
mLayoutSize.width / 2.0f, -mLayoutSize.height / 2.0f);
|
||||
} else {
|
||||
return ut::Rect(0.0f, 0.0f, mLayoutSize.width, mLayoutSize.height);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::SetTagProcessor(ut::TagProcessorBase<wchar_t>* pTagProcessor) {
|
||||
SetTagProcessorImpl(mpRootPane, pTagProcessor);
|
||||
}
|
||||
|
||||
Pane* Layout::BuildPaneObj(s32 kind, const void* dataPtr, const ResBlockSet& resBlockSet) {
|
||||
switch (kind) {
|
||||
case res::OBJECT_SIGNATURE_PANE: {
|
||||
const res::Pane* pResPane = static_cast<const res::Pane*>(dataPtr);
|
||||
|
||||
return CreateObject<Pane>(pResPane);
|
||||
}
|
||||
|
||||
case res::OBJECT_SIGNATURE_PICTURE: {
|
||||
const res::Picture* pResPic = static_cast<const res::Picture*>(dataPtr);
|
||||
|
||||
return CreateObject<Picture>(pResPic, resBlockSet);
|
||||
}
|
||||
|
||||
case res::OBJECT_SIGNATURE_TEXT_BOX: {
|
||||
// block?
|
||||
const res::TextBox* pBlock = static_cast<const res::TextBox*>(dataPtr);
|
||||
|
||||
return CreateObject<TextBox>(pBlock, resBlockSet);
|
||||
}
|
||||
|
||||
case res::OBJECT_SIGNATURE_WINDOW: {
|
||||
// block?
|
||||
const res::Window* pBlock = static_cast<const res::Window*>(dataPtr);
|
||||
|
||||
return CreateObject<Window>(pBlock, resBlockSet);
|
||||
}
|
||||
|
||||
case res::OBJECT_SIGNATURE_BOUNDING: {
|
||||
const res::Bounding* pResBounding = static_cast<const res::Bounding*>(dataPtr);
|
||||
|
||||
return CreateObject<Bounding>(pResBounding, resBlockSet);
|
||||
}
|
||||
|
||||
default:
|
||||
NW4R_DB_ASSERTMSG(503, false, "unknown data type");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,495 @@
|
||||
#include "pane.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "layout.h"
|
||||
|
||||
#include <cstring.h>
|
||||
|
||||
namespace {
|
||||
// pretend this is nw4hbm::lyt
|
||||
using namespace nw4hbm;
|
||||
using namespace nw4hbm::lyt;
|
||||
|
||||
void ReverseYAxis(math::MTX34* pMtx);
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
NW4HBM_UT_GET_RUNTIME_TYPEINFO(Pane);
|
||||
}
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace {
|
||||
|
||||
void ReverseYAxis(math::MTX34* pMtx) {
|
||||
pMtx->m[0][1] = -pMtx->m[0][1];
|
||||
pMtx->m[1][1] = -pMtx->m[1][1];
|
||||
pMtx->m[2][1] = -pMtx->m[2][1];
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
Pane::Pane() {
|
||||
Init();
|
||||
|
||||
mBasePosition = 4;
|
||||
memset(mName, 0, sizeof(mName));
|
||||
memset(mUserData, 0, sizeof(mUserData));
|
||||
|
||||
mTranslate = math::VEC3(0.0f, 0.0f, 0.0f);
|
||||
mRotate = math::VEC3(0.0f, 0.0f, 0.0f);
|
||||
mScale = math::VEC2(1.0f, 1.0f);
|
||||
mSize = Size(0.0f, 0.0f);
|
||||
mAlpha = ut::Color(255);
|
||||
mGlbAlpha = mAlpha;
|
||||
mFlag = 0;
|
||||
|
||||
SetVisible(true);
|
||||
}
|
||||
|
||||
Pane::Pane(const res::Pane* pBlock) {
|
||||
Init();
|
||||
|
||||
mBasePosition = pBlock->basePosition;
|
||||
SetName(pBlock->name);
|
||||
SetUserData(pBlock->userData);
|
||||
|
||||
mTranslate = pBlock->translate;
|
||||
mRotate = pBlock->rotate;
|
||||
mScale = pBlock->scale;
|
||||
mSize = pBlock->size;
|
||||
mAlpha = pBlock->alpha;
|
||||
mGlbAlpha = mAlpha;
|
||||
mFlag = pBlock->flag;
|
||||
}
|
||||
|
||||
void Pane::Init() {
|
||||
mpParent = NULL;
|
||||
mpMaterial = NULL;
|
||||
mbUserAllocated = false;
|
||||
}
|
||||
|
||||
Pane::~Pane() {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter(); it != mChildList.GetEndIter();)
|
||||
{
|
||||
PaneList::Iterator currIt = it++;
|
||||
mChildList.Erase(currIt);
|
||||
|
||||
if (!currIt->IsUserAllocated()) {
|
||||
currIt->~Pane();
|
||||
Layout::FreeMemory(&*currIt);
|
||||
}
|
||||
}
|
||||
|
||||
UnbindAnimationSelf(NULL);
|
||||
|
||||
if (mpMaterial && !mpMaterial->IsUserAllocated()) {
|
||||
mpMaterial->~Material();
|
||||
Layout::FreeMemory(mpMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::SetName(const char* name) {
|
||||
std::strncpy(mName, name, sizeof(mName));
|
||||
}
|
||||
|
||||
void Pane::SetUserData(const char* userData) {
|
||||
std::strncpy(mUserData, userData, sizeof(mUserData));
|
||||
}
|
||||
|
||||
void Pane::AppendChild(Pane* pChild) {
|
||||
InsertChild(mChildList.GetEndIter(), pChild);
|
||||
}
|
||||
|
||||
// it requires a type that wasn't used before to generate the string and avoid having it
|
||||
// stripped
|
||||
/* typedef nw4hbm::ut::LinkList<void**, 0> DummyLinkList;
|
||||
DECOMP_FORCE_CLASS_METHOD(DummyLinkList, GetNodeFromPointer(NULL));
|
||||
typedef nw4hbm::ut::LinkList<void***, 0> DummyLinkList2;
|
||||
DECOMP_FORCE_CLASS_METHOD(DummyLinkList2, GetNodeFromPointer(NULL)); */
|
||||
|
||||
void Pane::InsertChild(PaneList::Iterator next, Pane* pChild) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(253, pChild);
|
||||
NW4HBM_ASSERT(254, pChild->mpParent == 0);
|
||||
mChildList.Insert(next, pChild);
|
||||
pChild->mpParent = this;
|
||||
}
|
||||
|
||||
void dummyString() {
|
||||
OSReport("NW4HBM:Pointer must not be NULL (pNext)");
|
||||
OSReport("NW4HBM:Failed assertion pNext->mpParent == this");
|
||||
OSReport("NW4HBM:Failed assertion pChild->mpParent == this");
|
||||
}
|
||||
|
||||
#pragma ppc_iro_level 0
|
||||
|
||||
const ut::Rect Pane::GetPaneRect(const DrawInfo& drawInfo) const {
|
||||
ut::Rect ret;
|
||||
math::VEC2 basePt = GetVtxPos();
|
||||
|
||||
ret.left = basePt.x;
|
||||
ret.top = basePt.y;
|
||||
ret.right = ret.left + mSize.width;
|
||||
ret.bottom = ret.top + mSize.height;
|
||||
|
||||
if (drawInfo.IsYAxisUp()) {
|
||||
ret.top = -ret.top;
|
||||
ret.bottom = -ret.bottom;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma ppc_iro_level reset
|
||||
|
||||
ut::Color Pane::GetVtxColor(u32) const {
|
||||
return ut::Color(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void Pane::SetVtxColor(u32, ut::Color) { /* ... */ }
|
||||
|
||||
u8 Pane::GetColorElement(u32 idx) const {
|
||||
NW4HBM_ASSERT(319, idx < ANIMTARGET_PANE_COLOR_MAX);
|
||||
switch (idx) {
|
||||
case 16:
|
||||
return mAlpha;
|
||||
|
||||
default:
|
||||
return GetVtxColorElement(idx);
|
||||
}
|
||||
}
|
||||
|
||||
// it requires a type that wasn't used before to generate the string and avoid having it
|
||||
// stripped
|
||||
/* typedef nw4hbm::ut::LinkList<void****, 0> DummyLinkList3;
|
||||
DECOMP_FORCE_CLASS_METHOD(DummyLinkList3, GetNodeFromPointer(NULL)); */
|
||||
|
||||
void Pane::SetColorElement(u32 idx, u8 value) {
|
||||
NW4HBM_ASSERT(334, idx < ANIMTARGET_PANE_COLOR_MAX);
|
||||
switch (idx) {
|
||||
case 16:
|
||||
mAlpha = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
SetVtxColorElement(idx, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u8 Pane::GetVtxColorElement(u32) const {
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void Pane::SetVtxColorElement(u32, u8) { /* ... */ }
|
||||
|
||||
Pane* Pane::FindPaneByName(const char* findName, bool bRecursive) {
|
||||
if (detail::EqualsPaneName(mName, findName)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (bRecursive) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
if (Pane* pane = it->FindPaneByName(findName, true)) {
|
||||
return pane;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Material* Pane::FindMaterialByName(const char* findName, bool bRecursive) {
|
||||
if (mpMaterial && detail::EqualsMaterialName(mpMaterial->GetName(), findName)) {
|
||||
return mpMaterial;
|
||||
}
|
||||
|
||||
if (bRecursive) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
if (Material* pMaterial = it->FindMaterialByName(findName, true)) {
|
||||
return pMaterial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Pane::CalculateMtx(const DrawInfo& drawInfo) {
|
||||
// this doesnt even get referenced, an entirely new constant is generated lol
|
||||
const f32 invAlpha = 1.0f / 255.0f;
|
||||
|
||||
if (!detail::TestBit(mFlag, 0) && !drawInfo.IsInvisiblePaneCalculateMtx()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
math::MTX34 mtx1;
|
||||
math::MTX34 mtx2;
|
||||
math::MTX34 rotateMtx;
|
||||
|
||||
{
|
||||
math::VEC2 scale(mScale);
|
||||
|
||||
if (drawInfo.IsLocationAdjust() && detail::TestBit(mFlag, 2)) {
|
||||
scale.x *= drawInfo.GetLocationAdjustScale().x;
|
||||
scale.y *= drawInfo.GetLocationAdjustScale().y;
|
||||
}
|
||||
|
||||
PSMTXScale(mtx2, scale.x, scale.y, 1.0f);
|
||||
}
|
||||
|
||||
PSMTXRotRad(rotateMtx, 'x', DEG_TO_RAD(mRotate.x));
|
||||
PSMTXConcat(rotateMtx, mtx2, mtx1);
|
||||
|
||||
PSMTXRotRad(rotateMtx, 'y', DEG_TO_RAD(mRotate.y));
|
||||
PSMTXConcat(rotateMtx, mtx1, mtx2);
|
||||
|
||||
PSMTXRotRad(rotateMtx, 'z', DEG_TO_RAD(mRotate.z));
|
||||
PSMTXConcat(rotateMtx, mtx2, mtx1);
|
||||
|
||||
PSMTXTransApply(mtx1, mMtx, mTranslate.x, mTranslate.y, mTranslate.z);
|
||||
}
|
||||
|
||||
if (mpParent) {
|
||||
math::MTX34Mult(&mGlbMtx, &mpParent->mGlbMtx, &mMtx);
|
||||
} else if (drawInfo.IsMultipleViewMtxOnDraw()) {
|
||||
mGlbMtx = mMtx;
|
||||
} else {
|
||||
math::MTX34Mult(&mGlbMtx, &drawInfo.GetViewMtx(), &mMtx);
|
||||
}
|
||||
|
||||
if (drawInfo.IsInfluencedAlpha() && mpParent) {
|
||||
mGlbAlpha = mAlpha * drawInfo.GetGlobalAlpha();
|
||||
} else {
|
||||
mGlbAlpha = mAlpha;
|
||||
}
|
||||
|
||||
// cr = const ref?
|
||||
f32 crGlobalAlpha = drawInfo.GetGlobalAlpha();
|
||||
bool bCrInfluenced = drawInfo.IsInfluencedAlpha();
|
||||
|
||||
bool bModDrawInfo = detail::TestBit(mFlag, 1) && mAlpha != 0xff;
|
||||
|
||||
if (bModDrawInfo) {
|
||||
// mt = mutable, probably
|
||||
DrawInfo& mtDrawInfo = const_cast<DrawInfo&>(drawInfo);
|
||||
|
||||
mtDrawInfo.SetGlobalAlpha(crGlobalAlpha * mAlpha * invAlpha);
|
||||
mtDrawInfo.SetInfluencedAlpha(true);
|
||||
}
|
||||
|
||||
CalculateMtxChild(drawInfo);
|
||||
|
||||
// restore changed values if applicable
|
||||
if (bModDrawInfo) {
|
||||
DrawInfo& mtDrawInfo = const_cast<DrawInfo&>(drawInfo);
|
||||
|
||||
mtDrawInfo.SetGlobalAlpha(crGlobalAlpha);
|
||||
mtDrawInfo.SetInfluencedAlpha(bCrInfluenced);
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::CalculateMtxChild(const DrawInfo& drawInfo) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter(); it != mChildList.GetEndIter();
|
||||
it++)
|
||||
{
|
||||
it->CalculateMtx(drawInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::Draw(const DrawInfo& drawInfo) {
|
||||
if (detail::TestBit(mFlag, 0)) {
|
||||
DrawSelf(drawInfo);
|
||||
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
it->Draw(drawInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::DrawSelf(const DrawInfo& drawInfo) {
|
||||
if (mpParent && drawInfo.IsDebugDrawMode()) {
|
||||
LoadMtx(drawInfo);
|
||||
detail::DrawLine(GetVtxPos(), mSize, 0x00ff00ff); // green
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::Animate(u32 option) {
|
||||
AnimateSelf(option);
|
||||
|
||||
if (detail::TestBit(mFlag, 0) || !(option & 1)) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
it->Animate(option);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::AnimateSelf(u32 option) {
|
||||
for (AnimationLinkList::Iterator it = mAnimList.GetBeginIter();
|
||||
it != mAnimList.GetEndIter(); it++)
|
||||
{
|
||||
if (it->IsEnable()) {
|
||||
AnimTransform* animTrans = it->GetAnimTransform();
|
||||
|
||||
animTrans->Animate(it->GetIndex(), this);
|
||||
}
|
||||
}
|
||||
|
||||
if ((detail::TestBit(mFlag, 0) || !(option & 1)) && mpMaterial) {
|
||||
mpMaterial->Animate();
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::BindAnimation(AnimTransform* pAnimTrans, bool bRecursive) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(596, pAnimTrans);
|
||||
pAnimTrans->Bind(this, bRecursive);
|
||||
}
|
||||
|
||||
void Pane::UnbindAnimation(AnimTransform* pAnimTrans, bool bRecursive) {
|
||||
UnbindAnimationSelf(pAnimTrans);
|
||||
|
||||
if (bRecursive) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
it->UnbindAnimation(pAnimTrans, bRecursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::UnbindAllAnimation(bool bRecursive) {
|
||||
UnbindAnimation(NULL, bRecursive);
|
||||
}
|
||||
|
||||
void Pane::UnbindAnimationSelf(AnimTransform* pAnimTrans) {
|
||||
if (mpMaterial) {
|
||||
mpMaterial->UnbindAnimation(pAnimTrans);
|
||||
}
|
||||
|
||||
for (AnimationLinkList::Iterator it = mAnimList.GetBeginIter();
|
||||
it != mAnimList.GetEndIter();)
|
||||
{
|
||||
AnimationLinkList::Iterator currIt = it++;
|
||||
|
||||
if (pAnimTrans == NULL || currIt->GetAnimTransform() == pAnimTrans) {
|
||||
mAnimList.Erase(currIt);
|
||||
currIt->Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::AddAnimationLink(AnimationLink* pAnimationLink) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(649, pAnimationLink);
|
||||
mAnimList.PushBack(pAnimationLink);
|
||||
}
|
||||
|
||||
AnimationLink* Pane::FindAnimationLink(AnimTransform* pAnimTrans) {
|
||||
if (AnimationLink* ret = detail::FindAnimationLink(&mAnimList, pAnimTrans)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mpMaterial) {
|
||||
if (AnimationLink* ret = mpMaterial->FindAnimationLink(pAnimTrans)) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Pane::SetAnimationEnable(AnimTransform* pAnimTrans, bool bEnable, bool bRecursive) {
|
||||
if (AnimationLink* pAnimLink = detail::FindAnimationLink(&mAnimList, pAnimTrans)) {
|
||||
pAnimLink->SetEnable(bEnable);
|
||||
}
|
||||
|
||||
if (mpMaterial) {
|
||||
mpMaterial->SetAnimationEnable(pAnimTrans, bEnable);
|
||||
}
|
||||
|
||||
if (bRecursive) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
it->SetAnimationEnable(pAnimTrans, bEnable, bRecursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Pane::LoadMtx(const DrawInfo& drawInfo) {
|
||||
math::MTX34 mtx;
|
||||
MtxPtr mtxPtr = NULL;
|
||||
|
||||
if (drawInfo.IsMultipleViewMtxOnDraw()) {
|
||||
math::MTX34Mult(&mtx, &drawInfo.GetViewMtx(), &mGlbMtx);
|
||||
|
||||
if (drawInfo.IsYAxisUp()) {
|
||||
ReverseYAxis(&mtx);
|
||||
}
|
||||
|
||||
mtxPtr = mtx;
|
||||
} else if (drawInfo.IsYAxisUp()) {
|
||||
math::MTX34Copy(&mtx, &mGlbMtx);
|
||||
ReverseYAxis(&mtx);
|
||||
mtxPtr = mtx;
|
||||
} else {
|
||||
mtxPtr = mGlbMtx;
|
||||
}
|
||||
|
||||
GXLoadPosMtxImm(mtxPtr, 0);
|
||||
GXSetCurrentMtx(0);
|
||||
}
|
||||
|
||||
math::VEC2 Pane::GetVtxPos() const {
|
||||
math::VEC2 basePt(0.0f, 0.0f);
|
||||
|
||||
switch (mBasePosition % 3) {
|
||||
default:
|
||||
case 0:
|
||||
basePt.x = 0.0f;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
basePt.x = -mSize.width / 2.0f;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
basePt.x = -mSize.width;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mBasePosition / 3) {
|
||||
default:
|
||||
case 0:
|
||||
basePt.y = 0.0f;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
basePt.y = -mSize.height / 2.0f;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
basePt.y = -mSize.height;
|
||||
break;
|
||||
}
|
||||
|
||||
return basePt;
|
||||
}
|
||||
|
||||
Material* Pane::GetMaterial() const {
|
||||
return mpMaterial;
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "picture.h"
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
#include "new.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
NW4HBM_UT_GET_DERIVED_RUNTIME_TYPEINFO(Picture, Pane);
|
||||
|
||||
Picture::Picture(const res::Picture* pResPic, const ResBlockSet& resBlockSet)
|
||||
: Pane(pResPic) {
|
||||
u8 texCoordNum = ut::Min<u8>(pResPic->texCoordNum, 8);
|
||||
|
||||
Init(texCoordNum);
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mVtxColors); i++) {
|
||||
mVtxColors[i] = pResPic->vtxCols[i];
|
||||
}
|
||||
|
||||
if (texCoordNum && !mTexCoordAry.IsEmpty()) {
|
||||
mTexCoordAry.Copy(&pResPic[1], texCoordNum);
|
||||
}
|
||||
|
||||
if (Material* pMemMaterial =
|
||||
static_cast<Material*>(Layout::AllocMemory(sizeof(*pMemMaterial))))
|
||||
{
|
||||
NW4HBM_ASSERT_CHECK_NULL(149, resBlockSet.pMaterialList);
|
||||
const u32* matOffsTbl =
|
||||
detail::ConvertOffsToPtr<u32>(resBlockSet.pMaterialList, 0xc);
|
||||
const res::Material* pResMaterial = detail::ConvertOffsToPtr<res::Material>(
|
||||
resBlockSet.pMaterialList, matOffsTbl[pResPic->materialIdx]);
|
||||
|
||||
mpMaterial = new (pMemMaterial) Material(pResMaterial, resBlockSet);
|
||||
}
|
||||
}
|
||||
|
||||
void Picture::Init(u8 texNum) {
|
||||
if (texNum) {
|
||||
ReserveTexCoord(texNum);
|
||||
}
|
||||
}
|
||||
|
||||
Picture::~Picture() {
|
||||
if (mpMaterial && !mpMaterial->IsUserAllocated()) {
|
||||
mpMaterial->~Material();
|
||||
Layout::FreeMemory(mpMaterial);
|
||||
mpMaterial = NULL;
|
||||
}
|
||||
|
||||
mTexCoordAry.Free();
|
||||
}
|
||||
|
||||
void Picture::Append(TPLPalette* pTplRes) {
|
||||
GXTexObj texObj;
|
||||
detail::InitGXTexObjFromTPL(&texObj, pTplRes, 0);
|
||||
|
||||
Append(texObj);
|
||||
}
|
||||
|
||||
void Picture::Append(const GXTexObj& texObj) {
|
||||
if (mpMaterial->GetTextureNum() >= mpMaterial->GetTextureCap() ||
|
||||
mpMaterial->GetTextureNum() >= mpMaterial->GetTexCoordGenCap())
|
||||
{
|
||||
NW4R_DB_WARNING(
|
||||
192, false,
|
||||
"mpMaterial->GetTextureNum(%d) is large. mpMaterial->GetTextureCap(%d), "
|
||||
"mpMaterial->GetTexCoordGenCap(%d)\n",
|
||||
mpMaterial->GetTextureNum(), mpMaterial->GetTextureCap(),
|
||||
mpMaterial->GetTexCoordGenCap());
|
||||
return;
|
||||
}
|
||||
|
||||
u8 texIdx = mpMaterial->GetTextureNum();
|
||||
mpMaterial->SetTextureNum(texIdx + 1);
|
||||
mpMaterial->SetTexture(texIdx, texObj);
|
||||
mpMaterial->SetTexCoordGenNum(mpMaterial->GetTextureNum());
|
||||
mpMaterial->SetTexCoordGen(texIdx, TexCoordGen());
|
||||
|
||||
SetTexCoordNum(mpMaterial->GetTextureNum());
|
||||
|
||||
if (mSize == Size(0.0f, 0.0f) && mpMaterial->GetTextureNum() == 1) {
|
||||
mSize = detail::GetTextureSize(mpMaterial, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Picture::ReserveTexCoord(u8 num) {
|
||||
mTexCoordAry.Reserve(num);
|
||||
}
|
||||
|
||||
void Picture::SetTexCoordNum(u8 num) {
|
||||
mTexCoordAry.SetSize(num);
|
||||
}
|
||||
|
||||
ut::Color Picture::GetVtxColor(u32 idx) const {
|
||||
NW4HBM_ASSERT(251, idx < VERTEXCOLOR_MAX);
|
||||
return mVtxColors[idx];
|
||||
}
|
||||
|
||||
void Picture::SetVtxColor(u32 idx, ut::Color value) {
|
||||
NW4HBM_ASSERT(262, idx < VERTEXCOLOR_MAX);
|
||||
mVtxColors[idx] = value;
|
||||
}
|
||||
|
||||
u8 Picture::GetVtxColorElement(u32 idx) const {
|
||||
return detail::GetVtxColorElement(mVtxColors, idx);
|
||||
}
|
||||
|
||||
void Picture::SetVtxColorElement(u32 idx, u8 value) {
|
||||
detail::SetVtxColorElement(mVtxColors, idx, value);
|
||||
}
|
||||
|
||||
void Picture::DrawSelf(const DrawInfo& drawInfo) {
|
||||
if (!mpMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoadMtx(drawInfo);
|
||||
|
||||
bool bUseVtxCol = mpMaterial->SetupGX(
|
||||
detail::IsModulateVertexColor(mVtxColors, mGlbAlpha), mGlbAlpha);
|
||||
nw4hbm::lyt::detail::SetVertexFormat(bUseVtxCol, mTexCoordAry.GetSize());
|
||||
|
||||
detail::DrawQuad(GetVtxPos(), mSize, mTexCoordAry.GetSize(), mTexCoordAry.GetArray(),
|
||||
bUseVtxCol ? mVtxColors : NULL, mGlbAlpha);
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "resourceAccessor.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
ResourceAccessor::~ResourceAccessor() {}
|
||||
|
||||
ResourceAccessor::ResourceAccessor() {}
|
||||
|
||||
ut::Font* ResourceAccessor::GetFont(const char*) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,558 @@
|
||||
#include "../ut/CharStrmReader.h"
|
||||
#include "../ut/Font.h"
|
||||
#include "../ut/ResFont.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "layout.h"
|
||||
#include "material.h"
|
||||
#include "pane.h"
|
||||
#include "textBox.h"
|
||||
|
||||
#include "new.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
NW4HBM_UT_GET_DERIVED_RUNTIME_TYPEINFO(TextBox, Pane);
|
||||
}
|
||||
} // namespace nw4hbm
|
||||
|
||||
namespace {
|
||||
using namespace nw4hbm;
|
||||
|
||||
u8 ClampColor(s16 colVal);
|
||||
|
||||
ut::Color GetColor(const GXColorS10& src) {
|
||||
GXColor dst;
|
||||
|
||||
dst.r = ClampColor(src.r);
|
||||
dst.g = ClampColor(src.g);
|
||||
dst.b = ClampColor(src.b);
|
||||
dst.a = ClampColor(src.a);
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
u8 ClampColor(s16 value) {
|
||||
return value < 0 ? 0 : (value > 255 ? 255 : value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int CalcLineRectImpl(ut::Rect* pRect, ut::TextWriterBase<T>* pTextWriter, const T* str,
|
||||
int length, f32 maxWidth, bool* pbOver) {
|
||||
NW4HBM_ASSERT_VALID_PTR(71, pTextWriter);
|
||||
NW4HBM_ASSERT_VALID_PTR(72, pRect);
|
||||
NW4HBM_ASSERT_VALID_PTR(73, str);
|
||||
NW4R_ASSERT_MIN(74, length, 0);
|
||||
ut::PrintContext<T> context = {pTextWriter, str, 0.0f, 0.0f, 0};
|
||||
const ut::Font* font = pTextWriter->GetFont();
|
||||
|
||||
f32 x = 0.0f;
|
||||
bool bCharSpace = false;
|
||||
|
||||
NW4HBM_ASSERT_VALID_PTR(83, font);
|
||||
ut::CharStrmReader reader = font->GetCharStrmReader();
|
||||
const T* prStrPos = static_cast<const T*>(reader.GetCurrentPos());
|
||||
|
||||
pRect->left = 0.0f;
|
||||
pRect->right = 0.0f;
|
||||
pRect->top = ut::Min(0.0f, pTextWriter->GetLineHeight());
|
||||
pRect->bottom = ut::Max(0.0f, pTextWriter->GetLineHeight());
|
||||
|
||||
*pbOver = false;
|
||||
|
||||
reader.Set(str);
|
||||
|
||||
ut::Rect prMaxRect = *pRect;
|
||||
|
||||
for (u16 code = reader.Next();
|
||||
static_cast<const T*>(reader.GetCurrentPos()) - str <= length;
|
||||
prStrPos = static_cast<const T*>(reader.GetCurrentPos()), code = reader.Next(),
|
||||
prMaxRect = *pRect)
|
||||
{
|
||||
if ((int)code < L' ') {
|
||||
ut::Operation operation;
|
||||
ut::Rect rect(x, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
context.str = static_cast<const T*>(reader.GetCurrentPos());
|
||||
context.flags = 0;
|
||||
context.flags |= bCharSpace ? 0 : 1;
|
||||
|
||||
pTextWriter->SetCursorX(x);
|
||||
|
||||
operation = pTextWriter->GetTagProcessor().CalcRect(&rect, code, &context);
|
||||
|
||||
NW4HBM_ASSERT_VALID_PTR(123, context.str);
|
||||
reader.Set(context.str);
|
||||
|
||||
pRect->left = ut::Min(pRect->left, rect.left);
|
||||
pRect->top = ut::Min(pRect->top, rect.top);
|
||||
pRect->right = ut::Max(pRect->right, rect.right);
|
||||
pRect->bottom = ut::Max(pRect->bottom, rect.bottom);
|
||||
|
||||
x = pTextWriter->GetCursorX();
|
||||
|
||||
if (pRect->GetWidth() > maxWidth) {
|
||||
*pbOver = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (operation == ut::OPERATION_END_DRAW) {
|
||||
return length;
|
||||
} else if (operation == ut::OPERATION_NO_CHAR_SPACE) {
|
||||
bCharSpace = false;
|
||||
} else if (operation == ut::OPERATION_CHAR_SPACE) {
|
||||
bCharSpace = true;
|
||||
} else if (operation == ut::OPERATION_NEXT_LINE) {
|
||||
goto end_draw;
|
||||
}
|
||||
} else {
|
||||
if (bCharSpace) {
|
||||
x += pTextWriter->GetCharSpace();
|
||||
}
|
||||
|
||||
bCharSpace = true;
|
||||
|
||||
if (pTextWriter->IsWidthFixed()) {
|
||||
x += pTextWriter->GetFixedWidth();
|
||||
} else {
|
||||
x += pTextWriter->GetFont()->GetCharWidth(code) * pTextWriter->GetScaleH();
|
||||
}
|
||||
|
||||
pRect->left = ut::Min(pRect->left, x);
|
||||
pRect->right = ut::Max(pRect->right, x);
|
||||
|
||||
if (pRect->GetWidth() > maxWidth) {
|
||||
*pbOver = true;
|
||||
goto end_draw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end_draw:
|
||||
if (*pbOver && prStrPos) {
|
||||
*pRect = prMaxRect;
|
||||
return prStrPos - str;
|
||||
} else {
|
||||
return static_cast<const T*>(reader.GetCurrentPos()) - str;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CalcStringRectImpl(ut::Rect* pRect, ut::TextWriterBase<T>* pTextWriter, const T* str,
|
||||
int length, f32 maxWidth) {
|
||||
NW4HBM_ASSERT_VALID_PTR(218, pTextWriter);
|
||||
NW4HBM_ASSERT_VALID_PTR(219, pRect);
|
||||
NW4HBM_ASSERT_VALID_PTR(220, str);
|
||||
NW4R_ASSERT_MIN(221, length, 0);
|
||||
int remain = length;
|
||||
const T* pos = str;
|
||||
|
||||
pRect->left = 0.0f;
|
||||
pRect->right = 0.0f;
|
||||
pRect->top = 0.0f;
|
||||
pRect->bottom = 0.0f;
|
||||
pTextWriter->SetCursor(0.0f, 0.0f);
|
||||
|
||||
do {
|
||||
ut::Rect rect;
|
||||
bool bOver;
|
||||
int read = CalcLineRectImpl(&rect, pTextWriter, pos, remain, maxWidth, &bOver);
|
||||
|
||||
if (bOver) {
|
||||
CalcLineRectImpl(&rect, pTextWriter, L"\n", 1, maxWidth, &bOver);
|
||||
}
|
||||
|
||||
pos += read;
|
||||
remain -= read;
|
||||
|
||||
pRect->left = ut::Min(pRect->left, rect.left);
|
||||
pRect->top = ut::Min(pRect->top, rect.top);
|
||||
pRect->right = ut::Max(pRect->right, rect.right);
|
||||
pRect->bottom = ut::Max(pRect->bottom, rect.bottom);
|
||||
} while (remain > 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int CalcLineStrNum(f32* pWidth, ut::TextWriterBase<T>* pTextWriter, const T* str, int length,
|
||||
f32 maxWidth, bool* pbOver) {
|
||||
NW4HBM_ASSERT_VALID_PTR(275, pTextWriter);
|
||||
NW4HBM_ASSERT_VALID_PTR(276, str);
|
||||
NW4R_ASSERT_MIN(277, length, 0);
|
||||
|
||||
ut::Rect rect;
|
||||
ut::TextWriterBase<T> myCopy = *pTextWriter;
|
||||
myCopy.SetCursor(0.0f, 0.0f);
|
||||
|
||||
int ret = CalcLineRectImpl(&rect, &myCopy, str, length, maxWidth, pbOver);
|
||||
|
||||
*pWidth = rect.GetWidth();
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CalcStringRect(ut::Rect* pRect, ut::TextWriterBase<T>* pTextWriter, const T* str,
|
||||
int length, f32 maxWidth) {
|
||||
NW4HBM_ASSERT_VALID_PTR(311, pTextWriter);
|
||||
NW4HBM_ASSERT_VALID_PTR(312, pRect);
|
||||
NW4HBM_ASSERT_VALID_PTR(313, str);
|
||||
NW4R_ASSERT_MIN(314, length, 0);
|
||||
ut::TextWriterBase<T> myCopy = *pTextWriter;
|
||||
CalcStringRectImpl(pRect, &myCopy, str, length, maxWidth);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
TextBox::TextBox(u16 allocStrLen, const wchar_t* str, const ut::Font* pFont) : Pane() {
|
||||
Init(allocStrLen);
|
||||
SetString(str);
|
||||
SetFont(pFont);
|
||||
}
|
||||
|
||||
TextBox::TextBox(const res::TextBox* pBlock, const ResBlockSet& resBlockSet)
|
||||
: Pane(pBlock) {
|
||||
u16 allocStrBufLen = pBlock->textBufBytes / sizeof(wchar_t);
|
||||
if (allocStrBufLen) {
|
||||
allocStrBufLen = allocStrBufLen - 1;
|
||||
}
|
||||
|
||||
Init(allocStrBufLen);
|
||||
|
||||
if (pBlock->textStrBytes >= 2 && mTextBuf != NULL) {
|
||||
const wchar_t* pBlockText =
|
||||
detail::ConvertOffsToPtr<wchar_t>(pBlock, pBlock->textStrOffset);
|
||||
const u16 resStrLen = pBlock->textStrBytes / sizeof(wchar_t) - 1;
|
||||
|
||||
SetString(pBlockText, 0, resStrLen);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mTextColors); i++) {
|
||||
mTextColors[i] = pBlock->textCols[i];
|
||||
}
|
||||
|
||||
mFontSize = pBlock->fontSize;
|
||||
mTextPosition = pBlock->textPosition;
|
||||
mCharSpace = pBlock->charSpace;
|
||||
mLineSpace = pBlock->lineSpace;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(395, resBlockSet.pFontList);
|
||||
NW4HBM_ASSERT(396, pBlock->fontIdx < resBlockSet.pFontList->fontNum);
|
||||
|
||||
const res::Font* fonts = detail::ConvertOffsToPtr<res::Font>(
|
||||
resBlockSet.pFontList, sizeof(*resBlockSet.pFontList));
|
||||
|
||||
const char* fontName =
|
||||
detail::ConvertOffsToPtr<char>(fonts, fonts[pBlock->fontIdx].nameStrOffset);
|
||||
|
||||
if (ut::Font* pFont = resBlockSet.pResAccessor->GetFont(fontName)) {
|
||||
mpFont = pFont;
|
||||
} else if (void* fontRes =
|
||||
resBlockSet.pResAccessor->GetResource('font', fontName, NULL))
|
||||
{
|
||||
if (void* pMemFont = Layout::AllocMemory(sizeof(ut::ResFont))) {
|
||||
ut::ResFont* pResFont = new (pMemFont) ut::ResFont();
|
||||
bool bSuccess = pResFont->SetResource(fontRes);
|
||||
|
||||
if (!bSuccess) {
|
||||
NW4R_DB_ASSERTMSG(410, false, "Fail to load ResFont.");
|
||||
}
|
||||
|
||||
mpFont = pResFont;
|
||||
mTextBoxFlag.allocFont = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (void* pMemMaterial = Layout::AllocMemory(sizeof(Material))) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(420, resBlockSet.pMaterialList);
|
||||
|
||||
const u32* matOffsTbl = detail::ConvertOffsToPtr<u32>(
|
||||
resBlockSet.pMaterialList, sizeof(*resBlockSet.pMaterialList));
|
||||
|
||||
const res::Material* pResMaterial = detail::ConvertOffsToPtr<res::Material>(
|
||||
resBlockSet.pMaterialList, matOffsTbl[pBlock->materialIdx]);
|
||||
|
||||
mpMaterial = new (pMemMaterial) Material(pResMaterial, resBlockSet);
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::Init(u16 allocStrLen) {
|
||||
mTextBuf = NULL;
|
||||
mTextBufBytes = 0;
|
||||
mTextLen = 0;
|
||||
|
||||
mpFont = NULL;
|
||||
mFontSize = Size(0.0f, 0.0f);
|
||||
|
||||
SetTextPositionH(HORIZONTALPOSITION_CENTER);
|
||||
SetTextPositionV(VERTICALPOSITION_CENTER);
|
||||
|
||||
mLineSpace = 0.0f;
|
||||
mCharSpace = 0.0f;
|
||||
mpTagProcessor = NULL;
|
||||
|
||||
memset(&mTextBoxFlag, 0, sizeof(mTextBoxFlag));
|
||||
|
||||
if (allocStrLen != 0) {
|
||||
AllocStringBuffer(allocStrLen);
|
||||
}
|
||||
}
|
||||
|
||||
TextBox::~TextBox() {
|
||||
SetFont(NULL);
|
||||
|
||||
if (mpMaterial != NULL && !mpMaterial->IsUserAllocated()) {
|
||||
mpMaterial->~Material();
|
||||
Layout::FreeMemory(mpMaterial);
|
||||
mpMaterial = NULL;
|
||||
}
|
||||
|
||||
FreeStringBuffer();
|
||||
}
|
||||
|
||||
ut::Color TextBox::GetVtxColor(u32 idx) const {
|
||||
NW4HBM_ASSERT(467, idx < VERTEXCOLOR_MAX);
|
||||
return GetTextColor(idx / 2);
|
||||
}
|
||||
|
||||
void TextBox::SetVtxColor(u32 idx, ut::Color value) {
|
||||
NW4HBM_ASSERT(478, idx < VERTEXCOLOR_MAX);
|
||||
SetTextColor(idx / 2, value);
|
||||
}
|
||||
|
||||
u8 TextBox::GetVtxColorElement(u32 idx) const {
|
||||
NW4HBM_ASSERT(486, idx < ANIMTARGET_VERTEXCOLOR_MAX);
|
||||
return reinterpret_cast<const u8*>(mTextColors + idx / 8)[idx % 4];
|
||||
}
|
||||
|
||||
void TextBox::SetVtxColorElement(u32 idx, u8 value) {
|
||||
NW4HBM_ASSERT(494, idx < ANIMTARGET_VERTEXCOLOR_MAX);
|
||||
reinterpret_cast<u8*>(mTextColors + idx / 8)[idx % 4] = value;
|
||||
}
|
||||
|
||||
const ut::Rect TextBox::GetTextDrawRect(const DrawInfo& drawInfo) const {
|
||||
ut::WideTextWriter writer;
|
||||
|
||||
writer.SetFont(*mpFont);
|
||||
writer.SetFontSize(mFontSize.width, mFontSize.height);
|
||||
writer.SetLineSpace(mLineSpace);
|
||||
writer.SetCharSpace(mCharSpace);
|
||||
|
||||
if (mpTagProcessor) {
|
||||
writer.SetTagProcessor(mpTagProcessor);
|
||||
}
|
||||
|
||||
ut::Rect rect = GetTextDrawRect(&writer);
|
||||
|
||||
if (drawInfo.IsYAxisUp()) {
|
||||
rect.top = -rect.top;
|
||||
rect.bottom = -rect.bottom;
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
void TextBox::DrawSelf(const DrawInfo& drawInfo) {
|
||||
if (mTextBuf == NULL || mpFont == NULL || mpMaterial == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
LoadMtx(drawInfo);
|
||||
|
||||
ut::WideTextWriter writer;
|
||||
writer.SetFont(*mpFont);
|
||||
writer.SetFontSize(mFontSize.width, mFontSize.height);
|
||||
writer.SetLineSpace(mLineSpace);
|
||||
writer.SetCharSpace(mCharSpace);
|
||||
|
||||
ut::Color topCol = detail::MultipleAlpha(mTextColors[TEXTCOLOR_TOP], mGlbAlpha);
|
||||
ut::Color btmCol = detail::MultipleAlpha(mTextColors[TEXTCOLOR_BOTTOM], mGlbAlpha);
|
||||
writer.SetGradationMode(topCol != btmCol ? ut::CharWriter::GRADMODE_V :
|
||||
ut::CharWriter::GRADMODE_NONE);
|
||||
|
||||
writer.SetTextColor(topCol, btmCol);
|
||||
|
||||
ut::Color minCol = GetColor(mpMaterial->GetTevColor(TEVCOLOR_REG0));
|
||||
ut::Color maxCol = GetColor(mpMaterial->GetTevColor(TEVCOLOR_REG1));
|
||||
writer.SetColorMapping(minCol, maxCol);
|
||||
|
||||
if (mpTagProcessor) {
|
||||
writer.SetTagProcessor(mpTagProcessor);
|
||||
}
|
||||
|
||||
writer.SetupGX();
|
||||
|
||||
ut::Rect textRect = GetTextDrawRect(&writer);
|
||||
|
||||
f32 hMag = GetTextMagH();
|
||||
wchar_t* strPos = mTextBuf;
|
||||
f32 textWidth = textRect.GetWidth();
|
||||
|
||||
writer.SetCursor(textRect.left, textRect.top);
|
||||
|
||||
for (int remain = mTextLen; remain > 0;) {
|
||||
f32 lineWidth;
|
||||
bool bOver;
|
||||
int lineStrNum =
|
||||
CalcLineStrNum(&lineWidth, &writer, strPos, remain, mSize.width, &bOver);
|
||||
f32 textPosX = hMag * (textWidth - lineWidth);
|
||||
|
||||
writer.SetCursorX(textRect.left + textPosX);
|
||||
writer.Print(strPos, lineStrNum);
|
||||
|
||||
if (bOver) {
|
||||
writer.Print(L"\n");
|
||||
}
|
||||
|
||||
strPos += lineStrNum;
|
||||
remain -= lineStrNum;
|
||||
}
|
||||
}
|
||||
|
||||
u16 TextBox::GetStringBufferLength() const {
|
||||
if (mTextBufBytes == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
NW4HBM_ASSERT(605, mTextBufBytes >= sizeof(wchar_t));
|
||||
}
|
||||
|
||||
return mTextBufBytes / sizeof(wchar_t) - 1;
|
||||
}
|
||||
|
||||
void TextBox::AllocStringBuffer(u16 minLen) {
|
||||
if (minLen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
u16 allocBytes = sizeof(wchar_t) * (minLen + 1);
|
||||
if (allocBytes <= mTextBufBytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
FreeStringBuffer();
|
||||
|
||||
mTextBuf = static_cast<wchar_t*>(Layout::AllocMemory(allocBytes));
|
||||
if (mTextBuf != NULL) {
|
||||
mTextBufBytes = allocBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::FreeStringBuffer() {
|
||||
if (mTextBuf != NULL) {
|
||||
Layout::FreeMemory(mTextBuf);
|
||||
mTextBuf = NULL;
|
||||
mTextBufBytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
u16 TextBox::SetString(const wchar_t* str, u16 dstIdx) {
|
||||
return SetString(str, dstIdx, std::wcslen(str));
|
||||
}
|
||||
|
||||
u16 TextBox::SetString(const wchar_t* str, u16 dstIdx, u16 strLen) {
|
||||
if (mTextBuf == NULL) {
|
||||
NW4R_DB_WARNING(708, false, "mTextBuf is NULL.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 bufLen = GetStringBufferLength();
|
||||
if (dstIdx >= bufLen) {
|
||||
NW4R_DB_WARNING(716, false, "dstIdx is out of range.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const u16 cpLen = ut::Min<u16>(strLen, bufLen - dstIdx);
|
||||
|
||||
if (cpLen < strLen) {
|
||||
NW4R_DB_WARNING(721, false, "%d character(s) droped.\n", strLen - cpLen);
|
||||
}
|
||||
|
||||
std::memcpy(&mTextBuf[dstIdx], str, sizeof(wchar_t) * cpLen);
|
||||
|
||||
mTextLen = dstIdx + cpLen;
|
||||
mTextBuf[mTextLen] = L'\0';
|
||||
|
||||
return cpLen;
|
||||
}
|
||||
|
||||
const ut::Font* TextBox::GetFont() const {
|
||||
return mpFont;
|
||||
}
|
||||
|
||||
void TextBox::SetFont(const ut::Font* pFont) {
|
||||
if (mTextBoxFlag.allocFont) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(775, mpFont);
|
||||
mpFont->~Font();
|
||||
Layout::FreeMemory(const_cast<ut::Font*>(mpFont));
|
||||
mTextBoxFlag.allocFont = false;
|
||||
}
|
||||
|
||||
mpFont = pFont;
|
||||
|
||||
if (mpFont) {
|
||||
SetFontSize(Size(mpFont->GetWidth(), mpFont->GetHeight()));
|
||||
} else {
|
||||
SetFontSize(Size(0.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
const ut::Rect TextBox::GetTextDrawRect(ut::WideTextWriter* pWriter) const {
|
||||
ut::Rect textRect;
|
||||
|
||||
pWriter->SetCursor(0.0f, 0.0f);
|
||||
CalcStringRect(&textRect, pWriter, mTextBuf, mTextLen, mSize.width);
|
||||
|
||||
math::VEC2 basePt = Pane::GetVtxPos();
|
||||
|
||||
textRect.MoveTo(basePt.x + (mSize.width - textRect.GetWidth()) * GetTextMagH(),
|
||||
basePt.y + (mSize.height - textRect.GetHeight()) * GetTextMagV());
|
||||
|
||||
return textRect;
|
||||
}
|
||||
|
||||
f32 TextBox::GetTextMagH() const {
|
||||
f32 hMag = 0.0f;
|
||||
|
||||
switch (GetTextPositionH()) {
|
||||
default:
|
||||
case HORIZONTALPOSITION_LEFT: {
|
||||
hMag = 0.0f;
|
||||
break;
|
||||
}
|
||||
case HORIZONTALPOSITION_CENTER: {
|
||||
hMag = 0.5f;
|
||||
break;
|
||||
}
|
||||
case HORIZONTALPOSITION_RIGHT: {
|
||||
hMag = 1.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hMag;
|
||||
}
|
||||
|
||||
f32 TextBox::GetTextMagV() const {
|
||||
f32 vMag = 0.0f;
|
||||
|
||||
switch (GetTextPositionV()) {
|
||||
default:
|
||||
case HORIZONTALPOSITION_LEFT: {
|
||||
vMag = 0.0f;
|
||||
break;
|
||||
}
|
||||
case HORIZONTALPOSITION_CENTER: {
|
||||
vMag = 0.5f;
|
||||
break;
|
||||
}
|
||||
case HORIZONTALPOSITION_RIGHT: {
|
||||
vMag = 1.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return vMag;
|
||||
}
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,449 @@
|
||||
#ifndef NW4HBM_LYT_TYPES_H
|
||||
#define NW4HBM_LYT_TYPES_H
|
||||
|
||||
#include "revolution/types.h"
|
||||
|
||||
#include <revolution/gx.h>
|
||||
|
||||
#include "../math/types.h"
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
static const u32 RESOURCE_TYPE_ANIMATION = 'anim';
|
||||
static const u32 RESOURCE_TYPE_LAYOUT = 'blyt';
|
||||
static const u32 RESOURCE_TYPE_FONT = 'font';
|
||||
static const u32 RESOURCE_TYPE_TEXTURE = 'timg';
|
||||
|
||||
enum {
|
||||
VERTEXCOLOR_LT = 0,
|
||||
VERTEXCOLOR_RT,
|
||||
VERTEXCOLOR_LB,
|
||||
VERTEXCOLOR_RB,
|
||||
|
||||
VERTEXCOLOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
TEVCOLOR_REG0 = 0,
|
||||
TEVCOLOR_REG1,
|
||||
TEVCOLOR_REG2,
|
||||
|
||||
TEVCOLOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
HORIZONTALPOSITION_LEFT = 0,
|
||||
HORIZONTALPOSITION_CENTER,
|
||||
HORIZONTALPOSITION_RIGHT,
|
||||
HORIZONTALPOSITION_MAX
|
||||
};
|
||||
enum {
|
||||
VERTICALPOSITION_TOP = 0,
|
||||
VERTICALPOSITION_CENTER,
|
||||
VERTICALPOSITION_BOTTOM,
|
||||
VERTICALPOSITION_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
ORIGINTYPE_TOPLEFT = 0,
|
||||
ORIGINTYPE_CENTER,
|
||||
|
||||
ORIGINTYPE_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTCOLOR_TOP = 0,
|
||||
TEXTCOLOR_BOTTOM,
|
||||
|
||||
TEXTCOLOR_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
WINDOWFRAME_LT = 0,
|
||||
WINDOWFRAME_RT,
|
||||
WINDOWFRAME_LB,
|
||||
WINDOWFRAME_RB,
|
||||
|
||||
WINDOWFRAME_L,
|
||||
WINDOWFRAME_R,
|
||||
WINDOWFRAME_T,
|
||||
WINDOWFRAME_B,
|
||||
|
||||
WINDOWFRAME_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
TEXTUREFLIP_NONE,
|
||||
TEXTUREFLIP_H,
|
||||
TEXTUREFLIP_V,
|
||||
TEXTUREFLIP_90,
|
||||
TEXTUREFLIP_180,
|
||||
TEXTUREFLIP_270,
|
||||
|
||||
TEXTUREFLIP_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
FLIPINDEX_X,
|
||||
FLIPINDEX_Y,
|
||||
|
||||
FLIPINDEX_MAX
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
const T* ConvertOffsToPtr(const void* baseAddress, unsigned offset) {
|
||||
return reinterpret_cast<const T*>(reinterpret_cast<unsigned>(baseAddress) + offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* ConvertOffsToPtr(void* baseAddress, unsigned offset) {
|
||||
return reinterpret_cast<T*>(reinterpret_cast<unsigned>(baseAddress) + offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SetBit(T* pBits, int pos, bool val) {
|
||||
const T mask = (T)(~(1 << pos));
|
||||
*pBits &= mask;
|
||||
*pBits |= (val ? 1 : 0) << pos;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool TestBit(T bits, int pos) {
|
||||
const T mask = (T)(1 << pos);
|
||||
return 0 != (bits & mask);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetBits(T bits, int pos, int len) {
|
||||
T mask = static_cast<T>(~(-1 << len));
|
||||
return static_cast<T>((bits >> pos) & mask);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
typedef struct Size {
|
||||
Size() : width(), height() {}
|
||||
|
||||
Size(f32 aWidth, f32 aHeight) : width(aWidth), height(aHeight) {}
|
||||
|
||||
Size(const Size& other) : width(other.width), height(other.height) {}
|
||||
|
||||
friend bool operator==(const Size& a, const Size& b) {
|
||||
return a.width == b.width && a.height == b.height;
|
||||
}
|
||||
|
||||
/* 0x00 */ f32 width;
|
||||
/* 0x04 */ f32 height;
|
||||
} Size; // size = 0x08
|
||||
|
||||
typedef struct TexSRT {
|
||||
/* 0x00 */ math::VEC2 translate;
|
||||
/* 0x08 */ f32 rotate;
|
||||
/* 0x0C */ math::VEC2 scale;
|
||||
} TexSRT;
|
||||
|
||||
class TexCoordGen {
|
||||
public:
|
||||
TexCoordGen() : reserve(0) { Set(GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY); }
|
||||
|
||||
u32 GetTexMtx() const { return texMtx; }
|
||||
|
||||
GXTexGenType GetTexGenType() const { return static_cast<GXTexGenType>(texGenType); }
|
||||
GXTexGenSrc GetTexGenSrc() const { return static_cast<GXTexGenSrc>(texGenSrc); }
|
||||
|
||||
void Set(GXTexGenType aTexGenType, GXTexGenSrc aTexGenSrc, u32 aTexMtx) {
|
||||
texGenType = aTexGenType;
|
||||
texGenSrc = aTexGenSrc;
|
||||
texMtx = aTexMtx;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 texGenType;
|
||||
/* 0x01 */ u8 texGenSrc;
|
||||
/* 0x02 */ u8 texMtx;
|
||||
/* 0x03 */ u8 reserve;
|
||||
};
|
||||
|
||||
class IndirectStage {
|
||||
public:
|
||||
IndirectStage() { Set(GX_TEXCOORD0, GX_TEXMAP0, GX_ITS_1, GX_ITS_1); }
|
||||
|
||||
GXTexCoordID GetTexCoordGen() const { return static_cast<GXTexCoordID>(texCoordGen); }
|
||||
|
||||
GXTexMapID GetTexMap() const { return static_cast<GXTexMapID>(texMap); }
|
||||
|
||||
GXIndTexScale GetScaleS() const { return static_cast<GXIndTexScale>(scaleS); }
|
||||
GXIndTexScale GetScaleT() const { return static_cast<GXIndTexScale>(scaleT); }
|
||||
|
||||
void Set(GXTexCoordID aTexCoordGen, GXTexMapID aTexMap, GXIndTexScale aScaleS,
|
||||
GXIndTexScale aScaleT) {
|
||||
texCoordGen = aTexCoordGen;
|
||||
|
||||
texMap = aTexMap;
|
||||
scaleS = aScaleS;
|
||||
scaleT = aScaleT;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 texCoordGen;
|
||||
/* 0x01 */ u8 texMap;
|
||||
/* 0x02 */ u8 scaleS;
|
||||
/* 0x03 */ u8 scaleT;
|
||||
};
|
||||
|
||||
class TevSwapMode {
|
||||
public:
|
||||
GXTevColorChan GetR() const { return static_cast<GXTevColorChan>((swap) & 0x03); }
|
||||
GXTevColorChan GetG() const { return static_cast<GXTevColorChan>((swap >> 2) & 0x03); }
|
||||
GXTevColorChan GetB() const { return static_cast<GXTevColorChan>((swap >> 4) & 0x03); }
|
||||
GXTevColorChan GetA() const { return static_cast<GXTevColorChan>((swap >> 6) & 0x03); }
|
||||
|
||||
void Set(GXTevColorChan r, GXTevColorChan g, GXTevColorChan b, GXTevColorChan a) {
|
||||
swap = r | g << 2 | b << 4 | a << 6;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 swap;
|
||||
};
|
||||
|
||||
class TevStageInOp {
|
||||
public:
|
||||
u8 GetA() const { return ab & 0x0F; }
|
||||
u8 GetB() const { return (ab >> 4) & 0x0F; }
|
||||
u8 GetC() const { return cd & 0x0F; }
|
||||
u8 GetD() const { return (cd >> 4) & 0x0F; }
|
||||
|
||||
u8 GetScale() const { return (op >> 6) & 0x03; }
|
||||
u8 GetBias() const { return (op >> 4) & 0x03; }
|
||||
u8 GetOp() const { return op & 0x0F; }
|
||||
|
||||
u8 GetKSel() const { return (cl >> 3) & 0x1F; }
|
||||
u8 GetOutReg() const { return (cl >> 1) & 0x03; }
|
||||
bool IsClamp() const { return static_cast<bool>(cl & 0x01); }
|
||||
|
||||
void SetIn(u8 a, u8 b, u8 c, u8 d) {
|
||||
ab = a | b << 4;
|
||||
cd = c | d << 4;
|
||||
}
|
||||
|
||||
void SetOp(u8 aOp, u8 bias, u8 scale, bool clamp, u8 outReg, u8 kSel) {
|
||||
op = aOp | bias << 4 | scale << 6;
|
||||
cl = (clamp ? 1 : 0) | outReg << 1 | kSel << 3;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 ab;
|
||||
/* 0x01 */ u8 cd;
|
||||
/* 0x02 */ u8 op;
|
||||
/* 0x03 */ u8 cl;
|
||||
};
|
||||
|
||||
class TevStage {
|
||||
public:
|
||||
TevStage() {
|
||||
SetOrder(GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
||||
SetColorIn(GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
||||
SetAlphaIn(GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA);
|
||||
SetColorOp(GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV,
|
||||
GX_TEV_KCSEL_K0);
|
||||
SetAlphaOp(GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV,
|
||||
GX_TEV_KASEL_K0_R);
|
||||
SetIndirect(GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF,
|
||||
GX_ITW_OFF, false, false, GX_ITBA_OFF);
|
||||
}
|
||||
|
||||
GXTexCoordID GetTexCoordGen() const { return static_cast<GXTexCoordID>(texCoordGen); }
|
||||
GXChannelID GetColorChan() const { return static_cast<GXChannelID>(colChan); }
|
||||
|
||||
GXTexMapID GetTexMap() const {
|
||||
return static_cast<GXTexMapID>((swapSel & 1) << 8 | texMap);
|
||||
}
|
||||
|
||||
GXTevSwapSel GetTexSwapSel() const {
|
||||
return static_cast<GXTevSwapSel>((swapSel >> 3) & 0x03);
|
||||
}
|
||||
GXTevSwapSel GetRasSwapSel() const {
|
||||
return static_cast<GXTevSwapSel>((swapSel >> 1) & 0x03);
|
||||
}
|
||||
|
||||
GXTevColorArg GetColorInA() const { return static_cast<GXTevColorArg>(colIn.GetA()); }
|
||||
GXTevColorArg GetColorInB() const { return static_cast<GXTevColorArg>(colIn.GetB()); }
|
||||
GXTevColorArg GetColorInC() const { return static_cast<GXTevColorArg>(colIn.GetC()); }
|
||||
GXTevColorArg GetColorInD() const { return static_cast<GXTevColorArg>(colIn.GetD()); }
|
||||
|
||||
GXTevOp GetColorOp() const { return static_cast<GXTevOp>(colIn.GetOp()); }
|
||||
GXTevBias GetColorBias() const { return static_cast<GXTevBias>(colIn.GetBias()); }
|
||||
GXTevScale GetColorScale() const { return static_cast<GXTevScale>(colIn.GetScale()); }
|
||||
|
||||
bool IsColorClamp() const { return colIn.IsClamp(); }
|
||||
|
||||
GXTevRegID GetColorOutReg() const { return static_cast<GXTevRegID>(colIn.GetOutReg()); }
|
||||
|
||||
GXTevKColorSel GetKColorSel() const {
|
||||
return static_cast<GXTevKColorSel>(colIn.GetKSel());
|
||||
}
|
||||
|
||||
GXTevAlphaArg GetAlphaInA() const { return static_cast<GXTevAlphaArg>(alpIn.GetA()); }
|
||||
GXTevAlphaArg GetAlphaInB() const { return static_cast<GXTevAlphaArg>(alpIn.GetB()); }
|
||||
GXTevAlphaArg GetAlphaInC() const { return static_cast<GXTevAlphaArg>(alpIn.GetC()); }
|
||||
GXTevAlphaArg GetAlphaInD() const { return static_cast<GXTevAlphaArg>(alpIn.GetD()); }
|
||||
|
||||
GXTevOp GetAlphaOp() const { return static_cast<GXTevOp>(alpIn.GetOp()); }
|
||||
GXTevBias GetAlphaBias() const { return static_cast<GXTevBias>(alpIn.GetBias()); }
|
||||
GXTevScale GetAlphaScale() const { return static_cast<GXTevScale>(alpIn.GetScale()); }
|
||||
|
||||
bool IsAlphaClamp() const { return alpIn.IsClamp(); }
|
||||
|
||||
GXTevRegID GetAlphaOutReg() const { return static_cast<GXTevRegID>(alpIn.GetOutReg()); }
|
||||
|
||||
GXTevKAlphaSel GetKAlphaSel() const {
|
||||
return static_cast<GXTevKAlphaSel>(alpIn.GetKSel());
|
||||
}
|
||||
|
||||
GXIndTexStageID GetIndStage() const { return static_cast<GXIndTexStageID>(indStage); }
|
||||
GXIndTexMtxID GetIndMtxSel() const {
|
||||
return static_cast<GXIndTexMtxID>((indBiMt >> 3) & 0x0F);
|
||||
}
|
||||
GXIndTexBiasSel GetIndBiasSel() const {
|
||||
return static_cast<GXIndTexBiasSel>(indBiMt & 0x07);
|
||||
}
|
||||
|
||||
GXIndTexWrap GetIndWrapS() const { return static_cast<GXIndTexWrap>(indWrap & 0x07); }
|
||||
GXIndTexWrap GetIndWrapT() const {
|
||||
return static_cast<GXIndTexWrap>((indWrap >> 3) & 0x07);
|
||||
}
|
||||
|
||||
GXIndTexAlphaSel GetIndAlphaSel() const {
|
||||
return static_cast<GXIndTexAlphaSel>((indFoAdUtAl >> 4) & 0x03);
|
||||
}
|
||||
|
||||
bool IsIndUtcLod() const { return static_cast<bool>((indFoAdUtAl >> 3) & 0x01); }
|
||||
bool IsIndAddPrev() const { return static_cast<bool>((indFoAdUtAl >> 2) & 0x01); }
|
||||
|
||||
GXIndTexFormat GetIndFormat() const {
|
||||
return static_cast<GXIndTexFormat>(indFoAdUtAl & 0x03);
|
||||
}
|
||||
|
||||
void SetOrder(GXTexCoordID aTexCoordGen, GXTexMapID aTexMap, GXChannelID aColChan,
|
||||
GXTevSwapSel rasSel, GXTevSwapSel texSel) {
|
||||
texCoordGen = aTexCoordGen;
|
||||
colChan = aColChan;
|
||||
texMap = aTexMap;
|
||||
swapSel = aTexMap >> 8 | rasSel << 1 | texSel << 3;
|
||||
}
|
||||
|
||||
void SetColorIn(GXTevColorArg a, GXTevColorArg b, GXTevColorArg c, GXTevColorArg d) {
|
||||
colIn.SetIn(a, b, c, d);
|
||||
}
|
||||
|
||||
void SetColorOp(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp,
|
||||
GXTevRegID outReg, GXTevKColorSel kSel) {
|
||||
colIn.SetOp(op, bias, scale, clamp, outReg, kSel);
|
||||
}
|
||||
|
||||
void SetAlphaIn(GXTevAlphaArg a, GXTevAlphaArg b, GXTevAlphaArg c, GXTevAlphaArg d) {
|
||||
alpIn.SetIn(a, b, c, d);
|
||||
}
|
||||
|
||||
void SetAlphaOp(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp,
|
||||
GXTevRegID outReg, GXTevKAlphaSel kSel) {
|
||||
alpIn.SetOp(op, bias, scale, clamp, outReg, kSel);
|
||||
}
|
||||
|
||||
void SetIndirect(GXIndTexStageID stage, GXIndTexFormat format, GXIndTexBiasSel biasSel,
|
||||
GXIndTexMtxID mtxSel, GXIndTexWrap wrapS, GXIndTexWrap wrapT,
|
||||
bool addPrev, bool utcLod, GXIndTexAlphaSel alphaSel) {
|
||||
indStage = stage;
|
||||
indBiMt = biasSel | mtxSel << 3;
|
||||
indWrap = wrapS | wrapT << 3;
|
||||
indFoAdUtAl =
|
||||
format | (addPrev ? 1 : 0) << 2 | (utcLod ? 1 : 0) << 3 | alphaSel << 4;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 texCoordGen;
|
||||
/* 0x01 */ u8 colChan;
|
||||
/* 0x02 */ u8 texMap;
|
||||
/* 0x03 */ u8 swapSel;
|
||||
/* 0x04 */ TevStageInOp colIn;
|
||||
/* 0x08 */ TevStageInOp alpIn;
|
||||
/* 0x0C */ u8 indStage;
|
||||
/* 0x0D */ u8 indBiMt;
|
||||
/* 0x0E */ u8 indWrap;
|
||||
/* 0x0F */ u8 indFoAdUtAl;
|
||||
};
|
||||
|
||||
class ChanCtrl {
|
||||
public:
|
||||
ChanCtrl() : reserve1(0), reserve2(0) { Set(GX_SRC_VTX, GX_SRC_VTX); }
|
||||
|
||||
GXColorSrc GetColorSrc() const { return static_cast<GXColorSrc>(matSrcCol); }
|
||||
GXColorSrc GetAlphaSrc() const { return static_cast<GXColorSrc>(matSrcAlp); }
|
||||
|
||||
void Set(GXColorSrc colSrc, GXColorSrc alpSrc) {
|
||||
matSrcCol = colSrc;
|
||||
matSrcAlp = alpSrc;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 matSrcCol;
|
||||
/* 0x01 */ u8 matSrcAlp;
|
||||
/* 0x02 */ u8 reserve1;
|
||||
/* 0x03 */ u8 reserve2;
|
||||
};
|
||||
|
||||
class AlphaCompare {
|
||||
public:
|
||||
AlphaCompare() { Set(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); }
|
||||
|
||||
GXCompare GetComp0() const { return static_cast<GXCompare>(comp & 0x0F); }
|
||||
GXCompare GetComp1() const { return static_cast<GXCompare>((comp >> 4) & 0x0F); }
|
||||
|
||||
GXAlphaOp GetOp() const { return static_cast<GXAlphaOp>(op); }
|
||||
|
||||
u8 GetRef0() const { return ref0; }
|
||||
u8 GetRef1() const { return ref1; }
|
||||
|
||||
void Set(GXCompare aComp0, u8 aRef0, GXAlphaOp aOp, GXCompare aComp1, u8 aRef1) {
|
||||
comp = aComp0 | aComp1 << 4;
|
||||
op = aOp;
|
||||
ref0 = aRef0;
|
||||
ref1 = aRef1;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 comp;
|
||||
/* 0x01 */ u8 op;
|
||||
/* 0x02 */ u8 ref0;
|
||||
/* 0x03 */ u8 ref1;
|
||||
};
|
||||
|
||||
class BlendMode {
|
||||
public:
|
||||
BlendMode() { Set(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET); }
|
||||
|
||||
GXBlendMode GetType() const { return static_cast<GXBlendMode>(type); }
|
||||
GXBlendFactor GetSrcFactor() const { return static_cast<GXBlendFactor>(srcFactor); }
|
||||
GXBlendFactor GetDstFactor() const { return static_cast<GXBlendFactor>(dstFactor); }
|
||||
GXLogicOp GetOp() const { return static_cast<GXLogicOp>(op); }
|
||||
|
||||
void Set(GXBlendMode aType, GXBlendFactor aSrcFactor, GXBlendFactor aDstFactor,
|
||||
GXLogicOp aOp) {
|
||||
type = aType;
|
||||
srcFactor = aSrcFactor;
|
||||
dstFactor = aDstFactor;
|
||||
op = aOp;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ u8 type;
|
||||
/* 0x01 */ u8 srcFactor;
|
||||
/* 0x02 */ u8 dstFactor;
|
||||
/* 0x03 */ u8 op;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,568 @@
|
||||
#include "window.h"
|
||||
|
||||
#include "layout.h"
|
||||
|
||||
#include "new.h"
|
||||
|
||||
struct TextureFlipInfo {
|
||||
/* 0x00 */ u8 coords[4][2];
|
||||
/* 0x08 */ u8 idx[2];
|
||||
}; // size = 0x0A
|
||||
|
||||
namespace {
|
||||
// pretend this is nw4hbm::lyt
|
||||
using namespace nw4hbm;
|
||||
using namespace nw4hbm::lyt;
|
||||
|
||||
// NOTE the misspelling of GetTextureFlipInfo
|
||||
TextureFlipInfo& GetTexutreFlipInfo(u8 textureFlip);
|
||||
|
||||
void GetLTFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize);
|
||||
void GetLTTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip);
|
||||
void GetRTFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize);
|
||||
void GetRTTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip);
|
||||
void GetLBFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize);
|
||||
void GetLBTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip);
|
||||
void GetRBFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize);
|
||||
void GetRBTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip);
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
NW4HBM_UT_GET_DERIVED_RUNTIME_TYPEINFO(Window, Pane);
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
//! TODO clean up
|
||||
|
||||
namespace {
|
||||
|
||||
TextureFlipInfo& GetTexutreFlipInfo(u8 textureFlip) {
|
||||
// clang-format off
|
||||
static TextureFlipInfo flipInfos[] = // 0 1 2 3
|
||||
{ // in order of LT RT LB RB
|
||||
{{{0, 0}, {1, 0}, {0, 1}, {1, 1}}, {0, 1}}, // 0 1 2 3 no flip
|
||||
{{{1, 0}, {0, 0}, {1, 1}, {0, 1}}, {0, 1}}, // 1 0 3 2 horizontal flip
|
||||
{{{0, 1}, {1, 1}, {0, 0}, {1, 0}}, {0, 1}}, // 2 3 0 1 vertical flip
|
||||
{{{0, 1}, {0, 0}, {1, 1}, {1, 0}}, {1, 0}}, // 2 0 3 1, index flip cw 90 deg
|
||||
{{{1, 1}, {0, 1}, {1, 0}, {0, 0}}, {0, 1}}, // 3 2 1 0 cw 180 deg
|
||||
{{{1, 0}, {1, 1}, {0, 0}, {0, 1}}, {1, 0}} // 1 3 0 2, index flip cw 270 deg (ccw 90 deg)
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
NW4HBM_ASSERT(50, textureFlip < TEXTUREFLIP_MAX);
|
||||
return flipInfos[textureFlip];
|
||||
}
|
||||
|
||||
void GetLTFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize) {
|
||||
*pPt = basePt;
|
||||
pSize->width = winSize.width - frameSize.r;
|
||||
pSize->height = frameSize.t;
|
||||
}
|
||||
|
||||
void GetLTTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip) {
|
||||
TextureFlipInfo& flipInfo = GetTexutreFlipInfo(textureFlip);
|
||||
int ix = flipInfo.idx[FLIPINDEX_X];
|
||||
int iy = flipInfo.idx[FLIPINDEX_Y];
|
||||
|
||||
const math::VEC2 tSz(texSize.width, texSize.height);
|
||||
|
||||
texCds[VERTEXCOLOR_LT][ix] = texCds[VERTEXCOLOR_LB][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_LT][ix];
|
||||
|
||||
texCds[VERTEXCOLOR_LT][iy] = texCds[VERTEXCOLOR_RT][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_LT][iy];
|
||||
|
||||
texCds[VERTEXCOLOR_RB][ix] = texCds[VERTEXCOLOR_RT][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_LT][ix] +
|
||||
polSize.width /
|
||||
((flipInfo.coords[VERTEXCOLOR_RT][ix] - flipInfo.coords[VERTEXCOLOR_LT][ix]) *
|
||||
tSz[ix]);
|
||||
|
||||
texCds[VERTEXCOLOR_RB][iy] = texCds[VERTEXCOLOR_LB][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_LT][iy] +
|
||||
polSize.height /
|
||||
((flipInfo.coords[VERTEXCOLOR_LB][iy] - flipInfo.coords[VERTEXCOLOR_LT][iy]) *
|
||||
tSz[iy]);
|
||||
}
|
||||
|
||||
void GetRTFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize) {
|
||||
*pPt = math::VEC2(basePt.x + winSize.width - frameSize.r, basePt.y);
|
||||
pSize->width = frameSize.r;
|
||||
pSize->height = winSize.height - frameSize.b;
|
||||
}
|
||||
|
||||
void GetRTTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip) {
|
||||
TextureFlipInfo& flipInfo = GetTexutreFlipInfo(textureFlip);
|
||||
int ix = flipInfo.idx[FLIPINDEX_X];
|
||||
int iy = flipInfo.idx[FLIPINDEX_Y];
|
||||
|
||||
const math::VEC2 tSz(texSize.width, texSize.height);
|
||||
|
||||
texCds[VERTEXCOLOR_RT][ix] = texCds[VERTEXCOLOR_RB][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_RT][ix];
|
||||
|
||||
texCds[VERTEXCOLOR_RT][iy] = texCds[VERTEXCOLOR_LT][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_RT][iy];
|
||||
|
||||
texCds[VERTEXCOLOR_LB][ix] = texCds[VERTEXCOLOR_LT][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_RT][ix] +
|
||||
polSize.width /
|
||||
((flipInfo.coords[VERTEXCOLOR_LT][ix] - flipInfo.coords[VERTEXCOLOR_RT][ix]) *
|
||||
tSz[ix]);
|
||||
|
||||
texCds[VERTEXCOLOR_LB][iy] = texCds[VERTEXCOLOR_RB][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_RT][iy] +
|
||||
polSize.height /
|
||||
((flipInfo.coords[VERTEXCOLOR_RB][iy] - flipInfo.coords[VERTEXCOLOR_RT][iy]) *
|
||||
tSz[iy]);
|
||||
}
|
||||
|
||||
void GetLBFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize) {
|
||||
*pPt = math::VEC2(basePt.x, basePt.y + frameSize.t);
|
||||
pSize->width = frameSize.l;
|
||||
pSize->height = winSize.height - frameSize.t;
|
||||
}
|
||||
|
||||
void GetLBTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip) {
|
||||
TextureFlipInfo& flipInfo = GetTexutreFlipInfo(textureFlip);
|
||||
int ix = flipInfo.idx[FLIPINDEX_X];
|
||||
int iy = flipInfo.idx[FLIPINDEX_Y];
|
||||
|
||||
const math::VEC2 tSz(texSize.width, texSize.height);
|
||||
|
||||
texCds[VERTEXCOLOR_LB][ix] = texCds[VERTEXCOLOR_LT][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_LB][ix];
|
||||
|
||||
texCds[VERTEXCOLOR_LB][iy] = texCds[VERTEXCOLOR_RB][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_LB][iy];
|
||||
|
||||
texCds[VERTEXCOLOR_RT][ix] = texCds[VERTEXCOLOR_RB][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_LB][ix] +
|
||||
polSize.width /
|
||||
((flipInfo.coords[VERTEXCOLOR_RB][ix] - flipInfo.coords[VERTEXCOLOR_LB][ix]) *
|
||||
tSz[ix]);
|
||||
|
||||
texCds[VERTEXCOLOR_RT][iy] = texCds[VERTEXCOLOR_LT][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_LB][iy] +
|
||||
polSize.height /
|
||||
((flipInfo.coords[VERTEXCOLOR_LT][iy] - flipInfo.coords[VERTEXCOLOR_LB][iy]) *
|
||||
tSz[iy]);
|
||||
}
|
||||
|
||||
void GetRBFrameSize(math::VEC2* pPt, Size* pSize, const math::VEC2& basePt, const Size& winSize,
|
||||
const WindowFrameSize& frameSize) {
|
||||
*pPt = math::VEC2(basePt.x + frameSize.l, basePt.y + winSize.height - frameSize.b);
|
||||
pSize->width = winSize.width - frameSize.l;
|
||||
pSize->height = frameSize.b;
|
||||
}
|
||||
|
||||
void GetRBTexCoord(math::VEC2* texCds, const Size& polSize, const Size& texSize,
|
||||
u8 textureFlip) {
|
||||
TextureFlipInfo& flipInfo = GetTexutreFlipInfo(textureFlip);
|
||||
int ix = flipInfo.idx[FLIPINDEX_X];
|
||||
int iy = flipInfo.idx[FLIPINDEX_Y];
|
||||
|
||||
const math::VEC2 tSz(texSize.width, texSize.height);
|
||||
|
||||
texCds[VERTEXCOLOR_RB][ix] = texCds[VERTEXCOLOR_RT][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_RB][ix];
|
||||
|
||||
texCds[VERTEXCOLOR_RB][iy] = texCds[VERTEXCOLOR_LB][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_RB][iy];
|
||||
|
||||
texCds[VERTEXCOLOR_LT][ix] = texCds[VERTEXCOLOR_LB][ix] =
|
||||
flipInfo.coords[VERTEXCOLOR_RB][ix] +
|
||||
polSize.width /
|
||||
((flipInfo.coords[VERTEXCOLOR_LB][ix] - flipInfo.coords[VERTEXCOLOR_RB][ix]) *
|
||||
tSz[ix]);
|
||||
|
||||
texCds[VERTEXCOLOR_LT][iy] = texCds[VERTEXCOLOR_RT][iy] =
|
||||
flipInfo.coords[VERTEXCOLOR_RB][iy] +
|
||||
polSize.height /
|
||||
((flipInfo.coords[VERTEXCOLOR_RT][iy] - flipInfo.coords[VERTEXCOLOR_RB][iy]) *
|
||||
tSz[iy]);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
Window::Window(const res::Window* pBlock, const ResBlockSet& resBlockSet) : Pane(pBlock) {
|
||||
mContentInflation = pBlock->inflation;
|
||||
|
||||
NW4HBM_ASSERT_CHECK_NULL(193, resBlockSet.pMaterialList);
|
||||
const u32* const matOffsTbl = detail::ConvertOffsToPtr<u32>(
|
||||
resBlockSet.pMaterialList, sizeof(*resBlockSet.pMaterialList));
|
||||
|
||||
const res::WindowContent* pResContent =
|
||||
detail::ConvertOffsToPtr<res::WindowContent>(pBlock, pBlock->contentOffset);
|
||||
|
||||
for (int i = 0; i < (int)ARRAY_SIZE(mContent.vtxColors); i++) {
|
||||
mContent.vtxColors[i] = pResContent->vtxCols[i];
|
||||
}
|
||||
|
||||
if (pResContent->texCoordNum) {
|
||||
u8 texCoordNum = ut::Min<u8>(pResContent->texCoordNum, 8);
|
||||
mContent.texCoordAry.Reserve(texCoordNum);
|
||||
|
||||
if (!mContent.texCoordAry.IsEmpty()) {
|
||||
mContent.texCoordAry.Copy(&pResContent[1], texCoordNum);
|
||||
}
|
||||
}
|
||||
|
||||
if (void* pMemMaterial = Layout::AllocMemory(sizeof(Material))) {
|
||||
const res::Material* pResMaterial = detail::ConvertOffsToPtr<res::Material>(
|
||||
resBlockSet.pMaterialList, matOffsTbl[pResContent->materialIdx]);
|
||||
|
||||
mpMaterial = new (pMemMaterial) Material(pResMaterial, resBlockSet);
|
||||
}
|
||||
|
||||
mFrameNum = 0;
|
||||
mFrames = NULL;
|
||||
|
||||
if (pBlock->frameNum) {
|
||||
if ((mFrames = static_cast<Frame*>(
|
||||
Layout::AllocMemory(sizeof(*mFrames) * pBlock->frameNum))))
|
||||
{
|
||||
mFrameNum = pBlock->frameNum;
|
||||
const u32* frameOffsetTable =
|
||||
detail::ConvertOffsToPtr<u32>(pBlock, pBlock->frameOffsetTableOffset);
|
||||
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
const res::WindowFrame* pResWindowFrame =
|
||||
detail::ConvertOffsToPtr<res::WindowFrame>(pBlock, frameOffsetTable[i]);
|
||||
|
||||
mFrames[i].textureFlip = pResWindowFrame->textureFlip;
|
||||
mFrames[i].pMaterial = NULL;
|
||||
|
||||
if (void* pMemMaterial = Layout::AllocMemory(sizeof(Material))) {
|
||||
const res::Material* pResMaterial =
|
||||
detail::ConvertOffsToPtr<res::Material>(
|
||||
resBlockSet.pMaterialList,
|
||||
matOffsTbl[pResWindowFrame->materialIdx]);
|
||||
|
||||
mFrames[i].pMaterial =
|
||||
new (pMemMaterial) Material(pResMaterial, resBlockSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
if (mFrames) {
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
mFrames[i].pMaterial->~Material();
|
||||
Layout::FreeMemory(mFrames[i].pMaterial);
|
||||
}
|
||||
|
||||
Layout::FreeMemory(mFrames);
|
||||
}
|
||||
|
||||
if (mpMaterial && !mpMaterial->IsUserAllocated()) {
|
||||
mpMaterial->~Material();
|
||||
Layout::FreeMemory(mpMaterial);
|
||||
mpMaterial = NULL;
|
||||
}
|
||||
|
||||
mContent.texCoordAry.Free();
|
||||
}
|
||||
|
||||
Material* Window::FindMaterialByName(const char* findName, bool bRecursive) {
|
||||
if (mpMaterial && detail::EqualsMaterialName(mpMaterial->GetName(), findName)) {
|
||||
return mpMaterial;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
if (detail::EqualsMaterialName(mFrames[i].pMaterial->GetName(), findName)) {
|
||||
return mFrames[i].pMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
if (bRecursive) {
|
||||
for (PaneList::Iterator it = mChildList.GetBeginIter();
|
||||
it != mChildList.GetEndIter(); it++)
|
||||
{
|
||||
Material* pMat = it->FindMaterialByName(findName, true);
|
||||
if (pMat) {
|
||||
return pMat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AnimationLink* Window::FindAnimationLink(AnimTransform* pAnimTrans) {
|
||||
if (AnimationLink* ret = Pane::FindAnimationLink(pAnimTrans)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
if (AnimationLink* ret = mFrames[i].pMaterial->FindAnimationLink(pAnimTrans)) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Window::SetAnimationEnable(AnimTransform* pAnimTrans, bool bEnable, bool bRecursive) {
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
mFrames[i].pMaterial->SetAnimationEnable(pAnimTrans, bEnable);
|
||||
}
|
||||
|
||||
Pane::SetAnimationEnable(pAnimTrans, bEnable, bRecursive);
|
||||
}
|
||||
|
||||
ut::Color Window::GetVtxColor(u32 idx) const {
|
||||
NW4HBM_ASSERT(360, idx < VERTEXCOLOR_MAX);
|
||||
return mContent.vtxColors[idx];
|
||||
}
|
||||
|
||||
void Window::SetVtxColor(u32 idx, ut::Color value) {
|
||||
NW4HBM_ASSERT(371, idx < VERTEXCOLOR_MAX);
|
||||
mContent.vtxColors[idx] = value;
|
||||
}
|
||||
|
||||
u8 Window::GetVtxColorElement(u32 idx) const {
|
||||
return detail::GetVtxColorElement(mContent.vtxColors, idx);
|
||||
}
|
||||
|
||||
void Window::SetVtxColorElement(u32 idx, u8 value) {
|
||||
detail::SetVtxColorElement(mContent.vtxColors, idx, value);
|
||||
}
|
||||
|
||||
void Window::DrawSelf(const DrawInfo& drawInfo) {
|
||||
LoadMtx(drawInfo);
|
||||
WindowFrameSize frameSize = GetFrameSize(mFrameNum, mFrames);
|
||||
|
||||
math::VEC2 basePt = GetVtxPos();
|
||||
|
||||
DrawContent(basePt, frameSize, mGlbAlpha);
|
||||
|
||||
switch (mFrameNum) {
|
||||
case 1:
|
||||
DrawFrame(basePt, *mFrames, frameSize, mGlbAlpha);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
DrawFrame4(basePt, mFrames, frameSize, mGlbAlpha);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
DrawFrame8(basePt, mFrames, frameSize, mGlbAlpha);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Window::AnimateSelf(u32 option) {
|
||||
Pane::AnimateSelf(option);
|
||||
|
||||
if (detail::TestBit<>(mFlag, 0) || !(option & 1)) {
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
mFrames[i].pMaterial->Animate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::UnbindAnimationSelf(AnimTransform* pAnimTrans) {
|
||||
for (int i = 0; i < mFrameNum; i++) {
|
||||
mFrames[i].pMaterial->UnbindAnimation(pAnimTrans);
|
||||
}
|
||||
|
||||
Pane::UnbindAnimationSelf(pAnimTrans);
|
||||
}
|
||||
|
||||
void Window::DrawContent(const math::VEC2& basePt, const WindowFrameSize& frameSize,
|
||||
u8 alpha) {
|
||||
bool bUseVtxCol = mpMaterial->SetupGX(
|
||||
detail::IsModulateVertexColor(mContent.vtxColors, alpha), alpha);
|
||||
|
||||
detail::SetVertexFormat(bUseVtxCol, mContent.texCoordAry.GetSize());
|
||||
|
||||
// clang-format off
|
||||
detail::DrawQuad(
|
||||
math::VEC2(basePt.x + frameSize.l - mContentInflation.l,
|
||||
basePt.y + frameSize.t - mContentInflation.t),
|
||||
Size(mSize.width - frameSize.l + mContentInflation.l
|
||||
- frameSize.r + mContentInflation.r,
|
||||
mSize.height - frameSize.t + mContentInflation.t
|
||||
- frameSize.b + mContentInflation.b),
|
||||
mContent.texCoordAry.GetSize(),
|
||||
mContent.texCoordAry.GetArray(),
|
||||
bUseVtxCol ? mContent.vtxColors : NULL,
|
||||
alpha
|
||||
);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
void Window::DrawFrame(const math::VEC2& basePt, const Frame& frame,
|
||||
const WindowFrameSize& frameSize, u8 alpha) {
|
||||
bool bUseVtxCol =
|
||||
frame.pMaterial->SetupGX(detail::IsModulateVertexColor(NULL, alpha), alpha);
|
||||
detail::SetVertexFormat(bUseVtxCol, GX_TEXMAP1);
|
||||
|
||||
const Size texSize = detail::GetTextureSize(frame.pMaterial, GX_TEXMAP0);
|
||||
const ut::Color vtxColors[VERTEXCOLOR_MAX];
|
||||
|
||||
detail::TexCoords texCds[1];
|
||||
|
||||
math::VEC2 polPt;
|
||||
Size polSize;
|
||||
|
||||
#define DRAW_QUAD_FOR_FRAME_1(corner_, frameIdx_) \
|
||||
{ \
|
||||
Get##corner_##FrameSize(&polPt, &polSize, basePt, mSize, frameSize); \
|
||||
Get##corner_##TexCoord(*texCds, polSize, texSize, frameIdx_); \
|
||||
detail::DrawQuad(polPt, polSize, GX_TEXMAP1, texCds, bUseVtxCol ? vtxColors : NULL, \
|
||||
alpha); \
|
||||
}
|
||||
|
||||
DRAW_QUAD_FOR_FRAME_1(LT, TEXTUREFLIP_NONE);
|
||||
DRAW_QUAD_FOR_FRAME_1(RT, TEXTUREFLIP_H);
|
||||
DRAW_QUAD_FOR_FRAME_1(RB, TEXTUREFLIP_180);
|
||||
DRAW_QUAD_FOR_FRAME_1(LB, TEXTUREFLIP_V);
|
||||
|
||||
#undef DRAW_QUAD_FOR_FRAME_1
|
||||
}
|
||||
|
||||
void Window::DrawFrame4(const math::VEC2& basePt, const Frame* frames,
|
||||
const WindowFrameSize& frameSize, u8 alpha) {
|
||||
ut::Color vtxColors[4];
|
||||
detail::TexCoords texCds[1];
|
||||
math::VEC2 polPt;
|
||||
Size polSize;
|
||||
bool bModVtxCol = detail::IsModulateVertexColor(NULL, alpha);
|
||||
|
||||
#define DRAW_FRAME_4_QUAD_(corner_, frameIdx_) \
|
||||
do { \
|
||||
bool bUseVtxCol = frames[frameIdx_].pMaterial->SetupGX(bModVtxCol, alpha); \
|
||||
\
|
||||
Get##corner_##FrameSize(&polPt, &polSize, basePt, mSize, frameSize); \
|
||||
Get##corner_##TexCoord(*texCds, polSize, \
|
||||
detail::GetTextureSize(frames[frameIdx_].pMaterial, 0), \
|
||||
frames[frameIdx_].textureFlip); \
|
||||
\
|
||||
detail::SetVertexFormat(bUseVtxCol, 1); \
|
||||
\
|
||||
detail::DrawQuad(polPt, polSize, 1, texCds, bUseVtxCol ? vtxColors : NULL, alpha); \
|
||||
} while (0)
|
||||
|
||||
DRAW_FRAME_4_QUAD_(LT, 0);
|
||||
DRAW_FRAME_4_QUAD_(RT, 1);
|
||||
DRAW_FRAME_4_QUAD_(RB, 3);
|
||||
DRAW_FRAME_4_QUAD_(LB, 2);
|
||||
|
||||
#undef DRAW_FRAME_4_QUAD_
|
||||
}
|
||||
|
||||
void Window::DrawFrame8(const math::VEC2& basePt, const Frame* frames,
|
||||
const WindowFrameSize& frameSize, u8 alpha) {
|
||||
ut::Color vtxColors[4];
|
||||
detail::TexCoords texCds[1];
|
||||
Size polSize;
|
||||
bool bModVtxCol = detail::IsModulateVertexColor(NULL, alpha);
|
||||
|
||||
#define DRAW_FRAME_8_QUAD_(corner_, frameIdx_, polSizeInit_, basePtInit_) \
|
||||
do { \
|
||||
bool bUseVtxCol = frames[frameIdx_].pMaterial->SetupGX(bModVtxCol, alpha); \
|
||||
polSize = Size polSizeInit_; \
|
||||
\
|
||||
Get##corner_##TexCoord(*texCds, polSize, \
|
||||
detail::GetTextureSize(frames[frameIdx_].pMaterial, 0), \
|
||||
frames[frameIdx_].textureFlip); \
|
||||
\
|
||||
detail::SetVertexFormat(bUseVtxCol, 1); \
|
||||
\
|
||||
detail::DrawQuad(VEC_CTOR_ basePtInit_, polSize, 1, texCds, bUseVtxCol ? vtxColors : NULL, \
|
||||
alpha); \
|
||||
} while (0)
|
||||
|
||||
#define VEC_CTOR_ // avoid copy construction specifically for this first call
|
||||
DRAW_FRAME_8_QUAD_(LT, 0, (frameSize.l, frameSize.t), basePt);
|
||||
#undef VEC_CTOR_
|
||||
|
||||
#define VEC_CTOR_ math::VEC2
|
||||
|
||||
DRAW_FRAME_8_QUAD_(LT, 6, (mSize.width - frameSize.l - frameSize.r, frameSize.t),
|
||||
(basePt.x + frameSize.l, basePt.y));
|
||||
DRAW_FRAME_8_QUAD_(RT, 1, (frameSize.r, frameSize.t),
|
||||
(basePt.x + mSize.width - frameSize.r, basePt.y));
|
||||
DRAW_FRAME_8_QUAD_(RT, 5, (frameSize.r, mSize.height - frameSize.t - frameSize.b),
|
||||
(basePt.x + mSize.width - frameSize.r, basePt.y + frameSize.t));
|
||||
DRAW_FRAME_8_QUAD_(
|
||||
RB, 3, (frameSize.r, frameSize.b),
|
||||
(basePt.x + mSize.width - frameSize.r, basePt.y + mSize.height - frameSize.b));
|
||||
DRAW_FRAME_8_QUAD_(RB, 7, (mSize.width - frameSize.l - frameSize.r, frameSize.b),
|
||||
(basePt.x + frameSize.l, basePt.y + mSize.height - frameSize.b));
|
||||
DRAW_FRAME_8_QUAD_(LB, 2, (frameSize.l, frameSize.b),
|
||||
(basePt.x, basePt.y + mSize.height - frameSize.b));
|
||||
DRAW_FRAME_8_QUAD_(LB, 4, (frameSize.l, mSize.height - frameSize.t - frameSize.b),
|
||||
(basePt.x, basePt.y + frameSize.t));
|
||||
|
||||
#undef VEC_CTOR_
|
||||
#undef DRAW_FRAME_8_QUAD_
|
||||
}
|
||||
|
||||
WindowFrameSize Window::GetFrameSize(u8 frameNum, const Frame* frames) {
|
||||
WindowFrameSize ret = {};
|
||||
|
||||
switch (frameNum) {
|
||||
case 1: {
|
||||
Size texSize = detail::GetTextureSize(frames->pMaterial, 0);
|
||||
ret.l = texSize.width;
|
||||
ret.t = texSize.height;
|
||||
|
||||
ret.r = texSize.width;
|
||||
ret.b = texSize.height;
|
||||
} break;
|
||||
|
||||
case 4:
|
||||
case 8: {
|
||||
Size texSize = detail::GetTextureSize(frames[0].pMaterial, 0);
|
||||
ret.l = texSize.width;
|
||||
ret.t = texSize.height;
|
||||
|
||||
texSize = detail::GetTextureSize(frames[3].pMaterial, 0);
|
||||
ret.r = texSize.width;
|
||||
ret.b = texSize.height;
|
||||
} break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Material* Window::GetFrameMaterial(u32 frameIdx) const {
|
||||
NW4HBM_ASSERT(658, frameIdx < WINDOWFRAME_MAX);
|
||||
if (frameIdx >= mFrameNum) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mFrames[frameIdx].pMaterial;
|
||||
}
|
||||
|
||||
Material* Window::GetContentMaterial() const {
|
||||
return GetMaterial();
|
||||
}
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,154 @@
|
||||
#ifndef NW4HBM_LYT_MATERIAL_H
|
||||
#define NW4HBM_LYT_MATERIAL_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/tpl.h>
|
||||
#include <revolution/gx.h>
|
||||
|
||||
#include "animation.h"
|
||||
#include "lyt_types.h"
|
||||
#include "resources.h"
|
||||
|
||||
#include "../ut/Color.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
class Material;
|
||||
|
||||
namespace detail {
|
||||
typedef struct BitGXNums {
|
||||
u32 texMap : 4; // 11110000000000000000000000000000
|
||||
u32 texSRT : 4; // 00001111000000000000000000000000
|
||||
u32 texCoordGen : 4; // 00000000111100000000000000000000
|
||||
u32 indSRT : 2; // 00000000000011000000000000000000
|
||||
u32 indStage : 3; // 00000000000000111000000000000000
|
||||
u32 tevSwap : 1; // 00000000000000000100000000000000
|
||||
u32 tevStage : 5; // 00000000000000000011111000000000
|
||||
u32 chanCtrl : 1; // 00000000000000000000000100000000
|
||||
u32 matCol : 1; // 00000000000000000000000010000000
|
||||
u32 alpComp : 1; // 00000000000000000000000001000000
|
||||
u32 blendMode : 1; // 00000000000000000000000000100000
|
||||
} BitGXNums;
|
||||
Size GetTextureSize(Material* pMaterial, u8 texMapIdx);
|
||||
} // namespace detail
|
||||
|
||||
class Material {
|
||||
public:
|
||||
Material();
|
||||
Material(const res::Material* pRes, const ResBlockSet& resBlockSet);
|
||||
|
||||
/* 0x08 */ virtual ~Material();
|
||||
/* 0x0C */ virtual bool SetupGX(bool bModVtxCol, u8 alpha);
|
||||
/* 0x10 */ virtual void BindAnimation(AnimTransform* animTrans);
|
||||
/* 0x14 */ virtual void UnbindAnimation(AnimTransform* animTrans);
|
||||
/* 0x18 */ virtual void UnbindAllAnimation();
|
||||
/* 0x1C */ virtual void Animate();
|
||||
/* 0x20 */ virtual AnimationLink* FindAnimationLink(AnimTransform* animTrans);
|
||||
/* 0x24 */ virtual void SetAnimationEnable(AnimTransform* animTrans, bool bEnable);
|
||||
|
||||
const char* GetName() const { return mName; }
|
||||
GXColorS10 GetTevColor(u32 idx) const { return mTevCols[idx]; }
|
||||
|
||||
u8 GetTextureCap() const { return mGXMemCap.texMap; }
|
||||
|
||||
u8 GetTexSRTCap() const { return mGXMemCap.texSRT; }
|
||||
|
||||
u8 GetTexCoordGenCap() const { return mGXMemCap.texCoordGen; }
|
||||
|
||||
u8 GetIndTexSRTCap() const { return mGXMemCap.indSRT; }
|
||||
|
||||
bool IsTevSwapCap() const { return static_cast<bool>(mGXMemCap.tevSwap); }
|
||||
bool IsBlendModeCap() const { return static_cast<bool>(mGXMemCap.blendMode); }
|
||||
bool IsAlphaCompareCap() const { return static_cast<bool>(mGXMemCap.alpComp); }
|
||||
|
||||
bool IsMatColorCap() const { return static_cast<bool>(mGXMemCap.matCol); }
|
||||
bool IsChanCtrlCap() const { return static_cast<bool>(mGXMemCap.chanCtrl); }
|
||||
|
||||
u8 GetTextureNum() const { return mGXMemNum.texMap; }
|
||||
|
||||
bool IsUserAllocated() const { return mbUserAllocated; }
|
||||
|
||||
void SetName(const char* name);
|
||||
|
||||
const GXTexObj* GetTexMapAry() const;
|
||||
const TexSRT* GetTexSRTAry() const;
|
||||
const TexCoordGen* GetTexCoordGenAry() const;
|
||||
const ChanCtrl* GetChanCtrlAry() const;
|
||||
const ut::Color* GetMatColAry() const;
|
||||
const TevSwapMode* GetTevSwapAry() const;
|
||||
const AlphaCompare* GetAlphaComparePtr() const;
|
||||
const BlendMode* GetBlendModePtr() const;
|
||||
const IndirectStage* GetIndirectStageAry() const;
|
||||
const TexSRT* GetIndTexSRTAry() const;
|
||||
const TevStage* GetTevStageAry() const;
|
||||
|
||||
GXTexObj* GetTexMapAry();
|
||||
TexSRT* GetTexSRTAry();
|
||||
TexCoordGen* GetTexCoordGenAry();
|
||||
ChanCtrl* GetChanCtrlAry();
|
||||
ut::Color* GetMatColAry();
|
||||
TevSwapMode* GetTevSwapAry();
|
||||
AlphaCompare* GetAlphaComparePtr();
|
||||
BlendMode* GetBlendModePtr();
|
||||
IndirectStage* GetIndirectStageAry();
|
||||
TexSRT* GetIndTexSRTAry();
|
||||
TevStage* GetTevStageAry();
|
||||
|
||||
void GetTexture(GXTexObj* pTexObj, u8 texMapIdx) const;
|
||||
|
||||
void SetTextureNum(u8 num);
|
||||
void SetTexCoordGenNum(u8 num);
|
||||
void SetIndStageNum(u8 num);
|
||||
void SetTevStageNum(u8 num);
|
||||
|
||||
void SetTexture(u8 texMapIdx, const GXTexObj& texObj);
|
||||
void SetTexture(u8 texMapIdx, TPLPalette* pTplRes);
|
||||
void SetTextureNoWrap(u8 texMapIdx, TPLPalette* pTplRes);
|
||||
|
||||
void SetColorElement(u32 colorType, s16 value);
|
||||
|
||||
void SetTexCoordGen(u32 idx, TexCoordGen value) {
|
||||
NW4HBM_ASSERT(180, idx < mGXMemNum.texCoordGen);
|
||||
GetTexCoordGenAry()[idx] = value;
|
||||
}
|
||||
|
||||
void SetTexSRTElement(u32 texSRTIdx, u32 eleIdx, f32 value) {
|
||||
NW4HBM_ASSERT(293, texSRTIdx < mGXMemNum.texSRT);
|
||||
f32* srtAry = reinterpret_cast<f32*>(&GetTexSRTAry()[texSRTIdx]);
|
||||
srtAry[eleIdx] = value;
|
||||
}
|
||||
|
||||
void SetIndTexSRTElement(u32 texSRTIdx, u32 eleIdx, f32 value) {
|
||||
NW4HBM_ASSERT(309, texSRTIdx < mGXMemNum.indSRT);
|
||||
f32* srtAry = reinterpret_cast<f32*>(&GetIndTexSRTAry()[texSRTIdx]);
|
||||
srtAry[eleIdx] = value;
|
||||
}
|
||||
|
||||
void Init();
|
||||
void InitBitGXNums(detail::BitGXNums* ptr);
|
||||
|
||||
void ReserveGXMem(u8 texMapNum, u8 texSRTNum, u8 texCoordGenNum, u8 tevStageNum,
|
||||
bool allocTevSwap, u8 indStageNum, u8 indSRTNum, bool allocChanCtrl,
|
||||
bool allocMatCol, bool allocAlpComp, bool allocBlendMode);
|
||||
|
||||
void AddAnimationLink(AnimationLink* animationLink);
|
||||
|
||||
private:
|
||||
static const int MAX_TEX_SRT = (GX_TEXMTX9 - GX_TEXMTX0) / 3 + 1;
|
||||
static const int MAX_IND_SRT = (GX_ITM_2 - GX_ITM_0) + 1;
|
||||
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ char mName[20];
|
||||
/* 0x18 */ AnimationLinkList mAnimList;
|
||||
/* 0x24 */ GXColorS10 mTevCols[TEVCOLOR_MAX];
|
||||
/* 0x3C */ ut::Color mTevKCols[GX_MAX_KCOLOR];
|
||||
/* 0x4C */ detail::BitGXNums mGXMemCap;
|
||||
/* 0x50 */ detail::BitGXNums mGXMemNum;
|
||||
/* 0x54 */ bool mbUserAllocated;
|
||||
/* 0x58 */ void* mpGXMem;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,175 @@
|
||||
#ifndef NW4HBM_LYT_PANE_H
|
||||
#define NW4HBM_LYT_PANE_H
|
||||
|
||||
#include "revolution/types.h"
|
||||
|
||||
#include "../ut/Color.h"
|
||||
#include "../ut/LinkList.h"
|
||||
#include "../ut/Rect.h"
|
||||
#include "../ut/RuntimeTypeInfo.h"
|
||||
|
||||
#include "../db/assert.h"
|
||||
|
||||
#include "../math/types.h"
|
||||
|
||||
#include "animation.h"
|
||||
#include "drawInfo.h"
|
||||
#include "lyt_types.h"
|
||||
#include "material.h"
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
class Pane;
|
||||
|
||||
namespace detail {
|
||||
class PaneBase {
|
||||
public:
|
||||
inline PaneBase() : mLink() {}
|
||||
|
||||
/* 0x08 */ virtual ~PaneBase() {}
|
||||
|
||||
/* 0x00 (vtable) */
|
||||
/* 0x04 */ ut::LinkListNode mLink;
|
||||
};
|
||||
} // namespace detail
|
||||
typedef ut::LinkList<Pane, offsetof(detail::PaneBase, mLink)> PaneList;
|
||||
|
||||
enum {
|
||||
/* 1 */ ANIMOPTION_SKIP_INVISIBLE = (1 << 0),
|
||||
};
|
||||
|
||||
class Pane : detail::PaneBase {
|
||||
private:
|
||||
enum {
|
||||
/* 0 */ BIT_VISIBLE = 0,
|
||||
/* 1 */ BIT_INFLUENCED_ALPHA,
|
||||
/* 2 */ BIT_LOCATION_ADJUST
|
||||
};
|
||||
|
||||
public:
|
||||
Pane();
|
||||
Pane(const res::Pane* pBlock);
|
||||
|
||||
/* 0x08 */ virtual ~Pane();
|
||||
/* 0x0C */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x10 */ virtual void CalculateMtx(const DrawInfo& drawInfo);
|
||||
/* 0x14 */ virtual void Draw(const DrawInfo& drawInfo);
|
||||
/* 0x18 */ virtual void DrawSelf(const DrawInfo& drawInfo);
|
||||
/* 0x1C */ virtual void Animate(u32 option = 0);
|
||||
/* 0x20 */ virtual void AnimateSelf(u32 option = 0);
|
||||
/* 0x24 */ virtual ut::Color GetVtxColor(u32 idx) const;
|
||||
/* 0x28 */ virtual void SetVtxColor(u32 idx, ut::Color valuw);
|
||||
/* 0x2C */ virtual u8 GetColorElement(u32 idx) const;
|
||||
/* 0x30 */ virtual void SetColorElement(u32 idx, u8 color);
|
||||
/* 0x34 */ virtual u8 GetVtxColorElement(u32 idx) const;
|
||||
/* 0x38 */ virtual void SetVtxColorElement(u32 idx, u8 element);
|
||||
/* 0x3C */ virtual Pane* FindPaneByName(const char* findName, bool bRecursive = true);
|
||||
/* 0x40 */ virtual Material* FindMaterialByName(const char* findName,
|
||||
bool bRecursive = true);
|
||||
/* 0x44 */ virtual void BindAnimation(AnimTransform* animTrans, bool bRecursive = true);
|
||||
/* 0x48 */ virtual void UnbindAnimation(AnimTransform* animTrans,
|
||||
bool bRecursive = true);
|
||||
/* 0x4C */ virtual void UnbindAllAnimation(bool bRecursive = true);
|
||||
/* 0x50 */ virtual void UnbindAnimationSelf(AnimTransform* animTrans);
|
||||
/* 0x54 */ virtual AnimationLink* FindAnimationLink(AnimTransform* animTrans);
|
||||
/* 0x58 */ virtual void SetAnimationEnable(AnimTransform* animTrans, bool bEnable,
|
||||
bool bRecursive = true);
|
||||
/* 0x5C */ virtual Material* GetMaterial() const;
|
||||
/* 0x60 */ virtual void LoadMtx(const DrawInfo& drawInfo);
|
||||
|
||||
Pane* GetParent() const { return mpParent; }
|
||||
PaneList& GetChildList() { return mChildList; }
|
||||
|
||||
const math::VEC3& GetTranslate() { return mTranslate; }
|
||||
void SetTranslate(const math::VEC3& translate) { mTranslate = translate; }
|
||||
void SetTranslate(const math::VEC2& translate) {
|
||||
SetTranslate(math::VEC3(translate.x, translate.y, 0.0f));
|
||||
}
|
||||
|
||||
const math::VEC3& GetRotate() const { return mRotate; }
|
||||
void SetRotate(const math::VEC3& rotate) { mRotate = rotate; }
|
||||
|
||||
const math::VEC2& GetScale() const { return mScale; }
|
||||
void SetScale(const math::VEC2& scale) { mScale = scale; }
|
||||
|
||||
const Size& GetSize() const { return mSize; }
|
||||
void SetSize(const Size& size) { mSize = size; }
|
||||
|
||||
bool IsVisible() { return detail::TestBit(mFlag, BIT_VISIBLE); };
|
||||
void SetVisible(bool visible) { detail::SetBit(&mFlag, BIT_VISIBLE, visible); };
|
||||
|
||||
bool IsInfluencedAlpha() { return detail::TestBit(mFlag, BIT_INFLUENCED_ALPHA); };
|
||||
void SetInfluencedAlpha(bool visible) {
|
||||
detail::SetBit(&mFlag, BIT_INFLUENCED_ALPHA, visible);
|
||||
};
|
||||
|
||||
bool IsLocationAdjust() { return detail::TestBit(mFlag, BIT_LOCATION_ADJUST); };
|
||||
void SetLocationAdjust(bool visible) {
|
||||
detail::SetBit(&mFlag, BIT_LOCATION_ADJUST, visible);
|
||||
};
|
||||
|
||||
const math::MTX34& GetGlobalMtx() const { return mGlbMtx; }
|
||||
void SetGlobalMtx(const math::MTX34& mtx) { mGlbMtx = mtx; }
|
||||
|
||||
const math::MTX34& GetMtx() const { return mMtx; }
|
||||
void SetMtx(const math::MTX34& mtx) { mMtx = mtx; }
|
||||
|
||||
u8 GetAlpha() { return mAlpha; }
|
||||
void SetAlpha(u8 alpha) { mAlpha = alpha; }
|
||||
|
||||
const char* GetName() const { return mName; }
|
||||
|
||||
void SetSRTElement(u32 idx, f32 value) {
|
||||
NW4HBM_ASSERT(250, idx < ANIMTARGET_PANE_MAX);
|
||||
reinterpret_cast<f32*>(&mTranslate)[idx] = value;
|
||||
}
|
||||
|
||||
bool IsUserAllocated() const { return mbUserAllocated; }
|
||||
|
||||
const ut::Rect GetPaneRect(const DrawInfo& drawInfo) const;
|
||||
|
||||
math::VEC2 GetVtxPos() const;
|
||||
|
||||
void SetName(const char* name);
|
||||
void SetUserData(const char* userData);
|
||||
|
||||
void Init();
|
||||
|
||||
void InsertChild(PaneList::Iterator next, Pane* pChild);
|
||||
void InsertChild(Pane* pNext, Pane* pChild);
|
||||
|
||||
void PrependChild(Pane* pChild);
|
||||
void AppendChild(Pane* pChild);
|
||||
|
||||
void RemoveChild(Pane* pChild);
|
||||
|
||||
void CalculateMtxChild(const DrawInfo& drawInfo);
|
||||
|
||||
void AddAnimationLink(AnimationLink* animationLink);
|
||||
|
||||
protected:
|
||||
/* 0x00 (base) */
|
||||
/* 0x0C */ Pane* mpParent;
|
||||
/* 0x10 */ PaneList mChildList;
|
||||
/* 0x1C */ AnimationLinkList mAnimList;
|
||||
/* 0x28 */ Material* mpMaterial;
|
||||
/* 0x2C */ math::VEC3 mTranslate;
|
||||
/* 0x38 */ math::VEC3 mRotate;
|
||||
/* 0x44 */ math::VEC2 mScale;
|
||||
/* 0x4C */ Size mSize;
|
||||
/* 0x54 */ math::MTX34 mMtx;
|
||||
/* 0x84 */ math::MTX34 mGlbMtx;
|
||||
/* 0xB4 */ char mName[16];
|
||||
/* 0xC4 */ char mUserData[8];
|
||||
/* 0xCC */ u8 mBasePosition;
|
||||
/* 0xCD */ u8 mAlpha;
|
||||
/* 0xCE */ u8 mGlbAlpha;
|
||||
/* 0xCF */ u8 mFlag;
|
||||
/* 0xD0 */ bool mbUserAllocated;
|
||||
}; // size = 0xD4
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef NW4HBM_LYT_PICTURE_H
|
||||
#define NW4HBM_LYT_PICTURE_H
|
||||
|
||||
#include "pane.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class Picture : public Pane {
|
||||
public:
|
||||
Picture(u8 num);
|
||||
Picture(const res::Picture* pResPic, const ResBlockSet& resBlockSet);
|
||||
|
||||
/* 0x08 */ virtual ~Picture();
|
||||
/* 0x0C */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x18 */ virtual void DrawSelf(const DrawInfo& drawInfo);
|
||||
/* 0x24 */ virtual ut::Color GetVtxColor(u32 idx) const;
|
||||
/* 0x28 */ virtual void SetVtxColor(u32 idx, ut::Color value);
|
||||
/* 0x34 */ virtual u8 GetVtxColorElement(u32 idx) const;
|
||||
/* 0x38 */ virtual void SetVtxColorElement(u32 idx, u8 value);
|
||||
/* 0x64 */ virtual void Append(TPLPalette* pTplRes);
|
||||
/* 0x68 */ virtual void Append(const GXTexObj& texObj);
|
||||
|
||||
void SetTexCoordNum(u8 num);
|
||||
u8 GetTexCoordNum() const;
|
||||
|
||||
void GetTexCoord(u32 idx, math::VEC2* coords) const;
|
||||
void SetTexCoord(u32 idx, const math::VEC2* coords);
|
||||
|
||||
void Init(u8 texNum);
|
||||
void ReserveTexCoord(u8 num);
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0xD4 */ ut::Color mVtxColors[VERTEXCOLOR_MAX] ATTRIBUTE_ALIGN(4);
|
||||
/* 0xE4 */ detail::TexCoordAry mTexCoordAry;
|
||||
};
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef NW4HBM_LYT_RESOURCE_ACCESSOR_H
|
||||
#define NW4HBM_LYT_RESOURCE_ACCESSOR_H
|
||||
|
||||
#include "revolution/types.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
|
||||
namespace ut {
|
||||
class Font;
|
||||
}
|
||||
|
||||
namespace lyt {
|
||||
class ResourceAccessor {
|
||||
public:
|
||||
ResourceAccessor();
|
||||
|
||||
/* 0x08 */ virtual ~ResourceAccessor();
|
||||
/* 0x0C */ virtual void* GetResource(u32 resType, const char* name, u32* pSize) = 0;
|
||||
/* 0x10 */ virtual ut::Font* GetFont(const char* name);
|
||||
|
||||
/* 0x00 (vtable) */
|
||||
}; // size = 0x04
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,292 @@
|
||||
#ifndef NW4HBM_LYT_RESOURCES_H
|
||||
#define NW4HBM_LYT_RESOURCES_H
|
||||
|
||||
#include <revolution/gx.h>
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "../ut/binaryFileFormat.h"
|
||||
|
||||
#include "lyt_types.h"
|
||||
#include "resourceAccessor.h"
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
typedef struct InflationLRTB {
|
||||
/* 0x00 */ f32 l;
|
||||
/* 0x04 */ f32 r;
|
||||
/* 0x08 */ f32 t;
|
||||
/* 0x0C */ f32 b;
|
||||
} InflationLRTB;
|
||||
|
||||
typedef struct WindowFrameSize {
|
||||
/* 0x00 */ f32 l;
|
||||
/* 0x04 */ f32 r;
|
||||
/* 0x08 */ f32 t;
|
||||
/* 0x0C */ f32 b;
|
||||
} WindowFrameSize;
|
||||
|
||||
class MaterialResourceNum {
|
||||
public:
|
||||
u8 GetTexMapNum() const { return detail::GetBits<>(bits, 0, 4); }
|
||||
u8 GetTexSRTNum() const { return detail::GetBits<>(bits, 4, 4); }
|
||||
u8 GetTexCoordGenNum() const { return detail::GetBits<>(bits, 8, 4); }
|
||||
bool HasTevSwapTable() const { return detail::TestBit<>(bits, 12); }
|
||||
u8 GetIndTexSRTNum() const { return detail::GetBits<>(bits, 13, 2); }
|
||||
u8 GetIndTexStageNum() const { return detail::GetBits<>(bits, 15, 3); }
|
||||
u8 GetTevStageNum() const { return detail::GetBits<>(bits, 18, 5); }
|
||||
bool HasAlphaCompare() const { return detail::TestBit<>(bits, 23); }
|
||||
bool HasBlendMode() const { return detail::TestBit<>(bits, 24); }
|
||||
u8 GetChanCtrlNum() const { return detail::GetBits<>(bits, 25, 1); }
|
||||
u8 GetMatColNum() const { return detail::GetBits<>(bits, 27, 1); }
|
||||
|
||||
private:
|
||||
/* 0x00 */ u32 bits;
|
||||
}; // size = 0x04
|
||||
|
||||
namespace res {
|
||||
|
||||
/*** COMMON ***/
|
||||
|
||||
typedef struct BinaryFileHeader {
|
||||
/* 0x00 */ char signature[4];
|
||||
/* 0x04 */ u16 byteOrder;
|
||||
/* 0x06 */ u16 version;
|
||||
/* 0x08 */ u32 fileSize;
|
||||
/* 0x0C */ u16 headerSize;
|
||||
/* 0x0E */ u16 dataBlocks;
|
||||
} BinaryFileHeader; // size = 0x10
|
||||
|
||||
typedef struct DataBlockHeader {
|
||||
/* 0x00 */ char kind[4];
|
||||
/* 0x04 */ u32 size;
|
||||
} DataBlockHeader; // size = 0x08
|
||||
|
||||
/*** ANIMATION ***/
|
||||
|
||||
typedef struct StepKey {
|
||||
/* 0x00 */ f32 frame;
|
||||
/* 0x04 */ u16 value;
|
||||
/* 0x06 */ u16 padding;
|
||||
} StepKey; // size = 0x08
|
||||
|
||||
typedef struct HermiteKey {
|
||||
/* 0x00 */ f32 frame;
|
||||
/* 0x04 */ f32 value;
|
||||
/* 0x08 */ f32 slope;
|
||||
} HermiteKey; // size = 0x0C
|
||||
|
||||
typedef struct AnimationInfo {
|
||||
public:
|
||||
/* 0x00 */ u32 kind;
|
||||
/* 0x04 */ u8 num;
|
||||
/* 0x05 */ u8 padding[3];
|
||||
|
||||
public:
|
||||
static const u32 ANIM_INFO_PANE_PAIN_SRT = 'RLPA';
|
||||
static const u32 ANIM_INFO_PANE_VERTEX_COLOR = 'RLVC';
|
||||
static const u32 ANIM_INFO_PANE_VISIBILITY = 'RLVI';
|
||||
|
||||
static const u32 ANIM_INFO_MATERIAL_COLOR = 'RLMC';
|
||||
static const u32 ANIM_INFO_MATERIAL_TEXTURE_PATTERN = 'RLTP';
|
||||
static const u32 ANIM_INFO_MATERIAL_TEXTURE_SRT = 'RLTS';
|
||||
static const u32 ANIM_INFO_MATERIAL_IND_TEX_SRT = 'RLIM';
|
||||
} AnimationInfo;
|
||||
|
||||
typedef struct AnimationTarget {
|
||||
/* 0x00 */ u8 id;
|
||||
/* 0x01 */ u8 target;
|
||||
/* 0x02 */ u8 curveType;
|
||||
/* 0x03 */ u8 padding1;
|
||||
/* 0x04 */ u16 keyNum;
|
||||
/* 0x06 */ u8 padding2[2];
|
||||
/* 0x08 */ u32 keysOffset;
|
||||
} AnimationTarget; // size = 0x10
|
||||
|
||||
typedef struct AnimationBlock {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u16 frameSize;
|
||||
/* 0x0A */ u8 loop;
|
||||
/* 0x0B */ u8 padding1;
|
||||
/* 0x0C */ u16 fileNum;
|
||||
/* 0x0E */ u16 animContNum;
|
||||
/* 0x10 */ u32 animContOffsetsOffset;
|
||||
} AnimationBlock; // size = 0x14
|
||||
|
||||
typedef struct AnimationContent {
|
||||
public:
|
||||
enum {
|
||||
/* 0 */ ACType_Pane = 0,
|
||||
/* 1 */ ACType_Material,
|
||||
/* 2 */ ACType_Max
|
||||
};
|
||||
|
||||
public:
|
||||
/* 0x00 */ char name[20];
|
||||
/* 0x14 */ u8 num;
|
||||
/* 0x15 */ u8 type;
|
||||
/* 0x16 */ u8 padding[2];
|
||||
} AnimationContent; // size = 0x18
|
||||
|
||||
/*** MATERIAL ***/
|
||||
|
||||
typedef struct Texture {
|
||||
/* 0x00 */ u32 nameStrOffset;
|
||||
/* 0x04 */ u8 type;
|
||||
/* 0x05 */ u8 padding[3];
|
||||
} Texture; // size = 0x08
|
||||
|
||||
typedef struct Material {
|
||||
/* 0x00 */ char name[20];
|
||||
/* 0x14 */ GXColorS10 tevCols[TEVCOLOR_MAX];
|
||||
/* 0x2C */ GXColor tevKCols[GX_MAX_KCOLOR];
|
||||
/* 0x3C */ MaterialResourceNum resNum;
|
||||
} Material; // size = 0x40
|
||||
|
||||
typedef struct TexMap {
|
||||
/* 0x00 */ u16 texIdx;
|
||||
/* 0x02 */ u8 wrapS;
|
||||
/* 0x03 */ u8 wrapT;
|
||||
} TexMap; // size = 0x04
|
||||
|
||||
/*** PANES ***/
|
||||
|
||||
static const u32 FILE_HEADER_SIGNATURE_ANIMATION = 'RLAN';
|
||||
static const u32 FILE_HEADER_SIGNATURE_LAYOUT = 'RLYT';
|
||||
|
||||
static const u32 OBJECT_SIGNATURE_LAYOUT = 'lyt1';
|
||||
static const u32 OBJECT_SIGNATURE_FONT_LIST = 'fnl1';
|
||||
static const u32 OBJECT_SIGNATURE_MATERIAL_LIST = 'mat1';
|
||||
static const u32 OBJECT_SIGNATURE_TEXTURE_LIST = 'txl1';
|
||||
static const u32 OBJECT_SIGNATURE_PANE = 'pan1';
|
||||
static const u32 OBJECT_SIGNATURE_PANE_CHILD_START = 'pas1';
|
||||
static const u32 OBJECT_SIGNATURE_PANE_CHILD_END = 'pae1';
|
||||
static const u32 OBJECT_SIGNATURE_PICTURE = 'pic1';
|
||||
static const u32 OBJECT_SIGNATURE_BOUNDING = 'bnd1';
|
||||
static const u32 OBJECT_SIGNATURE_WINDOW = 'wnd1';
|
||||
static const u32 OBJECT_SIGNATURE_TEXT_BOX = 'txt1';
|
||||
static const u32 OBJECT_SIGNATURE_GROUP = 'grp1';
|
||||
static const u32 OBJECT_SIGNATURE_GROUP_CHILD_START = 'grs1';
|
||||
static const u32 OBJECT_SIGNATURE_GROUP_CHILD_END = 'gre1';
|
||||
static const u32 OBJECT_SIGNATURE_PANE_ANIM = 'pai1';
|
||||
|
||||
typedef struct Pane {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u8 flag;
|
||||
/* 0x09 */ u8 basePosition;
|
||||
/* 0x0A */ u8 alpha;
|
||||
/* 0x0B */ u8 padding;
|
||||
/* 0x0C */ char name[16];
|
||||
/* 0x1C */ char userData[8];
|
||||
/* 0x24 */ math::VEC3 translate;
|
||||
/* 0x30 */ math::VEC3 rotate;
|
||||
/* 0x3C */ math::VEC2 scale;
|
||||
/* 0x44 */ Size size;
|
||||
} Pane; // size = 0x4C
|
||||
|
||||
typedef struct Bounding : Pane {
|
||||
// (empty)
|
||||
} Bounding;
|
||||
|
||||
typedef struct Picture : public Pane {
|
||||
/* 0x4C */ u32 vtxCols[4];
|
||||
/* 0x5C */ u16 materialIdx;
|
||||
/* 0x5E */ u8 texCoordNum;
|
||||
/* 0x5F */ u8 padding[1];
|
||||
} Picture;
|
||||
|
||||
typedef struct Font {
|
||||
/* 0x00 */ u32 nameStrOffset;
|
||||
/* 0x04 */ u8 type;
|
||||
u8 padding[3];
|
||||
} Font;
|
||||
|
||||
typedef struct TextBox : public Pane {
|
||||
/* 0x4C */ u16 textBufBytes;
|
||||
/* 0x4E */ u16 textStrBytes;
|
||||
/* 0x50 */ u16 materialIdx;
|
||||
/* 0x52 */ u16 fontIdx;
|
||||
/* 0x54 */ u8 textPosition;
|
||||
u8 padding[3];
|
||||
/* 0x58 */ u32 textStrOffset;
|
||||
/* 0x5C */ u32 textCols[TEXTCOLOR_MAX];
|
||||
/* 0x64 */ Size fontSize;
|
||||
/* 0x6C */ f32 charSpace;
|
||||
/* 0x70 */ f32 lineSpace;
|
||||
} TextBox;
|
||||
|
||||
typedef struct WindowFrame {
|
||||
/* 0x00 */ u16 materialIdx;
|
||||
/* 0x02 */ u8 textureFlip;
|
||||
/* 0x03 */ u8 padding1;
|
||||
} WindowFrame;
|
||||
|
||||
typedef struct WindowContent {
|
||||
/* 0x00 */ u32 vtxCols[VERTEXCOLOR_MAX];
|
||||
/* 0x10 */ u16 materialIdx;
|
||||
/* 0x12 */ u8 texCoordNum;
|
||||
/* 0x13 */ u8 padding[1];
|
||||
} WindowContent;
|
||||
|
||||
typedef struct Window : public Pane {
|
||||
/* 0x4C */ InflationLRTB inflation;
|
||||
/* 0x5C */ u8 frameNum;
|
||||
/* 0x5D */ u8 padding1;
|
||||
/* 0x5E */ u8 padding2;
|
||||
/* 0x5F */ u8 padding3;
|
||||
/* 0x60 */ u32 contentOffset;
|
||||
/* 0x64 */ u32 frameOffsetTableOffset;
|
||||
} Window;
|
||||
|
||||
/*** GROUP ***/
|
||||
|
||||
typedef struct Group {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ char name[16];
|
||||
/* 0x18 */ u16 paneNum;
|
||||
/* 0x19 */ u8 padding[2];
|
||||
} Group;
|
||||
|
||||
/*** LAYOUT ***/
|
||||
|
||||
typedef struct Layout {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u8 originType;
|
||||
/* 0x09 */ u8 padding[3];
|
||||
/* 0x0C */ Size layoutSize;
|
||||
} Layout;
|
||||
|
||||
} // namespace res
|
||||
|
||||
namespace res {
|
||||
typedef struct TextureList {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u16 texNum;
|
||||
u8 padding[2];
|
||||
} TextureList;
|
||||
|
||||
typedef struct FontList {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u16 fontNum;
|
||||
u8 padding[2];
|
||||
} FontList;
|
||||
|
||||
typedef struct MaterialList {
|
||||
/* 0x00 */ DataBlockHeader blockHeader;
|
||||
/* 0x08 */ u16 materialNum;
|
||||
u8 padding[2];
|
||||
} MaterialList;
|
||||
} // namespace res
|
||||
|
||||
typedef struct ResBlockSet {
|
||||
/* 0x00 */ const res::TextureList* pTextureList;
|
||||
/* 0x04 */ const res::FontList* pFontList;
|
||||
/* 0x08 */ const res::MaterialList* pMaterialList;
|
||||
/* 0x0C */ ResourceAccessor* pResAccessor;
|
||||
} ResBlockSet;
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef NW4HBM_LYT_TEXTBOX_H
|
||||
#define NW4HBM_LYT_TEXTBOX_H
|
||||
|
||||
#include "common.h"
|
||||
#include "pane.h"
|
||||
|
||||
#include "../ut/RuntimeTypeInfo.h"
|
||||
#include "../ut/TagProcessorBase.h"
|
||||
#include "../ut/WideTagProcessor.h"
|
||||
#include "../ut/WideTextWriter.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class TextBox : public Pane {
|
||||
public:
|
||||
TextBox(u16 allocStrLen, const wchar_t* str, const ut::Font* pFont);
|
||||
TextBox(const res::TextBox* pBlock, const ResBlockSet& resBlockSet);
|
||||
|
||||
/* 0x08 */ virtual ~TextBox();
|
||||
/* 0x0C */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x18 */ virtual void DrawSelf(const DrawInfo& drawInfo);
|
||||
/* 0x24 */ virtual ut::Color GetVtxColor(u32 idx) const;
|
||||
/* 0x28 */ virtual void SetVtxColor(u32 idx, ut::Color value);
|
||||
/* 0x34 */ virtual u8 GetVtxColorElement(u32 idx) const;
|
||||
/* 0x38 */ virtual void SetVtxColorElement(u32 idx, u8 value);
|
||||
/* 0x64 */ virtual void AllocStringBuffer(u16 size);
|
||||
/* 0x68 */ virtual void FreeStringBuffer();
|
||||
/* 0x6C */ virtual u16 SetString(const wchar_t* str, u16 dstIdx = 0);
|
||||
/* 0x70 */ virtual u16 SetString(const wchar_t* str, u16 dstIdx, u16 strLen);
|
||||
|
||||
const Size& GetFontSize() const { return mFontSize; }
|
||||
|
||||
void SetFontSize(const Size& fontSize) { mFontSize = fontSize; }
|
||||
void SetTagProcessor(ut::WideTagProcessor* pTagProcessor) { mpTagProcessor = pTagProcessor; }
|
||||
|
||||
u16 GetStringBufferLength() const;
|
||||
|
||||
f32 GetTextMagH() const;
|
||||
f32 GetTextMagV() const;
|
||||
|
||||
u8 GetTextPositionH() const { return detail::GetHorizontalPosition(mTextPosition); }
|
||||
u8 GetTextPositionV() const { return detail::GetVerticalPosition(mTextPosition); }
|
||||
|
||||
const ut::Color GetTextColor(u32 type) const {
|
||||
NW4HBM_ASSERT(95, type < TEXTCOLOR_MAX);
|
||||
return mTextColors[type];
|
||||
}
|
||||
|
||||
void SetTextColor(u32 type, ut::Color value) {
|
||||
NW4HBM_ASSERT(96, type < TEXTCOLOR_MAX);
|
||||
mTextColors[type] = value;
|
||||
}
|
||||
|
||||
void SetTextPositionH(u8 pos) { detail::SetHorizontalPosition(&mTextPosition, pos); }
|
||||
void SetTextPositionV(u8 pos) { detail::SetVerticalPosition(&mTextPosition, pos); }
|
||||
|
||||
const ut::Font* GetFont() const;
|
||||
void SetFont(const ut::Font* pFont);
|
||||
|
||||
void Init(u16 allocStrLen);
|
||||
|
||||
const ut::Rect GetTextDrawRect(const DrawInfo& drawInfo) const;
|
||||
const ut::Rect GetTextDrawRect(ut::WideTextWriter* pWriter) const;
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0xD4 */ wchar_t* mTextBuf;
|
||||
/* 0xD8 */ ut::Color mTextColors[TEXTCOLOR_MAX];
|
||||
/* 0xE0 */ const ut::Font* mpFont;
|
||||
/* 0xE4 */ Size mFontSize;
|
||||
/* 0xEC */ f32 mLineSpace;
|
||||
/* 0xF0 */ f32 mCharSpace;
|
||||
/* 0xF4 */ ut::WideTagProcessor* mpTagProcessor;
|
||||
/* 0xF8 */ u16 mTextBufBytes;
|
||||
/* 0xFA */ u16 mTextLen;
|
||||
/* 0xFC */ u8 mTextPosition;
|
||||
|
||||
/* 0xFD */ struct {
|
||||
u8 allocFont : 1;
|
||||
} mTextBoxFlag;
|
||||
};
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef NW4HBM_LYT_WINDOW_H
|
||||
#define NW4HBM_LYT_WINDOW_H
|
||||
|
||||
#include "common.h"
|
||||
#include "pane.h"
|
||||
#include "resources.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace lyt {
|
||||
|
||||
class Window : public Pane {
|
||||
private:
|
||||
typedef struct Content {
|
||||
/* 0x00 */ ut::Color vtxColors[4];
|
||||
/* 0x10 */ detail::TexCoordAry texCoordAry;
|
||||
} Content;
|
||||
|
||||
typedef struct Frame {
|
||||
/* 0x00 */ u8 textureFlip;
|
||||
/* 0x04 */ Material* pMaterial;
|
||||
} Frame;
|
||||
|
||||
public:
|
||||
Window(const res::Window* pBlock, const ResBlockSet& resBlockSet);
|
||||
|
||||
/* 0x08 */ virtual ~Window();
|
||||
/* 0x0C */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x18 */ virtual void DrawSelf(const DrawInfo& drawInfo);
|
||||
/* 0x20 */ virtual void AnimateSelf(u32 option);
|
||||
/* 0x24 */ virtual ut::Color GetVtxColor(u32 idx) const;
|
||||
/* 0x28 */ virtual void SetVtxColor(u32 idx, ut::Color value);
|
||||
/* 0x34 */ virtual u8 GetVtxColorElement(u32 idx) const;
|
||||
/* 0x38 */ virtual void SetVtxColorElement(u32 idx, u8 value);
|
||||
/* 0x40 */ virtual Material* FindMaterialByName(const char* findName, bool bRecursive);
|
||||
/* 0x50 */ virtual void UnbindAnimationSelf(AnimTransform* animTrans);
|
||||
/* 0x54 */ virtual AnimationLink* FindAnimationLink(AnimTransform* animTrans);
|
||||
/* 0x58 */ virtual void SetAnimationEnable(AnimTransform* animTrans, bool bEnable,
|
||||
bool bRecursive);
|
||||
/* 0x64 */ virtual Material* GetContentMaterial() const;
|
||||
/* 0x68 */ virtual Material* GetFrameMaterial(u32 frameIdx) const;
|
||||
/* 0x6C */ virtual void DrawContent(const math::VEC2& basePt,
|
||||
const WindowFrameSize& frameSize, u8 alpha);
|
||||
/* 0x70 */ virtual void DrawFrame(const math::VEC2& basePt, const Frame& frame,
|
||||
const WindowFrameSize& frameSize, u8 alpha);
|
||||
/* 0x74 */ virtual void DrawFrame4(const math::VEC2& basePt, const Frame* frames,
|
||||
const WindowFrameSize& frameSize, u8 alpha);
|
||||
/* 0x78 */ virtual void DrawFrame8(const math::VEC2& basePt, const Frame* frames,
|
||||
const WindowFrameSize& frameSize, u8 alpha);
|
||||
|
||||
WindowFrameSize GetFrameSize(u8 frameNum, const Frame* frames);
|
||||
|
||||
private:
|
||||
/* 0x00 (base) */
|
||||
/* 0x0D4 */ InflationLRTB mContentInflation;
|
||||
/* 0x0E4 */ Content mContent;
|
||||
/* 0x0FC */ Frame* mFrames;
|
||||
/* 0x100 */ u8 mFrameNum;
|
||||
}; // size = 0x104
|
||||
|
||||
} // namespace lyt
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef NW4HBM_MACROS_H
|
||||
#define NW4HBM_MACROS_H
|
||||
|
||||
// Doesn't exist in line info, but still helpful to have
|
||||
|
||||
#if defined(CHAR_BIT)
|
||||
#define CHAR_BIT_ CHAR_BIT
|
||||
#else
|
||||
#define CHAR_BIT_ 8 // most common; default
|
||||
#endif
|
||||
|
||||
// offset_ is in chars
|
||||
#define NW4HBM_BYTE_(byte_, offset_) (static_cast<unsigned char>(byte_) << CHAR_BIT_ * (offset_))
|
||||
|
||||
// File versions and FourChars
|
||||
|
||||
#define NW4HBM_FILE_VERSION(major_, minor_) (NW4HBM_BYTE_(major_, 1) | NW4HBM_BYTE_(minor_, 0))
|
||||
|
||||
#define NW4HBM_FOUR_CHAR(a_, b_, c_, d_) \
|
||||
(NW4HBM_BYTE_(a_, 3) | NW4HBM_BYTE_(b_, 2) | NW4HBM_BYTE_(c_, 1) | NW4HBM_BYTE_(d_, 0))
|
||||
|
||||
#endif // NW4HBM_MACROS_H
|
||||
@@ -0,0 +1,164 @@
|
||||
#ifndef NW4HBM_MATH_ARITHMETIC_H
|
||||
#define NW4HBM_MATH_ARITHMETIC_H
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath.h>
|
||||
|
||||
#include <revolution/os.h>
|
||||
#include <revolution/types.h>
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
f32 FrSqrt(f32 x);
|
||||
|
||||
f32 Hermite(f32 p1, f32 t1, f32 p2, f32 t2, f32 s);
|
||||
f32 Bezier(f32 p1, f32 p2, f32 p3, f32 p4, f32 s);
|
||||
f32 CatmullRom(f32 p0, f32 p1, f32 p2, f32 p3, f32 s);
|
||||
|
||||
u32 CntBit1(u32 x);
|
||||
u32 CntBit1(u32 const* first, u32 const* last);
|
||||
u32 DistBit(u32 const* first1, u32 const* last1, u32 const* first2);
|
||||
u32 RevBit(u32 x);
|
||||
|
||||
int IExp(int x, u32 n);
|
||||
u32 ILog10(u32 x);
|
||||
|
||||
inline u32 F32AsU32(f32 x) {
|
||||
return *reinterpret_cast<u32*>(&x);
|
||||
}
|
||||
|
||||
inline f32 U32AsF32(u32 x) {
|
||||
return *reinterpret_cast<f32*>(&x);
|
||||
}
|
||||
|
||||
inline s32 FGetExpPart(f32 f) {
|
||||
s32 s = (F32AsU32(f) >> 23) & 0xff;
|
||||
|
||||
return s - 127;
|
||||
}
|
||||
|
||||
inline f32 FGetMantPart(f32 f) {
|
||||
u32 u = (F32AsU32(f) & 0x807fffff) | 0x3f800000;
|
||||
|
||||
return U32AsF32(u);
|
||||
}
|
||||
|
||||
inline f32 FSelect(register f32 cond, register f32 ifPos, register f32 ifNeg) {
|
||||
register f32 ret;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm { fsel ret, cond, ifPos, ifNeg }
|
||||
;
|
||||
#else
|
||||
#pragma unused(cond, ifPos, ifNeg)
|
||||
ret = 0;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline f32 FAbs(register f32 x) {
|
||||
register f32 ret;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm { fabs ret, x }
|
||||
#else
|
||||
#pragma unused(x)
|
||||
ret = 0;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline f32 FNAbs(register f32 x) {
|
||||
register f32 ret;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm { fnabs ret, x }
|
||||
#else
|
||||
#pragma unused(x)
|
||||
ret = 0;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline f32 AcosRad(f32 x) {
|
||||
return std::acos(x);
|
||||
}
|
||||
|
||||
inline f32 FCopySign(f32 abs, f32 sign) {
|
||||
f32 pos = FAbs(abs);
|
||||
f32 neg = FNAbs(abs);
|
||||
|
||||
return FSelect(sign, pos, neg);
|
||||
}
|
||||
|
||||
inline s16 F32ToS16(f32 x) {
|
||||
s16 rval;
|
||||
|
||||
OSf32tos16(&x, &rval);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
inline u16 F32ToU16(f32 x) {
|
||||
u16 rval;
|
||||
|
||||
OSf32tou16(&x, &rval);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
inline f32 U16ToF32(u16 x) {
|
||||
f32 rval;
|
||||
|
||||
OSu16tof32(&x, &rval);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
inline f32 S16ToF32(s16 x) {
|
||||
f32 rval;
|
||||
|
||||
OSs16tof32(&x, &rval);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
inline f32 FSqrt(f32 x) {
|
||||
return x <= 0.0f ? 0.0f : x * FrSqrt(x);
|
||||
}
|
||||
|
||||
inline f32 FCbrt(f32 x) {
|
||||
return std::pow(x, 1.0f / 3.0f);
|
||||
}
|
||||
|
||||
inline u32 CntLz(register u32 x) {
|
||||
register u32 result;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm { cntlzw result, x }
|
||||
#else
|
||||
#pragma unused(x)
|
||||
result = 0;
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline u32 DistBit(u32 x, u32 y) {
|
||||
return CntBit1(x ^ y);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
f32 FExp(f32 x);
|
||||
f32 FLog(f32 x);
|
||||
|
||||
u32 CntLz_(u32 x);
|
||||
} // namespace detail
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_ARITHMETIC_H
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef NW4HBM_MATH_CONSTANTS_H
|
||||
#define NW4HBM_MATH_CONSTANTS_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
static f32 const Ln2 = 0.69314718056f;
|
||||
static f32 const Pi = 3.141592653589f;
|
||||
static f32 const Tau = 2.0f * Pi;
|
||||
|
||||
namespace convert {
|
||||
static f32 const Deg2Rad = Pi / 180.0f;
|
||||
// Rad2Deg
|
||||
|
||||
static f32 const Deg2FIdx = 256.0f / 360.0f;
|
||||
static f32 const FIdx2Deg = 360.0f / 256.0f;
|
||||
|
||||
static f32 const Rad2FIdx = 256.0f / Tau;
|
||||
static f32 const FIdx2Rad = Tau / 256.0f;
|
||||
} // namespace convert
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_CONSTANTS_H
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef NW4HBM_MATH_EQUATION_H
|
||||
#define NW4HBM_MATH_EQUATION_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
int SolveEquation2(f32* root, f32 a, f32 b, f32 c);
|
||||
int SolveEquation3(f32* root, f32 a, f32 b, f32 c, f32 d);
|
||||
int SolveEquation4(f32* root, f32 a, f32 b, f32 c, f32 d, f32 e);
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_EQUATION_H
|
||||
@@ -0,0 +1,171 @@
|
||||
#ifndef NW4HBM_MATH_GEOMETRY_H
|
||||
#define NW4HBM_MATH_GEOMETRY_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
enum IntersectionResult {
|
||||
INTERSECTION_NONE = 0,
|
||||
INTERSECTION_1 = 1,
|
||||
INTERSECTION_2 = 2,
|
||||
|
||||
INTERSECTION_LINE3_ON_PLANE = INTERSECTION_2,
|
||||
INTERSECTION_RAY3_ON_PLANE = INTERSECTION_2,
|
||||
INTERSECTION_SEGMENT3_ON_PLANE = INTERSECTION_2,
|
||||
|
||||
INTERSECTION_OUTSIDE = 0,
|
||||
INTERSECTION_INSIDE = 1,
|
||||
INTERSECTION_INTERSECT = 2
|
||||
};
|
||||
|
||||
struct SEGMENT3 {
|
||||
VEC3 P0; // size 0x0c, offset 0x00
|
||||
VEC3 P1; // size 0x0c, offset 0x0c
|
||||
}; // size 0x18
|
||||
|
||||
struct RAY3 {
|
||||
VEC3 P; // size 0x0c, offset 0x00
|
||||
VEC3 d; // size 0x0c, offset 0x0c
|
||||
}; // size 0x18
|
||||
|
||||
struct LINE3 {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
LINE3() {}
|
||||
LINE3(VEC3 const& Pt, VEC3 const& dir, bool isNormalized) : P(Pt), d(dir) {
|
||||
if (!isNormalized)
|
||||
Normalize();
|
||||
}
|
||||
|
||||
// methods
|
||||
void Normalize() { VEC3Normalize(&d, &d); }
|
||||
|
||||
void Set(SEGMENT3 const* S) {
|
||||
P = S->P0;
|
||||
VEC3Sub(&d, &S->P1, &S->P0);
|
||||
|
||||
Normalize();
|
||||
}
|
||||
|
||||
// members
|
||||
public:
|
||||
VEC3 P; // size 0x0c, offset 0x00
|
||||
VEC3 d; // size 0x0c, offset 0x0c
|
||||
}; // size 0x18
|
||||
|
||||
struct CAPSULE {
|
||||
SEGMENT3 S; // size 0x18, offset 0x00
|
||||
f32 r; // size 0x04, offset 0x18
|
||||
}; // size 0x1c
|
||||
|
||||
struct PLANE {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Set(VEC3 const* P0, VEC3 const* P1, VEC3 const* P2);
|
||||
|
||||
f32 Test(VEC3 const& P) const { return VEC3Dot(&N, &P) + d; }
|
||||
|
||||
// members
|
||||
public:
|
||||
VEC3 N; // size 0x0c, offset 0x00
|
||||
f32 d; // size 0x04, offset 0x0c
|
||||
}; // size 0x10
|
||||
|
||||
struct AABB {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
AABB() {}
|
||||
|
||||
// methods
|
||||
void Normalize();
|
||||
void Set(VEC3 const* arrayPoint, unsigned numPoints);
|
||||
void Set(AABB const* box, MTX34 const* M);
|
||||
|
||||
// members
|
||||
public:
|
||||
VEC3 Pmin; // size 0x0c, offset 0x00
|
||||
VEC3 Pmax; // size 0x0c, offset 0x0c
|
||||
}; // size 0x18
|
||||
|
||||
struct SPHERE {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Set(VEC3 const* arrayPoint, unsigned numPoints);
|
||||
|
||||
// members
|
||||
public:
|
||||
VEC3 C; // size 0x0c, offset 0x00
|
||||
f32 r; // size 0x04, offset 0x0c
|
||||
}; // size 0x10
|
||||
|
||||
class FRUSTUM {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Set(f32 fovy, f32 aspect, f32 n, f32 f, MTX34 const& camera);
|
||||
void Set(f32 top, f32 bottom, f32 left, f32 right, f32 n, f32 f, MTX34 const& camera);
|
||||
|
||||
bool IntersectSphere(SPHERE const* S) const;
|
||||
bool IntersectAABB(AABB const* B) const;
|
||||
IntersectionResult IntersectAABB_Ex(AABB const* B) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
MTX34 cam; // size 0x30, offset 0x00
|
||||
PLANE leftPlane; // size 0x10, offset 0x30
|
||||
PLANE rightPlane; // size 0x10, offset 0x40
|
||||
PLANE topPlane; // size 0x10, offset 0x50
|
||||
PLANE bottomPlane; // size 0x10, offset 0x60
|
||||
f32 near; // size 0x04, offset 0x70
|
||||
f32 far; // size 0x04, offset 0x74
|
||||
AABB box; // size 0x18, offset 0x78
|
||||
PLANE planes[6]; // size 0x60, offset 0x90
|
||||
}; // size 0xf0
|
||||
|
||||
f32 DistSqPoint3ToLine3(VEC3 const* P, LINE3 const* L, f32* t);
|
||||
f32 DistSqPoint3ToRay3(VEC3 const* P, RAY3 const* R, f32* t);
|
||||
f32 DistSqPoint3ToSegment3(VEC3 const* P, SEGMENT3 const* S, f32* t);
|
||||
f32 DistSqPoint3ToPlane(VEC3 const* P, PLANE const* J, VEC3* Q);
|
||||
f32 DistSqSphereToPlane(SPHERE const* S, PLANE const* J);
|
||||
f32 DistSqPoint3ToPolyline3(VEC3 const* P, VEC3 const* vertices, unsigned nVertices);
|
||||
f32 DistSqLine3ToLine3(LINE3 const* L0, LINE3 const* L1, f32* s, f32* t);
|
||||
f32 DistSqSegment3ToSegment3(SEGMENT3 const* S1, SEGMENT3 const* S2, f32* s, f32* t);
|
||||
f32 DistSqLine3ToRay3(LINE3 const* L, RAY3 const* R, f32* s, f32* t);
|
||||
f32 DistSqLine3ToSegment3(LINE3 const* L0, SEGMENT3 const* S, f32* s, f32* t);
|
||||
f32 DistSqRay3ToRay3(RAY3 const* R0, RAY3 const* R1, f32* s, f32* t);
|
||||
f32 DistSqRay3ToSegment3(RAY3 const* R0, SEGMENT3 const* S, f32* s, f32* t);
|
||||
|
||||
IntersectionResult IntersectionLine3Plane(LINE3 const* L, PLANE const* J, f32* t, VEC3* I);
|
||||
IntersectionResult IntersectionRay3Plane(RAY3 const* R, PLANE const* J, f32* t, VEC3* I);
|
||||
IntersectionResult IntersectionSegment3Plane(SEGMENT3 const* S, PLANE const* J, f32* t,
|
||||
VEC3* I);
|
||||
IntersectionResult IntersectionLine3Sphere(LINE3 const* L, SPHERE const* sphere, f32* t0,
|
||||
f32* t1);
|
||||
IntersectionResult IntersectionRay3Sphere(RAY3 const* R, SPHERE const* sphere, f32* t0,
|
||||
f32* t1);
|
||||
bool IntersectionRay3Sphere(RAY3 const* R, SPHERE const* sphere);
|
||||
IntersectionResult IntersectionSegment3Sphere(SEGMENT3 const* S, SPHERE const* sphere,
|
||||
f32* t0, f32* t1);
|
||||
|
||||
bool IntersectionRay3AABB(RAY3 const* R, AABB const* box, f32* t);
|
||||
bool IntersectionAABB(AABB const* a, AABB const* b);
|
||||
bool IntersectionSphereAABB(SPHERE const* sphere, AABB const* aabb);
|
||||
bool IntersectionSphere(SPHERE const* s0, SPHERE const* s1);
|
||||
bool IntersectionCapsule(CAPSULE const* C0, CAPSULE const* C1);
|
||||
bool IntersectionRay3Capsule(RAY3 const* R, CAPSULE const* C);
|
||||
bool IntersectionLine3Capsule(LINE3 const* L, CAPSULE const* C);
|
||||
bool IntersectionPlaneCapsule(PLANE const* J, CAPSULE const* C);
|
||||
|
||||
SPHERE* MergeSphere(SPHERE* s2, SPHERE const* s0, SPHERE const* s1);
|
||||
AABB* MergeAABB(AABB* a2, AABB const* a0, AABB const* a1);
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_GEOMETRY_H
|
||||
@@ -0,0 +1,433 @@
|
||||
#include "arithmetic.h"
|
||||
#include <revolution/types.h>
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ f32 sin_val;
|
||||
/* 0x04 */ f32 cos_val;
|
||||
/* 0x08 */ f32 sin_delta;
|
||||
/* 0x0C */ f32 cos_delta;
|
||||
} SinCosSample; // size = 0x10
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ f32 atan_val;
|
||||
/* 0x04 */ f32 atan_delta;
|
||||
} ArcTanSample; // size = 0x08
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
namespace {
|
||||
f32 AtanFIdx_(f32 x);
|
||||
|
||||
static SinCosSample sSinCosTbl[] = {
|
||||
{0.0f, 1.0f, 0.024541f, -3.01e-4f},
|
||||
{0.024541f, 0.999699f, 0.024526f, -9.03e-4f},
|
||||
{0.049068f, 0.998795f, 0.024497f, -0.001505f},
|
||||
{0.073565f, 0.99729f, 0.024453f, -0.002106f},
|
||||
{0.098017f, 0.995185f, 0.024394f, -0.002705f},
|
||||
{0.122411f, 0.99248f, 0.02432f, -0.003303f},
|
||||
{0.14673f, 0.989177f, 0.024231f, -0.003899f},
|
||||
{0.170962f, 0.985278f, 0.024128f, -0.004492f},
|
||||
{0.19509f, 0.980785f, 0.024011f, -0.005083f},
|
||||
{0.219101f, 0.975702f, 0.023879f, -0.005671f},
|
||||
{0.24298f, 0.970031f, 0.023733f, -0.006255f},
|
||||
{0.266713f, 0.963776f, 0.023572f, -0.006836f},
|
||||
{0.290285f, 0.95694f, 0.023397f, -0.007412f},
|
||||
{0.313682f, 0.949528f, 0.023208f, -0.007984f},
|
||||
{0.33689f, 0.941544f, 0.023005f, -0.008551f},
|
||||
{0.359895f, 0.932993f, 0.022788f, -0.009113f},
|
||||
{0.382683f, 0.92388f, 0.022558f, -0.00967f},
|
||||
{0.405241f, 0.91421f, 0.022314f, -0.01022f},
|
||||
{0.427555f, 0.903989f, 0.022056f, -0.010765f},
|
||||
{0.449611f, 0.893224f, 0.021785f, -0.011303f},
|
||||
{0.471397f, 0.881921f, 0.021501f, -0.011834f},
|
||||
{0.492898f, 0.870087f, 0.021205f, -0.012358f},
|
||||
{0.514103f, 0.857729f, 0.020895f, -0.012875f},
|
||||
{0.534998f, 0.844854f, 0.020573f, -0.013384f},
|
||||
{0.55557f, 0.83147f, 0.020238f, -0.013885f},
|
||||
{0.575808f, 0.817585f, 0.019891f, -0.014377f},
|
||||
{0.595699f, 0.803208f, 0.019532f, -0.014861f},
|
||||
{0.615232f, 0.788346f, 0.019162f, -0.015336f},
|
||||
{0.634393f, 0.77301f, 0.01878f, -0.015802f},
|
||||
{0.653173f, 0.757209f, 0.018386f, -0.016258f},
|
||||
{0.671559f, 0.740951f, 0.017982f, -0.016704f},
|
||||
{0.689541f, 0.724247f, 0.017566f, -0.01714f},
|
||||
{0.707107f, 0.707107f, 0.01714f, -0.017566f},
|
||||
{0.724247f, 0.689541f, 0.016704f, -0.017982f},
|
||||
{0.740951f, 0.671559f, 0.016258f, -0.018386f},
|
||||
{0.757209f, 0.653173f, 0.015802f, -0.01878f},
|
||||
{0.77301f, 0.634393f, 0.015336f, -0.019162f},
|
||||
{0.788346f, 0.615232f, 0.014861f, -0.019532f},
|
||||
{0.803208f, 0.595699f, 0.014377f, -0.019891f},
|
||||
{0.817585f, 0.575808f, 0.013885f, -0.020238f},
|
||||
{0.83147f, 0.55557f, 0.013384f, -0.020573f},
|
||||
{0.844854f, 0.534998f, 0.012875f, -0.020895f},
|
||||
{0.857729f, 0.514103f, 0.012358f, -0.021205f},
|
||||
{0.870087f, 0.492898f, 0.011834f, -0.021501f},
|
||||
{0.881921f, 0.471397f, 0.011303f, -0.021785f},
|
||||
{0.893224f, 0.449611f, 0.010765f, -0.022056f},
|
||||
{0.903989f, 0.427555f, 0.01022f, -0.022314f},
|
||||
{0.91421f, 0.405241f, 0.00967f, -0.022558f},
|
||||
{0.92388f, 0.382683f, 0.009113f, -0.022788f},
|
||||
{0.932993f, 0.359895f, 0.008551f, -0.023005f},
|
||||
{0.941544f, 0.33689f, 0.007984f, -0.023208f},
|
||||
{0.949528f, 0.313682f, 0.007412f, -0.023397f},
|
||||
{0.95694f, 0.290285f, 0.006836f, -0.023572f},
|
||||
{0.963776f, 0.266713f, 0.006255f, -0.023733f},
|
||||
{0.970031f, 0.24298f, 0.005671f, -0.023879f},
|
||||
{0.975702f, 0.219101f, 0.005083f, -0.024011f},
|
||||
{0.980785f, 0.19509f, 0.004492f, -0.024128f},
|
||||
{0.985278f, 0.170962f, 0.003899f, -0.024231f},
|
||||
{0.989177f, 0.14673f, 0.003303f, -0.02432f},
|
||||
{0.99248f, 0.122411f, 0.002705f, -0.024394f},
|
||||
{0.995185f, 0.098017f, 0.002106f, -0.024453f},
|
||||
{0.99729f, 0.073565f, 0.001505f, -0.024497f},
|
||||
{0.998795f, 0.049068f, 9.03e-4f, -0.024526f},
|
||||
{0.999699f, 0.024541f, 3.01e-4f, -0.024541f},
|
||||
{1.0f, 0.0f, -3.01e-4f, -0.024541f},
|
||||
{0.999699f, -0.024541f, -9.03e-4f, -0.024526f},
|
||||
{0.998795f, -0.049068f, -0.001505f, -0.024497f},
|
||||
{0.99729f, -0.073565f, -0.002106f, -0.024453f},
|
||||
{0.995185f, -0.098017f, -0.002705f, -0.024394f},
|
||||
{0.99248f, -0.122411f, -0.003303f, -0.02432f},
|
||||
{0.989177f, -0.14673f, -0.003899f, -0.024231f},
|
||||
{0.985278f, -0.170962f, -0.004492f, -0.024128f},
|
||||
{0.980785f, -0.19509f, -0.005083f, -0.024011f},
|
||||
{0.975702f, -0.219101f, -0.005671f, -0.023879f},
|
||||
{0.970031f, -0.24298f, -0.006255f, -0.023733f},
|
||||
{0.963776f, -0.266713f, -0.006836f, -0.023572f},
|
||||
{0.95694f, -0.290285f, -0.007412f, -0.023397f},
|
||||
{0.949528f, -0.313682f, -0.007984f, -0.023208f},
|
||||
{0.941544f, -0.33689f, -0.008551f, -0.023005f},
|
||||
{0.932993f, -0.359895f, -0.009113f, -0.022788f},
|
||||
{0.92388f, -0.382683f, -0.00967f, -0.022558f},
|
||||
{0.91421f, -0.405241f, -0.01022f, -0.022314f},
|
||||
{0.903989f, -0.427555f, -0.010765f, -0.022056f},
|
||||
{0.893224f, -0.449611f, -0.011303f, -0.021785f},
|
||||
{0.881921f, -0.471397f, -0.011834f, -0.021501f},
|
||||
{0.870087f, -0.492898f, -0.012358f, -0.021205f},
|
||||
{0.857729f, -0.514103f, -0.012875f, -0.020895f},
|
||||
{0.844854f, -0.534998f, -0.013384f, -0.020573f},
|
||||
{0.83147f, -0.55557f, -0.013885f, -0.020238f},
|
||||
{0.817585f, -0.575808f, -0.014377f, -0.019891f},
|
||||
{0.803208f, -0.595699f, -0.014861f, -0.019532f},
|
||||
{0.788346f, -0.615232f, -0.015336f, -0.019162f},
|
||||
{0.77301f, -0.634393f, -0.015802f, -0.01878f},
|
||||
{0.757209f, -0.653173f, -0.016258f, -0.018386f},
|
||||
{0.740951f, -0.671559f, -0.016704f, -0.017982f},
|
||||
{0.724247f, -0.689541f, -0.01714f, -0.017566f},
|
||||
{0.707107f, -0.707107f, -0.017566f, -0.01714f},
|
||||
{0.689541f, -0.724247f, -0.017982f, -0.016704f},
|
||||
{0.671559f, -0.740951f, -0.018386f, -0.016258f},
|
||||
{0.653173f, -0.757209f, -0.01878f, -0.015802f},
|
||||
{0.634393f, -0.77301f, -0.019162f, -0.015336f},
|
||||
{0.615232f, -0.788346f, -0.019532f, -0.014861f},
|
||||
{0.595699f, -0.803208f, -0.019891f, -0.014377f},
|
||||
{0.575808f, -0.817585f, -0.020238f, -0.013885f},
|
||||
{0.55557f, -0.83147f, -0.020573f, -0.013384f},
|
||||
{0.534998f, -0.844854f, -0.020895f, -0.012875f},
|
||||
{0.514103f, -0.857729f, -0.021205f, -0.012358f},
|
||||
{0.492898f, -0.870087f, -0.021501f, -0.011834f},
|
||||
{0.471397f, -0.881921f, -0.021785f, -0.011303f},
|
||||
{0.449611f, -0.893224f, -0.022056f, -0.010765f},
|
||||
{0.427555f, -0.903989f, -0.022314f, -0.01022f},
|
||||
{0.405241f, -0.91421f, -0.022558f, -0.00967f},
|
||||
{0.382683f, -0.92388f, -0.022788f, -0.009113f},
|
||||
{0.359895f, -0.932993f, -0.023005f, -0.008551f},
|
||||
{0.33689f, -0.941544f, -0.023208f, -0.007984f},
|
||||
{0.313682f, -0.949528f, -0.023397f, -0.007412f},
|
||||
{0.290285f, -0.95694f, -0.023572f, -0.006836f},
|
||||
{0.266713f, -0.963776f, -0.023733f, -0.006255f},
|
||||
{0.24298f, -0.970031f, -0.023879f, -0.005671f},
|
||||
{0.219101f, -0.975702f, -0.024011f, -0.005083f},
|
||||
{0.19509f, -0.980785f, -0.024128f, -0.004492f},
|
||||
{0.170962f, -0.985278f, -0.024231f, -0.003899f},
|
||||
{0.14673f, -0.989177f, -0.02432f, -0.003303f},
|
||||
{0.122411f, -0.99248f, -0.024394f, -0.002705f},
|
||||
{0.098017f, -0.995185f, -0.024453f, -0.002106f},
|
||||
{0.073565f, -0.99729f, -0.024497f, -0.001505f},
|
||||
{0.049068f, -0.998795f, -0.024526f, -9.03e-4f},
|
||||
{0.024541f, -0.999699f, -0.024541f, -3.01e-4f},
|
||||
{0.0f, -1.0f, -0.024541f, 3.01e-4f},
|
||||
{-0.024541f, -0.999699f, -0.024526f, 9.03e-4f},
|
||||
{-0.049068f, -0.998795f, -0.024497f, 0.001505f},
|
||||
{-0.073565f, -0.99729f, -0.024453f, 0.002106f},
|
||||
{-0.098017f, -0.995185f, -0.024394f, 0.002705f},
|
||||
{-0.122411f, -0.99248f, -0.02432f, 0.003303f},
|
||||
{-0.14673f, -0.989177f, -0.024231f, 0.003899f},
|
||||
{-0.170962f, -0.985278f, -0.024128f, 0.004492f},
|
||||
{-0.19509f, -0.980785f, -0.024011f, 0.005083f},
|
||||
{-0.219101f, -0.975702f, -0.023879f, 0.005671f},
|
||||
{-0.24298f, -0.970031f, -0.023733f, 0.006255f},
|
||||
{-0.266713f, -0.963776f, -0.023572f, 0.006836f},
|
||||
{-0.290285f, -0.95694f, -0.023397f, 0.007412f},
|
||||
{-0.313682f, -0.949528f, -0.023208f, 0.007984f},
|
||||
{-0.33689f, -0.941544f, -0.023005f, 0.008551f},
|
||||
{-0.359895f, -0.932993f, -0.022788f, 0.009113f},
|
||||
{-0.382683f, -0.92388f, -0.022558f, 0.00967f},
|
||||
{-0.405241f, -0.91421f, -0.022314f, 0.01022f},
|
||||
{-0.427555f, -0.903989f, -0.022056f, 0.010765f},
|
||||
{-0.449611f, -0.893224f, -0.021785f, 0.011303f},
|
||||
{-0.471397f, -0.881921f, -0.021501f, 0.011834f},
|
||||
{-0.492898f, -0.870087f, -0.021205f, 0.012358f},
|
||||
{-0.514103f, -0.857729f, -0.020895f, 0.012875f},
|
||||
{-0.534998f, -0.844854f, -0.020573f, 0.013384f},
|
||||
{-0.55557f, -0.83147f, -0.020238f, 0.013885f},
|
||||
{-0.575808f, -0.817585f, -0.019891f, 0.014377f},
|
||||
{-0.595699f, -0.803208f, -0.019532f, 0.014861f},
|
||||
{-0.615232f, -0.788346f, -0.019162f, 0.015336f},
|
||||
{-0.634393f, -0.77301f, -0.01878f, 0.015802f},
|
||||
{-0.653173f, -0.757209f, -0.018386f, 0.016258f},
|
||||
{-0.671559f, -0.740951f, -0.017982f, 0.016704f},
|
||||
{-0.689541f, -0.724247f, -0.017566f, 0.01714f},
|
||||
{-0.707107f, -0.707107f, -0.01714f, 0.017566f},
|
||||
{-0.724247f, -0.689541f, -0.016704f, 0.017982f},
|
||||
{-0.740951f, -0.671559f, -0.016258f, 0.018386f},
|
||||
{-0.757209f, -0.653173f, -0.015802f, 0.01878f},
|
||||
{-0.77301f, -0.634393f, -0.015336f, 0.019162f},
|
||||
{-0.788346f, -0.615232f, -0.014861f, 0.019532f},
|
||||
{-0.803208f, -0.595699f, -0.014377f, 0.019891f},
|
||||
{-0.817585f, -0.575808f, -0.013885f, 0.020238f},
|
||||
{-0.83147f, -0.55557f, -0.013384f, 0.020573f},
|
||||
{-0.844854f, -0.534998f, -0.012875f, 0.020895f},
|
||||
{-0.857729f, -0.514103f, -0.012358f, 0.021205f},
|
||||
{-0.870087f, -0.492898f, -0.011834f, 0.021501f},
|
||||
{-0.881921f, -0.471397f, -0.011303f, 0.021785f},
|
||||
{-0.893224f, -0.449611f, -0.010765f, 0.022056f},
|
||||
{-0.903989f, -0.427555f, -0.01022f, 0.022314f},
|
||||
{-0.91421f, -0.405241f, -0.00967f, 0.022558f},
|
||||
{-0.92388f, -0.382683f, -0.009113f, 0.022788f},
|
||||
{-0.932993f, -0.359895f, -0.008551f, 0.023005f},
|
||||
{-0.941544f, -0.33689f, -0.007984f, 0.023208f},
|
||||
{-0.949528f, -0.313682f, -0.007412f, 0.023397f},
|
||||
{-0.95694f, -0.290285f, -0.006836f, 0.023572f},
|
||||
{-0.963776f, -0.266713f, -0.006255f, 0.023733f},
|
||||
{-0.970031f, -0.24298f, -0.005671f, 0.023879f},
|
||||
{-0.975702f, -0.219101f, -0.005083f, 0.024011f},
|
||||
{-0.980785f, -0.19509f, -0.004492f, 0.024128f},
|
||||
{-0.985278f, -0.170962f, -0.003899f, 0.024231f},
|
||||
{-0.989177f, -0.14673f, -0.003303f, 0.02432f},
|
||||
{-0.99248f, -0.122411f, -0.002705f, 0.024394f},
|
||||
{-0.995185f, -0.098017f, -0.002106f, 0.024453f},
|
||||
{-0.99729f, -0.073565f, -0.001505f, 0.024497f},
|
||||
{-0.998795f, -0.049068f, -9.03e-4f, 0.024526f},
|
||||
{-0.999699f, -0.024541f, -3.01e-4f, 0.024541f},
|
||||
{-1.0f, -0.0f, 3.01e-4f, 0.024541f},
|
||||
{-0.999699f, 0.024541f, 9.03e-4f, 0.024526f},
|
||||
{-0.998795f, 0.049068f, 0.001505f, 0.024497f},
|
||||
{-0.99729f, 0.073565f, 0.002106f, 0.024453f},
|
||||
{-0.995185f, 0.098017f, 0.002705f, 0.024394f},
|
||||
{-0.99248f, 0.122411f, 0.003303f, 0.02432f},
|
||||
{-0.989177f, 0.14673f, 0.003899f, 0.024231f},
|
||||
{-0.985278f, 0.170962f, 0.004492f, 0.024128f},
|
||||
{-0.980785f, 0.19509f, 0.005083f, 0.024011f},
|
||||
{-0.975702f, 0.219101f, 0.005671f, 0.023879f},
|
||||
{-0.970031f, 0.24298f, 0.006255f, 0.023733f},
|
||||
{-0.963776f, 0.266713f, 0.006836f, 0.023572f},
|
||||
{-0.95694f, 0.290285f, 0.007412f, 0.023397f},
|
||||
{-0.949528f, 0.313682f, 0.007984f, 0.023208f},
|
||||
{-0.941544f, 0.33689f, 0.008551f, 0.023005f},
|
||||
{-0.932993f, 0.359895f, 0.009113f, 0.022788f},
|
||||
{-0.92388f, 0.382683f, 0.00967f, 0.022558f},
|
||||
{-0.91421f, 0.405241f, 0.01022f, 0.022314f},
|
||||
{-0.903989f, 0.427555f, 0.010765f, 0.022056f},
|
||||
{-0.893224f, 0.449611f, 0.011303f, 0.021785f},
|
||||
{-0.881921f, 0.471397f, 0.011834f, 0.021501f},
|
||||
{-0.870087f, 0.492898f, 0.012358f, 0.021205f},
|
||||
{-0.857729f, 0.514103f, 0.012875f, 0.020895f},
|
||||
{-0.844854f, 0.534998f, 0.013384f, 0.020573f},
|
||||
{-0.83147f, 0.55557f, 0.013885f, 0.020238f},
|
||||
{-0.817585f, 0.575808f, 0.014377f, 0.019891f},
|
||||
{-0.803208f, 0.595699f, 0.014861f, 0.019532f},
|
||||
{-0.788346f, 0.615232f, 0.015336f, 0.019162f},
|
||||
{-0.77301f, 0.634393f, 0.015802f, 0.01878f},
|
||||
{-0.757209f, 0.653173f, 0.016258f, 0.018386f},
|
||||
{-0.740951f, 0.671559f, 0.016704f, 0.017982f},
|
||||
{-0.724247f, 0.689541f, 0.01714f, 0.017566f},
|
||||
{-0.707107f, 0.707107f, 0.017566f, 0.01714f},
|
||||
{-0.689541f, 0.724247f, 0.017982f, 0.016704f},
|
||||
{-0.671559f, 0.740951f, 0.018386f, 0.016258f},
|
||||
{-0.653173f, 0.757209f, 0.01878f, 0.015802f},
|
||||
{-0.634393f, 0.77301f, 0.019162f, 0.015336f},
|
||||
{-0.615232f, 0.788346f, 0.019532f, 0.014861f},
|
||||
{-0.595699f, 0.803208f, 0.019891f, 0.014377f},
|
||||
{-0.575808f, 0.817585f, 0.020238f, 0.013885f},
|
||||
{-0.55557f, 0.83147f, 0.020573f, 0.013384f},
|
||||
{-0.534998f, 0.844854f, 0.020895f, 0.012875f},
|
||||
{-0.514103f, 0.857729f, 0.021205f, 0.012358f},
|
||||
{-0.492898f, 0.870087f, 0.021501f, 0.011834f},
|
||||
{-0.471397f, 0.881921f, 0.021785f, 0.011303f},
|
||||
{-0.449611f, 0.893224f, 0.022056f, 0.010765f},
|
||||
{-0.427555f, 0.903989f, 0.022314f, 0.01022f},
|
||||
{-0.405241f, 0.91421f, 0.022558f, 0.00967f},
|
||||
{-0.382683f, 0.92388f, 0.022788f, 0.009113f},
|
||||
{-0.359895f, 0.932993f, 0.023005f, 0.008551f},
|
||||
{-0.33689f, 0.941544f, 0.023208f, 0.007984f},
|
||||
{-0.313682f, 0.949528f, 0.023397f, 0.007412f},
|
||||
{-0.290285f, 0.95694f, 0.023572f, 0.006836f},
|
||||
{-0.266713f, 0.963776f, 0.023733f, 0.006255f},
|
||||
{-0.24298f, 0.970031f, 0.023879f, 0.005671f},
|
||||
{-0.219101f, 0.975702f, 0.024011f, 0.005083f},
|
||||
{-0.19509f, 0.980785f, 0.024128f, 0.004492f},
|
||||
{-0.170962f, 0.985278f, 0.024231f, 0.003899f},
|
||||
{-0.14673f, 0.989177f, 0.02432f, 0.003303f},
|
||||
{-0.122411f, 0.99248f, 0.024394f, 0.002705f},
|
||||
{-0.098017f, 0.995185f, 0.024453f, 0.002106f},
|
||||
{-0.073565f, 0.99729f, 0.024497f, 0.001505f},
|
||||
{-0.049068f, 0.998795f, 0.024526f, 9.03e-4f},
|
||||
{-0.024541f, 0.999699f, 0.024541f, 3.01e-4f},
|
||||
{-0.0f, 1.0f, 0.024541f, -3.01e-4f},
|
||||
};
|
||||
|
||||
static ArcTanSample sArcTanTbl[] = {
|
||||
{0.0f, 1.2728254f}, {1.2728254f, 1.2703458f}, {2.5431712f, 1.2654155f},
|
||||
{3.8085866f, 1.2580916f}, {5.0666785f, 1.2484571f}, {6.3151355f, 1.2366195f},
|
||||
{7.551755f, 1.2227072f}, {8.774462f, 1.2068666f}, {9.981329f, 1.1892582f},
|
||||
{11.170587f, 1.1700529f}, {12.34064f, 1.149428f}, {13.4900675f, 1.1275644f},
|
||||
{14.617632f, 1.1046423f}, {15.722275f, 1.0808387f}, {16.803114f, 1.0563251f},
|
||||
{17.859438f, 1.0312649f}, {18.890703f, 1.005812f}, {19.896515f, 0.98010963f},
|
||||
{20.876625f, 0.9542891f}, {21.830914f, 0.9284698f}, {22.759384f, 0.90275896f},
|
||||
{23.662142f, 0.87725157f}, {24.539394f, 0.8520309f}, {25.391424f, 0.8271689f},
|
||||
{26.218594f, 0.802727f}, {27.02132f, 0.77875656f}, {27.800077f, 0.7553001f},
|
||||
{28.555378f, 0.7323915f}, {29.28777f, 0.7100574f}, {29.997826f, 0.6883175f},
|
||||
{30.686144f, 0.66718566f}, {31.353329f, 0.6466705f}, {32.0f, 0.62677616f},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
|
||||
f32 AtanFIdx_(f32 x) {
|
||||
u16 idx;
|
||||
f32 val;
|
||||
f32 r;
|
||||
|
||||
x *= 32.0f;
|
||||
|
||||
idx = F32ToU16(x);
|
||||
r = x - U16ToF32(idx);
|
||||
val = sArcTanTbl[idx].atan_val + r * sArcTanTbl[idx].atan_delta;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
f32 SinFIdx(f32 fidx) {
|
||||
f32 abs_fidx = FAbs(fidx); // hm
|
||||
f32 val;
|
||||
u16 idx;
|
||||
f32 r;
|
||||
|
||||
while (abs_fidx >= 65536.0f) {
|
||||
abs_fidx -= 65536.0f;
|
||||
}
|
||||
|
||||
idx = F32ToU16(abs_fidx);
|
||||
r = abs_fidx - U16ToF32(idx);
|
||||
|
||||
idx &= 0xff;
|
||||
val = sSinCosTbl[idx].sin_val + r * sSinCosTbl[idx].sin_delta;
|
||||
|
||||
return fidx < 0.0f ? -val : val;
|
||||
}
|
||||
|
||||
f32 CosFIdx(f32 fidx) {
|
||||
u16 idx;
|
||||
f32 r;
|
||||
|
||||
fidx = FAbs(fidx);
|
||||
while (fidx >= 65536.0f) {
|
||||
fidx -= 65536.0f;
|
||||
}
|
||||
|
||||
idx = F32ToU16(fidx);
|
||||
r = fidx - U16ToF32(idx);
|
||||
|
||||
idx &= 0xff;
|
||||
|
||||
return sSinCosTbl[idx].cos_val + r * sSinCosTbl[idx].cos_delta;
|
||||
}
|
||||
|
||||
extern void __deadstrip1();
|
||||
extern void __deadstrip1() {
|
||||
(void)32.0f;
|
||||
(void)64.0f;
|
||||
}
|
||||
|
||||
f32 Atan2FIdx(f32 y, f32 x) {
|
||||
f32 a;
|
||||
f32 b;
|
||||
f32 c;
|
||||
bool minus;
|
||||
|
||||
if (x == 0.0f && y == 0.0f) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (x >= 0.0f) {
|
||||
if (y >= 0.0f) {
|
||||
if (x >= y) {
|
||||
a = x;
|
||||
b = y;
|
||||
c = 0.0f;
|
||||
|
||||
minus = false;
|
||||
} else {
|
||||
a = y;
|
||||
b = x;
|
||||
c = 64.0f;
|
||||
|
||||
minus = true;
|
||||
}
|
||||
} else {
|
||||
if (x >= -y) {
|
||||
a = x;
|
||||
b = -y;
|
||||
c = 0.0f;
|
||||
|
||||
minus = true;
|
||||
} else {
|
||||
a = -y;
|
||||
b = x;
|
||||
c = -64.0f;
|
||||
|
||||
minus = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (y >= 0.0f) {
|
||||
if (-x >= y) {
|
||||
a = -x;
|
||||
b = y;
|
||||
c = 128.0f;
|
||||
|
||||
minus = true;
|
||||
} else {
|
||||
a = y;
|
||||
b = -x;
|
||||
c = 64.0f;
|
||||
|
||||
minus = false;
|
||||
}
|
||||
} else {
|
||||
if (-x >= -y) {
|
||||
a = -x;
|
||||
b = -y;
|
||||
c = -128.0f;
|
||||
|
||||
minus = false;
|
||||
} else {
|
||||
a = -y;
|
||||
b = -x;
|
||||
c = -64.0f;
|
||||
|
||||
minus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return minus ? c - AtanFIdx_(b / a) : c + AtanFIdx_(b / a);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef NW4HBM_MATH_TRIANGULAR_H
|
||||
#define NW4HBM_MATH_TRIANGULAR_H
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath.h>
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
f32 SinFIdx(f32 fidx);
|
||||
f32 CosFIdx(f32 fidx);
|
||||
void SinCosFIdx(f32* s, f32* c, f32 fidx);
|
||||
|
||||
f32 AtanFIdx(f32 x);
|
||||
f32 Atan2FIdx(f32 y, f32 x);
|
||||
|
||||
inline f32 TanFIdx(f32 fidx) {
|
||||
// They were just like "Ah fuck it we already got too many tables" haha lol
|
||||
return std::tanf(fidx * convert::FIdx2Rad);
|
||||
}
|
||||
|
||||
inline f32 CosRad(f32 rad) {
|
||||
return CosFIdx(rad * convert::Rad2FIdx);
|
||||
}
|
||||
|
||||
inline f32 SinDeg(f32 deg) {
|
||||
return SinFIdx(deg * convert::Deg2FIdx);
|
||||
}
|
||||
|
||||
inline f32 CosDeg(f32 deg) {
|
||||
return CosFIdx(deg * convert::Deg2FIdx);
|
||||
}
|
||||
|
||||
inline f32 TanDeg(f32 deg) {
|
||||
return TanFIdx(deg * convert::Deg2FIdx);
|
||||
}
|
||||
|
||||
inline f32 Atan2Deg(f32 y, f32 x) {
|
||||
return Atan2FIdx(y, x) * convert::FIdx2Deg;
|
||||
}
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_TRIANGULAR_H
|
||||
@@ -0,0 +1,523 @@
|
||||
#ifndef NW4HBM_MATH_TYPES_H
|
||||
#define NW4HBM_MATH_TYPES_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/mtx.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace math {
|
||||
struct _VEC2 {
|
||||
f32 x; // size 0x04, offset 0x00
|
||||
f32 y; // size 0x04, offset 0x04
|
||||
}; // size 0x08
|
||||
|
||||
struct _VEC3 {
|
||||
f32 x; // size 0x04, offset 0x00
|
||||
f32 y; // size 0x04, offset 0x04
|
||||
f32 z; // size 0x04, offset 0x08
|
||||
}; // size 0x0c
|
||||
|
||||
struct _VEC4 {
|
||||
f32 x; // size 0x04, offset 0x00
|
||||
f32 y; // size 0x04, offset 0x04
|
||||
f32 z; // size 0x04, offset 0x08
|
||||
f32 w; // size 0x04, offset 0x0c
|
||||
}; // size 0x10
|
||||
|
||||
struct _QUAT {
|
||||
f32 x; // size 0x04, offset 0x00
|
||||
f32 y; // size 0x04, offset 0x04
|
||||
f32 z; // size 0x04, offset 0x08
|
||||
f32 w; // size 0x04, offset 0x0c
|
||||
}; // size 0x10
|
||||
|
||||
struct _MTX33 {
|
||||
union {
|
||||
struct {
|
||||
f32 _00; // size 0x04, offset 0x00
|
||||
f32 _01; // size 0x04, offset 0x04
|
||||
f32 _02; // size 0x04, offset 0x08
|
||||
f32 _10; // size 0x04, offset 0x0c
|
||||
f32 _11; // size 0x04, offset 0x10
|
||||
f32 _12; // size 0x04, offset 0x14
|
||||
f32 _20; // size 0x04, offset 0x18
|
||||
f32 _21; // size 0x04, offset 0x1c
|
||||
f32 _22; // size 0x04, offset 0x20
|
||||
}; // size 0x24
|
||||
|
||||
f32 m[3][3]; // size 0x24
|
||||
f32 a[3 * 3]; // size 0x24
|
||||
}; // size 0x24, offset 0x00
|
||||
}; // size 0x24
|
||||
|
||||
struct _MTX34 {
|
||||
union {
|
||||
struct {
|
||||
f32 _00; // size 0x04, offset 0x00
|
||||
f32 _01; // size 0x04, offset 0x04
|
||||
f32 _02; // size 0x04, offset 0x08
|
||||
f32 _03; // size 0x04, offset 0x0c
|
||||
f32 _10; // size 0x04, offset 0x10
|
||||
f32 _11; // size 0x04, offset 0x14
|
||||
f32 _12; // size 0x04, offset 0x18
|
||||
f32 _13; // size 0x04, offset 0x1c
|
||||
f32 _20; // size 0x04, offset 0x20
|
||||
f32 _21; // size 0x04, offset 0x24
|
||||
f32 _22; // size 0x04, offset 0x28
|
||||
f32 _23; // size 0x04, offset 0x2c
|
||||
}; // size 0x30
|
||||
|
||||
f32 m[3][4]; // size 0x30
|
||||
f32 a[3 * 4]; // size 0x30
|
||||
Mtx mtx; // size 0x30
|
||||
}; // size 0x30, offset 0x00
|
||||
}; // size 0x30
|
||||
|
||||
struct _MTX44 {
|
||||
union {
|
||||
struct {
|
||||
f32 _00; // size 0x04, offset 0x00
|
||||
f32 _01; // size 0x04, offset 0x04
|
||||
f32 _02; // size 0x04, offset 0x08
|
||||
f32 _03; // size 0x04, offset 0x0c
|
||||
f32 _10; // size 0x04, offset 0x10
|
||||
f32 _11; // size 0x04, offset 0x14
|
||||
f32 _12; // size 0x04, offset 0x18
|
||||
f32 _13; // size 0x04, offset 0x1c
|
||||
f32 _20; // size 0x04, offset 0x20
|
||||
f32 _21; // size 0x04, offset 0x24
|
||||
f32 _22; // size 0x04, offset 0x28
|
||||
f32 _23; // size 0x04, offset 0x2c
|
||||
f32 _30; // size 0x04, offset 0x30
|
||||
f32 _31; // size 0x04, offset 0x34
|
||||
f32 _32; // size 0x04, offset 0x38
|
||||
f32 _33; // size 0x04, offset 0x3c
|
||||
}; // size 0x40
|
||||
|
||||
f32 m[4][4]; // size 0x40
|
||||
f32 a[4 * 4]; // size 0x40
|
||||
Mtx44 mtx; // size 0x40
|
||||
}; // size 0x40, offset 0x00
|
||||
}; // size 0x40
|
||||
|
||||
struct VEC2 : public _VEC2 {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
VEC2() {}
|
||||
VEC2(f32 fx, f32 fy) {
|
||||
x = fx;
|
||||
y = fy;
|
||||
}
|
||||
|
||||
// operators
|
||||
operator f32*() { return reinterpret_cast<f32*>(this); }
|
||||
operator f32 const*() const { return reinterpret_cast<f32 const*>(this); }
|
||||
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _VEC2 */ // size 0x08, offset 0x00
|
||||
}; // size 0x08
|
||||
|
||||
struct VEC3 : public _VEC3 {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
VEC3() {}
|
||||
VEC3(f32 fx, f32 fy, f32 fz) {
|
||||
x = fx;
|
||||
y = fy;
|
||||
z = fz;
|
||||
}
|
||||
|
||||
// operators
|
||||
VEC3 operator+(VEC3 const& rhs) const;
|
||||
VEC3 operator-(VEC3 const& rhs) const;
|
||||
|
||||
VEC3 operator*(f32 f) const;
|
||||
|
||||
operator VecPtr() { return reinterpret_cast<VecPtr>(this); }
|
||||
operator CVecPtr() const { return (CVecPtr)(this); }
|
||||
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _VEC3 */ // size 0x0c, offset 0x00
|
||||
}; // size 0x0c
|
||||
|
||||
struct VEC4 : public _VEC4 {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
VEC4() {}
|
||||
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _VEC4 */ // size 0x10, offset 0x00
|
||||
}; // size 0x10
|
||||
|
||||
struct QUAT : public _QUAT {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _QUAT */ // size 0x10, offset 0x00
|
||||
}; // size 0x10
|
||||
|
||||
struct MTX33 : public _MTX33 {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _MTX33 */ // size 0x24, offset 0x00
|
||||
}; // size 0x24
|
||||
|
||||
struct MTX34 : public _MTX34 {
|
||||
// methods
|
||||
public:
|
||||
// cdtors
|
||||
MTX34() {}
|
||||
|
||||
// operators
|
||||
operator MtxPtr() { return mtx; }
|
||||
operator CMtxP() const { return mtx; }
|
||||
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _MTX34 */ // size 0x30, offset 0x00
|
||||
}; // size 0x30
|
||||
|
||||
struct MTX44 : public _MTX44 {
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
void Report(bool bNewline, char const* name) const;
|
||||
|
||||
// members
|
||||
public:
|
||||
/* base _MTX44 */ // size 0x24, offset 0x00
|
||||
}; // size 0x24
|
||||
|
||||
inline VEC3* VEC3Add(register VEC3* pOut, register VEC3 const* p1,
|
||||
register VEC3 const* p2) {
|
||||
register f32 a, b, c;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
// xy
|
||||
psq_l a, 0(p1), FALSE, qr0
|
||||
psq_l b, 0(p2), FALSE, qr0
|
||||
|
||||
ps_add c, a, b
|
||||
psq_st c, 0(pOut), FALSE, qr0
|
||||
|
||||
// z-
|
||||
psq_l a, 8(p1), TRUE, qr0
|
||||
psq_l b, 8(p2), TRUE, qr0
|
||||
|
||||
ps_add c, a, b
|
||||
psq_st c, 8(pOut), TRUE, qr0
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p1, p2, a, b, c)
|
||||
#endif
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline VEC3* VEC3Sub(register VEC3* pOut, register VEC3 const* p1,
|
||||
register VEC3 const* p2) {
|
||||
register f32 a, b, c;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
// xy
|
||||
psq_l a, 0(p1), FALSE, qr0
|
||||
psq_l b, 0(p2), FALSE, qr0
|
||||
|
||||
ps_sub c, a, b
|
||||
psq_st c, 0(pOut), FALSE, qr0
|
||||
|
||||
// z-
|
||||
psq_l a, 8(p1), TRUE, qr0
|
||||
psq_l b, 8(p2), TRUE, qr0
|
||||
|
||||
ps_sub c, a, b
|
||||
psq_st c, 8(pOut), TRUE, qr0
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p1, p2, a, b, c)
|
||||
#endif
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline VEC3* VEC3Scale(register VEC3* pOut, register VEC3 const* p, register f32 scale) {
|
||||
register f32 a, b;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
// xy
|
||||
psq_l a, 0(p), FALSE, qr0
|
||||
ps_muls0 b, a, scale
|
||||
psq_st b, 0(pOut), FALSE, qr0
|
||||
|
||||
// z-
|
||||
psq_l a, 8(p), TRUE, qr0
|
||||
ps_muls0 b, a, scale
|
||||
psq_st b, 8(pOut), TRUE, qr0
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p, scale, a, b)
|
||||
#endif
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline VEC3* VEC3Lerp(register VEC3* pOut, register VEC3 const* p1, register VEC3 const* p2,
|
||||
register f32 t) {
|
||||
register f32 a, b, c;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
// xy
|
||||
psq_l a, 0(p1), FALSE, qr0
|
||||
psq_l b, 0(p2), FALSE, qr0
|
||||
|
||||
ps_sub c, b, a
|
||||
ps_madds0 c, c, t, a
|
||||
psq_st c, 0(pOut), FALSE, qr0
|
||||
|
||||
// z-
|
||||
psq_l a, 8(p1), TRUE, qr0
|
||||
psq_l b, 8(p2), TRUE, qr0
|
||||
|
||||
ps_sub c, b, a
|
||||
ps_madds0 c, c, t, a
|
||||
psq_st c, 8(pOut), TRUE, qr0
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p1, p2, t, a, b, c)
|
||||
#endif
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline f32 VEC3Dot(register VEC3 const* p1, register VEC3 const* p2) {
|
||||
register f32 _v1, _v2, _v3, _v4, _v5;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
// yz
|
||||
psq_l _v2, 4(p1), FALSE, qr0
|
||||
psq_l _v3, 4(p2), FALSE, qr0
|
||||
|
||||
ps_mul _v2, _v2, _v3
|
||||
|
||||
// x-
|
||||
psq_l _v5, 0(p1), TRUE, qr0
|
||||
psq_l _v4, 0(p2), TRUE, qr0
|
||||
|
||||
ps_madd _v3, _v5, _v4, _v2
|
||||
ps_sum0 _v1, _v3, _v2, _v2
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p1, p2, _v2, _v3, _v4, _v5)
|
||||
_v1 = 0;
|
||||
#endif
|
||||
|
||||
return _v1;
|
||||
}
|
||||
|
||||
inline f32 VEC3LenSq(register VEC3 const* p) {
|
||||
register f32 vxy, vzz, sqmag;
|
||||
|
||||
#if defined(__MWERKS__)
|
||||
asm
|
||||
{
|
||||
#define qr0 0
|
||||
|
||||
psq_l vxy, 0(p), FALSE, qr0
|
||||
ps_mul vxy, vxy, vxy
|
||||
|
||||
lfs vzz, 8(p)
|
||||
ps_madd sqmag, vzz, vzz, vxy
|
||||
ps_sum0 sqmag, sqmag, vxy, vxy
|
||||
|
||||
#undef qr0
|
||||
}
|
||||
#else
|
||||
#pragma unused(p, vxy, vzz)
|
||||
sqmag = 0;
|
||||
#endif
|
||||
|
||||
return sqmag;
|
||||
}
|
||||
|
||||
inline VEC3* VEC3Cross(VEC3* pOut, VEC3 const* p1, VEC3 const* p2) {
|
||||
PSVECCrossProduct(*p1, *p2, *pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline VEC3* VEC3Normalize(VEC3* pOut, VEC3 const* p) {
|
||||
PSVECNormalize(*p, *pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline f32 VEC3DistSq(VEC3 const* p1, VEC3 const* p2) {
|
||||
return PSVECSquareDistance(*p1, *p2);
|
||||
}
|
||||
|
||||
// Line info puts these operators outside of the class body
|
||||
inline VEC3 VEC3::operator+(VEC3 const& rhs) const {
|
||||
VEC3 tmp;
|
||||
VEC3Add(&tmp, this, &rhs);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline VEC3 VEC3::operator-(VEC3 const& rhs) const {
|
||||
VEC3 tmp;
|
||||
VEC3Sub(&tmp, this, &rhs);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline VEC3 VEC3::operator*(f32 f) const {
|
||||
VEC3 tmp;
|
||||
VEC3Scale(&tmp, this, f);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline MTX34* MTX34Mult(MTX34* pOut, MTX34 const* p1, MTX34 const* p2) {
|
||||
PSMTXConcat(*p1, *p2, *pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline MTX34* MTX34Copy(MTX34* pOut, const MTX34* p) {
|
||||
PSMTXCopy(*p, *pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline MTX34* MTX34Identity(MTX34* pOut) {
|
||||
PSMTXIdentity(*pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
inline u32 MTX34Inv(MTX34* pOut, MTX34 const* p) {
|
||||
return PSMTXInverse(*p, *pOut);
|
||||
}
|
||||
|
||||
inline VEC3* VEC3TransformCoord(VEC3* pOut, MTX34 const* pM, VEC3 const* pV) {
|
||||
PSMTXMultVec(*pM, *pV, *pOut);
|
||||
|
||||
return pOut;
|
||||
}
|
||||
|
||||
VEC2* VEC2Maximize(VEC2* pOut, VEC2 const* p1, VEC2 const* p2);
|
||||
VEC2* VEC2Minimize(VEC2* pOut, VEC2 const* p1, VEC2 const* p2);
|
||||
VEC2* VEC2Normalize(VEC2* pOut, VEC2 const* p);
|
||||
|
||||
VEC3* VEC3Maximize(VEC3* pOut, VEC3 const* p1, VEC3 const* p2);
|
||||
VEC3* VEC3Minimize(VEC3* pOut, VEC3 const* p1, VEC3 const* p2);
|
||||
|
||||
VEC4* VEC4Add(VEC4* pOut, VEC4 const* p1, VEC4 const* p2);
|
||||
VEC4* VEC4Sub(VEC4* pOut, VEC4 const* p1, VEC4 const* p2);
|
||||
VEC4* VEC4Scale(VEC4* pOut, VEC4 const* p, f32 scale);
|
||||
VEC4* VEC4Lerp(VEC4* pOut, VEC4 const* p1, VEC4 const* p2, f32 t);
|
||||
f32 VEC4Dot(VEC4 const* p1, VEC4 const* p2);
|
||||
f32 VEC4LenSq(VEC4 const* p);
|
||||
f32 VEC4Len(VEC4 const* p);
|
||||
VEC4* VEC4Normalize(VEC4* pOut, VEC4 const* p);
|
||||
f32 VEC4DistSq(VEC4 const* p1, VEC4 const* p2);
|
||||
VEC4* VEC4Maximize(VEC4* pOut, VEC4 const* p1, VEC4 const* p2);
|
||||
VEC4* VEC4Minimize(VEC4* pOut, VEC4 const* p1, VEC4 const* p2);
|
||||
|
||||
MTX33* MTX33Copy(MTX33* pOut, MTX33 const* p);
|
||||
MTX33* MTX33Zero(MTX33* pOut);
|
||||
MTX33* MTX33Identity(MTX33* pOut);
|
||||
|
||||
MTX33* MTX34ToMTX33(MTX33* pOut, MTX34 const* pM);
|
||||
|
||||
MTX33* MTX33MAdd(MTX33* pOut, f32 t, MTX33 const* p1, MTX33 const* p2);
|
||||
|
||||
u32 MTX34InvTranspose(MTX33* inv, MTX34 const* src);
|
||||
MTX34* MTX34Zero(MTX34* pOut);
|
||||
bool MTX34IsIdentity(MTX34 const* p);
|
||||
MTX34* MTX34Add(MTX34* pOut, MTX34 const* p1, MTX34 const* p2);
|
||||
MTX34* MTX34Sub(MTX34* pOut, MTX34 const* p1, MTX34 const* p2);
|
||||
MTX34* MTX34Mult(MTX34* pOut, MTX34 const* p, f32 f);
|
||||
MTX34* MTX34Scale(MTX34* pOut, MTX34 const* pM, VEC3 const* pS);
|
||||
MTX34* MTX34Trans(MTX34* pOut, MTX34 const* pM, VEC3 const* pT);
|
||||
MTX34* MTX34MAdd(MTX34* pOut, f32 t, MTX34 const* p1, MTX34 const* p2);
|
||||
MTX34* MTX34RotAxisFIdx(MTX34* pOut, VEC3 const* pAxis, f32 fIdx);
|
||||
MTX34* MTX34RotXYZFIdx(MTX34* pOut, f32 fIdxX, f32 fIdxY, f32 fIdxZ);
|
||||
MTX34* MTX34RotXYZTransFIdx(MTX34* pOut, f32 fIdxX, f32 fIdxY, f32 fIdxZ, VEC3 const* pT);
|
||||
|
||||
VEC3* VEC3TransformNormal(VEC3* pOut, MTX34 const* pM, VEC3 const* pV);
|
||||
VEC3* VEC3TransformNormalArray(VEC3* pOut, MTX34 const* pM, VEC3 const* pV, u32 count);
|
||||
|
||||
MTX44* MTX44Zero(MTX44* pOut);
|
||||
MTX44* MTX44Identity(MTX44* pOut);
|
||||
MTX44* MTX44Copy(MTX44* pOut, MTX44 const* p);
|
||||
bool MTX44IsIdentity(MTX44 const* p);
|
||||
|
||||
VEC4* VEC3Transform(VEC4* pOut, MTX44 const* pM, VEC3 const* pV);
|
||||
VEC3* VEC3TransformCoord(VEC3* pOut, MTX44 const* pM, VEC3 const* pV);
|
||||
VEC4* VEC3TransformArray(VEC4* pOut, MTX44 const* pM, VEC3 const* pV, u32 count);
|
||||
VEC3* VEC3TransformCoordArray(VEC3* pOut, MTX44 const* pM, VEC3 const* pV, u32 count);
|
||||
|
||||
VEC4* VEC4Transform(VEC4* pOut, MTX44 const* pM, VEC4 const* pV);
|
||||
VEC4* VEC4TransformArray(VEC4* pOut, MTX44 const* pM, VEC4 const* pV, u32 count);
|
||||
} // namespace math
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif // NW4HBM_MATH_TYPES_H
|
||||
@@ -0,0 +1,125 @@
|
||||
#ifndef NW4HBM_SND_AX_MANAGER_H
|
||||
#define NW4HBM_SND_AX_MANAGER_H
|
||||
|
||||
#include "FxBase.h"
|
||||
|
||||
#include "AxVoice.h"
|
||||
#include "MoveValue.h"
|
||||
|
||||
#include <revolution/ai.h>
|
||||
#include <revolution/ax.h>
|
||||
|
||||
#include "../db/assert.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
class AxManager {
|
||||
public:
|
||||
typedef struct CallbackListNode {
|
||||
/* 0x00 */ ut::LinkListNode link;
|
||||
/* 0x08 */ AXCallback callback;
|
||||
} CallbackListNode;
|
||||
|
||||
typedef ut::LinkList<CallbackListNode, offsetof(CallbackListNode, link)>
|
||||
CallbackList;
|
||||
|
||||
static AxManager& GetInstance();
|
||||
|
||||
void Init();
|
||||
void Shutdown();
|
||||
void Update();
|
||||
|
||||
bool CheckInit() { return mInitialized; }
|
||||
|
||||
bool IsDiskError() const { return mDiskErrorFlag; }
|
||||
bool IsHomeButtonMenu() const { return mHomeButtonMuteFlag; }
|
||||
|
||||
bool IsResetReady() const { return mResetReadyCounter == 0; }
|
||||
|
||||
f32 GetOutputVolume() const;
|
||||
void* GetZeroBufferAddress();
|
||||
|
||||
void RegisterCallback(CallbackListNode* node, AXCallback callback);
|
||||
void UnregisterCallback(CallbackListNode* node);
|
||||
|
||||
void SetOutputMode(OutputMode mode);
|
||||
OutputMode GetOutputMode();
|
||||
|
||||
void UpdateAllVoicesPriority();
|
||||
void UpdateAllVoices();
|
||||
void UpdateAllVoicesSync(u32 syncFlag);
|
||||
|
||||
f32 GetMasterVolume() const { return mMasterVolume.GetValue(); }
|
||||
void SetMasterVolume(f32 volume, int frame);
|
||||
|
||||
bool AppendEffect(AuxBus bus, FxBase* fx);
|
||||
void ClearEffect(AuxBus bus, int frame);
|
||||
void ShutdownEffect(AuxBus bus);
|
||||
|
||||
FxList& GetEffectList(AuxBus bus) {
|
||||
NW4R_ASSERT_MINMAX(189, bus, AUX_A, AUX_BUS_NUM);
|
||||
return mFxList[bus];
|
||||
}
|
||||
|
||||
void AppendVoiceList(AxVoice* voice);
|
||||
void RemoveVoiceList(AxVoice* voice);
|
||||
|
||||
AxVoice* AllocVoice(int channels, int voices, int priority,
|
||||
AxVoice::AxVoiceCallback callback, void* callbackData);
|
||||
void FreeVoice(AxVoice* voice);
|
||||
|
||||
void ChangeVoicePriority(AxVoice* voice);
|
||||
void LockUpdateVoicePriority();
|
||||
void UnlockUpdateVoicePriority();
|
||||
|
||||
int DropLowestPriorityVoice(int priority);
|
||||
|
||||
AxVoiceList& GetVoiceList() { return mPrioVoiceList; }
|
||||
|
||||
private:
|
||||
static const u8 AUX_CALLBACK_WAIT_FRAME = 6;
|
||||
|
||||
static const int FX_SAMPLE_RATE = AX_SAMPLE_RATE;
|
||||
static const SampleFormat FX_SAMPLE_FORMAT = SAMPLE_FORMAT_PCM_S32;
|
||||
static const int FX_BUFFER_SIZE = AX_FRAME_SIZE;
|
||||
|
||||
static const int ZERO_BUFFER_SIZE = 256;
|
||||
|
||||
AxManager();
|
||||
|
||||
static void AxCallbackFunc();
|
||||
static void AuxCallbackFunc(void* chans, void* context);
|
||||
|
||||
/* 0x0000 */ OutputMode mOutputMode;
|
||||
/* 0x0004 */ void* mZeroBufferAddress;
|
||||
/* 0x0008 */ CallbackList mCallbackList;
|
||||
/* 0x0014 */ AxVoiceList mPrioVoiceList;
|
||||
/* 0x0020 */ AxVoiceList mFreeVoiceList;
|
||||
/* 0x002C */ AxVoice mVoices[AX_MAX_VOICES];
|
||||
/* 0xA22C */ AXCallback mNextAxRegisterCallback;
|
||||
/* 0xA230 */ bool mInitialized;
|
||||
/* 0xA231 */ bool mUpdateVoicePrioFlag;
|
||||
/* 0xA232 */ bool mHomeButtonMuteFlag;
|
||||
/* 0xA233 */ bool mDiskErrorFlag;
|
||||
/* 0xA234 */ MoveValue<f32, int> mHomeButtonMenuVolume;
|
||||
/* 0xA244 */ MoveValue<f32, int> mMasterVolume;
|
||||
/* 0xA254 */ MoveValue<f32, int> mVolumeForReset;
|
||||
/* 0xA264 */ AIDCallback mOldAidCallback;
|
||||
/* 0xA268 */ vs32 mResetReadyCounter;
|
||||
/* 0xA26C */ MoveValue<f32, int> mAuxFadeVolume[AUX_BUS_NUM];
|
||||
/* 0xA29C */ MoveValue<f32, int> mAuxUserVolume[AUX_BUS_NUM];
|
||||
/* 0xA2CC */ FxList mFxList[AUX_BUS_NUM];
|
||||
/* 0xA2F0 */ AXCallback mAuxCallback[AUX_BUS_NUM];
|
||||
/* 0xA2FC */ void* mAuxCallbackContext[AUX_BUS_NUM];
|
||||
/* 0xA308 */ u8 mAuxCallbackWaitCounter[AUX_BUS_NUM];
|
||||
|
||||
static u8 sZeroBuffer[ZERO_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,321 @@
|
||||
#ifndef NW4HBM_SND_AX_VOICE_H
|
||||
#define NW4HBM_SND_AX_VOICE_H
|
||||
|
||||
#include <revolution/ax.h>
|
||||
#include <revolution/wpad.h>
|
||||
#include "DisposeCallbackManager.h"
|
||||
#include "limits.h"
|
||||
#include "snd_global.h"
|
||||
#include "snd_types.h"
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
#include "global.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
inline int CalcAxvpbDelta(u16 init, u16 target) {
|
||||
return (target - init) / AX_SAMPLES_PER_FRAME;
|
||||
}
|
||||
|
||||
inline u16 CalcMixVolume(f32 volume) {
|
||||
return ut::Min<u32>(USHRT_MAX, AX_MAX_VOLUME * volume);
|
||||
}
|
||||
|
||||
class AxVoiceParamBlock {
|
||||
public:
|
||||
AxVoiceParamBlock();
|
||||
|
||||
operator AXVPB*() { return mVpb; }
|
||||
|
||||
bool IsAvailable() const { return mVpb != NULL; }
|
||||
|
||||
bool IsRun() const { return IsAvailable() && mVpb->pb.state == AX_VOICE_RUN; }
|
||||
|
||||
u32 GetCurrentAddress() const {
|
||||
if (!IsAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mVpb->pb.addr.currentAddressHi << 16) + mVpb->pb.addr.currentAddressLo;
|
||||
}
|
||||
|
||||
u32 GetLoopAddress() const {
|
||||
if (!IsAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mVpb->pb.addr.loopAddressHi << 16) + mVpb->pb.addr.loopAddressLo;
|
||||
}
|
||||
|
||||
u32 GetEndAddress() const {
|
||||
if (!IsAvailable()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (mVpb->pb.addr.endAddressHi << 16) + mVpb->pb.addr.endAddressLo;
|
||||
}
|
||||
|
||||
void SetVoiceAddr(const AXPBADDR& rAddr) {
|
||||
if (IsAvailable()) {
|
||||
// AXSetVoiceAddr doesn't actually modify the object
|
||||
AXSetVoiceAddr(mVpb, const_cast<AXPBADDR*>(&rAddr));
|
||||
}
|
||||
}
|
||||
|
||||
void SetVoicePriority(u32 priority) {
|
||||
if (IsAvailable()) {
|
||||
AXSetVoicePriority(mVpb, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVoiceStateRun() {
|
||||
if (IsAvailable()) {
|
||||
AXSetVoiceState(mVpb, AX_VOICE_RUN);
|
||||
}
|
||||
}
|
||||
|
||||
void SetVoiceStateStop() {
|
||||
if (IsRun()) {
|
||||
AXSetVoiceState(mVpb, AX_VOICE_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
void Sync();
|
||||
bool IsRmtIirEnable() const;
|
||||
|
||||
void Set(AXVPB* pVpb);
|
||||
void Clear();
|
||||
|
||||
void SetVoiceType(u16 type);
|
||||
void SetVoiceVe(u16 volume, u16 initVolume);
|
||||
void SetVoiceMix(const AXPBMIX& rMix, bool syncNow);
|
||||
void SetVoiceLoop(u16 loop);
|
||||
void SetVoiceLoopAddr(u32 addr);
|
||||
void SetVoiceEndAddr(u32 addr);
|
||||
void SetVoiceAdpcm(const AXPBADPCM& rAdpcm);
|
||||
void SetVoiceSrcType(u32 type);
|
||||
void SetVoiceSrc(const AXPBSRC& rSrc);
|
||||
void SetVoiceSrcRatio(f32 ratio);
|
||||
void SetVoiceAdpcmLoop(const AXPBADPCMLOOP& rLoop);
|
||||
void SetVoiceLpf(const AXPBLPF& rLpf);
|
||||
void SetVoiceLpfCoefs(u16 a0, u16 b0);
|
||||
void SetVoiceRmtOn(u16 on);
|
||||
void SetVoiceRmtMix(const AXPBRMTMIX& rMix);
|
||||
void SetVoiceRmtIIR(const AXPBRMTIIR& rIir);
|
||||
void SetVoiceRmtIIRCoefs(u16 type, ...);
|
||||
void UpdateDelta();
|
||||
|
||||
private:
|
||||
static const u16 DEFAULT_VOLUME = AX_MAX_VOLUME;
|
||||
|
||||
private:
|
||||
/* 0x00 */ AXVPB* mVpb;
|
||||
/* 0x04 */ u32 mSync;
|
||||
/* 0x08 */ volatile AXPBVE mPrevVeSetting;
|
||||
/* 0x0C */ bool mFirstVeUpdateFlag;
|
||||
/* 0x0E */ u16 mVolume;
|
||||
};
|
||||
|
||||
class WaveData;
|
||||
class AxVoice : public DisposeCallback {
|
||||
friend class AxManager;
|
||||
|
||||
public:
|
||||
typedef enum CallbackStatus {
|
||||
CALLBACK_STATUS_FINISH_WAVE = 0,
|
||||
CALLBACK_STATUS_INVALIDATE_WAVE,
|
||||
CALLBACK_STATUS_DROP_VOICE,
|
||||
CALLBACK_STATUS_DROP_DSP
|
||||
} CallbackStatus;
|
||||
|
||||
typedef enum VoiceSyncFlag {
|
||||
SYNC_AX_SRC_INITIAL = (1 << 0),
|
||||
SYNC_AX_VOICE = (1 << 1),
|
||||
SYNC_AX_SRC = (1 << 3),
|
||||
SYNC_AX_VE = (1 << 4),
|
||||
SYNC_AX_MIX = (1 << 5),
|
||||
SYNC_AX_LPF = (1 << 6),
|
||||
SYNC_AX_REMOTE = (1 << 7),
|
||||
SYNC_AX_BIQUAD = (1 << 8),
|
||||
} VoiceSyncFlag;
|
||||
|
||||
typedef enum Format {
|
||||
FORMAT_PCM16 = 10,
|
||||
FORMAT_PCM8 = 25,
|
||||
FORMAT_ADPCM = 0
|
||||
} Format;
|
||||
|
||||
typedef enum VoiceType { VOICE_TYPE_NORMAL = 0, VOICE_TYPE_STREAM } VoiceType;
|
||||
|
||||
typedef enum SrcType {
|
||||
SRC_NONE = 0,
|
||||
SRC_LINEAR,
|
||||
SRC_4TAP_8K,
|
||||
SRC_4TAP_12K,
|
||||
SRC_4TAP_16K,
|
||||
SRC_4TAP_AUTO
|
||||
} SrcType;
|
||||
|
||||
typedef void (*AxVoiceCallback)(AxVoice* drovoice, CallbackStatus status,
|
||||
void* callbackArg);
|
||||
|
||||
AxVoice();
|
||||
|
||||
/* 0x08 */ virtual ~AxVoice();
|
||||
/* 0x0C */ virtual void InvalidateData(const void* start, const void* end) {}
|
||||
/* 0x10 */ virtual void InvalidateWaveData(const void* start, const void* end);
|
||||
|
||||
void Setup(const WaveData& waveParam);
|
||||
void Update();
|
||||
void Free();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
void Pause(bool flag);
|
||||
|
||||
void SetVolume(f32 volume);
|
||||
void SetVeVolume(f32 targetVolume, f32 initVolume);
|
||||
void SetMainOutVolume(f32 volume);
|
||||
void SetRemoteOutVolume(int remoteIndex, f32 volume);
|
||||
|
||||
void SetPitch(f32 pitch);
|
||||
void SetPan(f32 pan);
|
||||
void SetPan2(f32 pan);
|
||||
void SetSurroundPan(f32 surroundPan);
|
||||
void SetSurroundPan2(f32 surroundPan);
|
||||
|
||||
void SetLpfFreq(f32 lpfFreq);
|
||||
|
||||
void SetOutputLine(int lineFlag);
|
||||
|
||||
void SetMainSend(f32 send);
|
||||
void SetFxSend(AuxBus bus, f32 send);
|
||||
void SetRemoteSend(int remoteIndex, f32 send);
|
||||
void SetRemoteFxSend(int remoteIndex, f32 send);
|
||||
|
||||
void SetPriority(int priority);
|
||||
int GetPriority() const { return mPriority; }
|
||||
|
||||
u32 GetCurrentPlayingDspAddress() const;
|
||||
u32 GetLoopStartDspAddress() const;
|
||||
u32 GetLoopEndDspAddress() const;
|
||||
|
||||
u32 GetCurrentPlayingSample() const;
|
||||
|
||||
void SetAdpcmLoop(int channelIndex, Format format, const AdpcmLoopParam* param);
|
||||
void SetBaseAddress(int channelIndex, const void* baseAddress);
|
||||
|
||||
bool IsPlayFinished() const;
|
||||
bool IsRun();
|
||||
|
||||
void SetAxAddr(int channelIndex, bool loopFlag, Format format, const void* waveAddr,
|
||||
u32 loopStart, u32 loopEnd);
|
||||
|
||||
void SetLoopStart(int channelIndex, const void* baseAddress, u32 samples);
|
||||
void SetLoopEnd(int channelIndex, const void* baseAddress, u32 samples);
|
||||
void SetLoopFlag(bool loopFlag);
|
||||
|
||||
void StopAtPoint(int channelIndex, const void* baseAddress, u32 samples);
|
||||
void SetVoiceType(VoiceType type);
|
||||
|
||||
void UpdateAxSrc(bool initialUpdate);
|
||||
void SetAxSrcType(SrcType type);
|
||||
|
||||
void SetAxAdpcm(int channelIndex, Format format, const AdpcmParam* param);
|
||||
void SetAxAdpcmLoop(int channelIndex, Format format,
|
||||
const AdpcmLoopParam* param) NO_INLINE;
|
||||
|
||||
bool UpdateAxVe();
|
||||
void UpdateAxMix();
|
||||
void UpdateAxLpf();
|
||||
|
||||
void InitParam(int channelCount, int voiceOutCount, AxVoiceCallback callback,
|
||||
void* callbackData);
|
||||
bool Acquire(int channelCount, int voiceOutCount, int priority,
|
||||
AxVoiceCallback callback, void* callbackData);
|
||||
|
||||
int GetAxVoiceCount() const { return mChannelCount * mVoiceOutCount; }
|
||||
|
||||
static u32 GetDspAddressBySample(const void* baseAddress, u32 samples,
|
||||
Format format);
|
||||
static u32 GetSampleByDspAddress(const void* baseAddress, u32 addr, Format format);
|
||||
static u32 GetSampleByByte(u32 byte, Format format);
|
||||
|
||||
template <typename T>
|
||||
void SetAxParam(void (*func)(AXVPB*, T), T param) {
|
||||
for (int i = 0; i < mChannelCount; i++) {
|
||||
for (int j = 0; j < mVoiceOutCount; j++) {
|
||||
if (mVpb[i][j] != NULL) {
|
||||
func(mVpb[i][j], param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Format GetFormat() { return mFormat; }
|
||||
|
||||
static const int VOICES_MAX = 4;
|
||||
static const int PRIORITY_MAX = 255;
|
||||
|
||||
protected:
|
||||
static void VoiceCallback(void* callbackData);
|
||||
|
||||
void TransformDpl2Pan(f32* outPan, f32* outSurroundPan, f32 inPan,
|
||||
f32 inSurroundPan);
|
||||
|
||||
void CalcAXPBMIX(int channelIndex, int voiceIndex, AXPBMIX* mix);
|
||||
void CalcAXPBRMTMIX(int channelIndex, int voiceIndex, AXPBRMTMIX* mix);
|
||||
|
||||
/* 0x000 (base) */
|
||||
/* 0x00C */ AXVPB* mVpb[CHANNEL_MAX][VOICES_MAX];
|
||||
/* 0x02C */ VoiceChannelParam mVoiceChannelParam[CHANNEL_MAX];
|
||||
/* 0x094 */ SoundParam mVoiceOutParam[VOICES_MAX];
|
||||
/* 0x104 */ s32 mChannelCount;
|
||||
/* 0x108 */ s32 mVoiceOutCount;
|
||||
/* 0x10C */ AxVoiceCallback mCallback;
|
||||
/* 0x110 */ void* mCallbackData;
|
||||
/* 0x114 */ int mSampleRate;
|
||||
/* 0x118 */ Format mFormat;
|
||||
/* 0x11C */ bool mActiveFlag;
|
||||
/* 0x11D */ bool mStartFlag;
|
||||
/* 0x11E */ bool mStartedFlag;
|
||||
/* 0x11F */ bool mPauseFlag;
|
||||
/* 0x120 */ bool mPausingFlag;
|
||||
/* 0x121 */ bool mFirstVeUpdateFlag;
|
||||
/* 0x122 */ bool mHomeButtonMuteFlag;
|
||||
/* 0x123 */ u8 mSyncFlag;
|
||||
/* 0x124 */ int mPriority;
|
||||
/* 0x128 */ f32 mPan;
|
||||
/* 0x12C */ f32 mSurroundPan;
|
||||
/* 0x130 */ f32 mPan2;
|
||||
/* 0x134 */ f32 mSurroundPan2;
|
||||
/* 0x138 */ f32 mLpfFreq;
|
||||
/* 0x13C */ int mOutputLineFlag;
|
||||
/* 0x140 */ f32 mMainOutVolume;
|
||||
/* 0x144 */ f32 mMainSend;
|
||||
/* 0x148 */ f32 mFxSend[AUX_BUS_NUM];
|
||||
/* 0x154 */ f32 mRemoteOutVolume[VOICES_MAX];
|
||||
/* 0x164 */ f32 mRemoteSend[VOICES_MAX];
|
||||
/* 0x174 */ f32 mRemoteFxSend[VOICES_MAX];
|
||||
/* 0x184 */ f32 mPitch;
|
||||
/* 0x188 */ f32 mVolume;
|
||||
/* 0x18C */ f32 mVolumePrev[VOICES_MAX];
|
||||
/* 0x19C */ f32 mVeInitVolume;
|
||||
/* 0x1A0 */ f32 mVeTargetVolume;
|
||||
/* 0x1A4 */ u16 mGainPrev;
|
||||
|
||||
public:
|
||||
/* 0x1A8 */ ut::LinkListNode mLinkNode;
|
||||
};
|
||||
|
||||
typedef ut::LinkList<AxVoice, offsetof(AxVoice, mLinkNode)> AxVoiceList;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef NW4HBM_SND_BANK_H
|
||||
#define NW4HBM_SND_BANK_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "BankFile.h"
|
||||
#include "NoteOnCallback.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
class Channel;
|
||||
|
||||
class Bank {
|
||||
public:
|
||||
explicit Bank(const void* bankData);
|
||||
~Bank();
|
||||
|
||||
Channel* NoteOn(const NoteOnInfo& noteOnInfo) const;
|
||||
|
||||
void SetWaveDataAddress(const void* waveData) {
|
||||
NW4HBM_ASSERT_CHECK_NULL(47, waveData);
|
||||
mWaveDataAddress = waveData;
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x00 */ BankFileReader mBankReader;
|
||||
/* 0x0C */ const void* mWaveDataAddress;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef NW4HBM_SND_BANK_FILE_H
|
||||
#define NW4HBM_SND_BANK_FILE_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "Util.h"
|
||||
#include "WaveFile.h"
|
||||
|
||||
#include "../ut/binaryFileFormat.h"
|
||||
|
||||
#include <revolution/hbm.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
inline u8 ReadByte(const void* address) {
|
||||
return *static_cast<const u8*>(address);
|
||||
}
|
||||
|
||||
namespace BankFile {
|
||||
|
||||
static const u32 SIGNATURE_FILE = 'RBNK';
|
||||
static const u32 SIGNATURE_DATA_BLOCK = 'DATA';
|
||||
static const u32 SIGNATURE_WAVE_BLOCK = 'WAVE';
|
||||
|
||||
typedef struct InstParam {
|
||||
/* 0x00 */ s32 waveIndex;
|
||||
/* 0x04 */ u8 attack;
|
||||
/* 0x05 */ u8 decay;
|
||||
/* 0x06 */ u8 sustain;
|
||||
/* 0x07 */ u8 release;
|
||||
/* 0x08 */ u16 hold;
|
||||
/* 0x0A */ u16 padding;
|
||||
/* 0x0C */ u8 originalKey;
|
||||
/* 0x0D */ u8 volume;
|
||||
/* 0x0E */ u8 pan;
|
||||
/* 0x0F */ u8 padding2;
|
||||
/* 0x10 */ f32 tune;
|
||||
/* 0x14 */ Util::DataRef<void> lfoTableRef;
|
||||
/* 0x1C */ Util::DataRef<void> graphEnvTablevRef;
|
||||
/* 0x24 */ Util::DataRef<void> randomizerTableRef;
|
||||
/* 0x2C */ u32 reserved;
|
||||
} InstParam;
|
||||
|
||||
typedef struct RangeTable {
|
||||
/* 0x00 */ u8 tableSize;
|
||||
/* 0x01 */ u8 key[];
|
||||
} RangeTable;
|
||||
|
||||
typedef struct IndexTable IndexTable;
|
||||
|
||||
typedef Util::DataRef<void, InstParam, RangeTable, IndexTable> DataRegion;
|
||||
typedef Util::DataRef<WaveFile::WaveInfo> WaveRegion;
|
||||
|
||||
struct IndexTable {
|
||||
/* 0x00 */ u8 min;
|
||||
/* 0x01 */ u8 max;
|
||||
/* 0x02 */ u16 reserved;
|
||||
/* 0x04 */ DataRegion ref[];
|
||||
};
|
||||
|
||||
typedef struct Header {
|
||||
/* 0x00 */ ut::BinaryFileHeader fileHeader;
|
||||
/* 0x10 */ u32 dataBlockOffset;
|
||||
/* 0x14 */ u32 dataBlockSize;
|
||||
/* 0x18 */ u32 waveBlockOffset;
|
||||
/* 0x1C */ u32 waveBlockSize;
|
||||
} Header;
|
||||
|
||||
typedef struct DataBlock {
|
||||
/* 0x00 */ ut::BinaryBlockHeader blockHeader;
|
||||
/* 0x08 */ Util::Table<DataRegion> instTable;
|
||||
} DataBlock;
|
||||
|
||||
typedef struct WaveBlock {
|
||||
/* 0x00 */ ut::BinaryBlockHeader blockHeader;
|
||||
/* 0x08 */ Util::Table<WaveRegion> waveInfoTable;
|
||||
} WaveBlock;
|
||||
|
||||
} // namespace BankFile
|
||||
|
||||
typedef struct InstInfo {
|
||||
/* 0x00 */ s32 waveIndex;
|
||||
/* 0x04 */ u8 attack;
|
||||
/* 0x05 */ u8 decay;
|
||||
/* 0x06 */ u8 sustain;
|
||||
/* 0x07 */ u8 release;
|
||||
/* 0x08 */ u8 originalKey;
|
||||
/* 0x09 */ u8 pan;
|
||||
/* 0x0A */ u8 volume;
|
||||
/* 0x0C */ f32 tune;
|
||||
} InstInfo;
|
||||
|
||||
class BankFileReader {
|
||||
public:
|
||||
static const int FILE_VERSION = NW4HBM_VERSION(1, 1);
|
||||
|
||||
public:
|
||||
explicit BankFileReader(const void* bankData);
|
||||
|
||||
bool IsValidFileHeader(const void* bankData);
|
||||
|
||||
bool ReadInstInfo(InstInfo* instInfo, int prgNo, int key, int velocity) const;
|
||||
bool ReadWaveParam(WaveData* waveParam, int waveIndex,
|
||||
const void* waveDataAddress) const;
|
||||
|
||||
private:
|
||||
const BankFile::DataRegion* GetReferenceToSubRegion(const BankFile::DataRegion* ref,
|
||||
int splitKey) const;
|
||||
|
||||
private:
|
||||
/* 0x00 */ const BankFile::Header* mHeader;
|
||||
/* 0x04 */ const BankFile::DataBlock* mDataBlock;
|
||||
/* 0x08 */ const BankFile::WaveBlock* mWaveBlock;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef NW4HBM_SND_BASIC_PLAYER_H
|
||||
#define NW4HBM_SND_BASIC_PLAYER_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include "snd_types.h"
|
||||
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
namespace {
|
||||
|
||||
class BasicPlayer {
|
||||
public:
|
||||
BasicPlayer() : mId(-1) {}
|
||||
|
||||
/* 0x08 */ virtual ~BasicPlayer()
|
||||
#ifdef MAKE_DTOR_ZERO
|
||||
= 0
|
||||
#endif
|
||||
{};
|
||||
|
||||
/* 0x0C */ virtual bool Start() = 0;
|
||||
/* 0x10 */ virtual void Stop() = 0;
|
||||
/* 0x14 */ virtual void Pause(bool flag) = 0;
|
||||
/* 0x18 */ virtual bool IsActive() const = 0;
|
||||
/* 0x1C */ virtual bool IsPrepared() const = 0;
|
||||
/* 0x20 */ virtual bool IsStarted() const = 0;
|
||||
/* 0x24 */ virtual bool IsPause() const = 0;
|
||||
/* 0x28 */ virtual void SetVolume(f32 volume) = 0;
|
||||
/* 0x2C */ virtual void SetPitch(f32 pitch) = 0;
|
||||
/* 0x30 */ virtual void SetPan(f32 pan) = 0;
|
||||
/* 0x34 */ virtual void SetSurroundPan(f32 surroundPan) = 0;
|
||||
/* 0x38 */ virtual void SetPan2(f32 pan2) = 0;
|
||||
/* 0x3C */ virtual void SetSurroundPan2(f32 surroundPan2) = 0;
|
||||
/* 0x40 */ virtual void SetLpfFreq(f32 lpfFreq) = 0;
|
||||
/* 0x44 */ virtual f32 GetVolume() const = 0;
|
||||
/* 0x48 */ virtual f32 GetPitch() const = 0;
|
||||
/* 0x4C */ virtual f32 GetPan() const = 0;
|
||||
/* 0x50 */ virtual f32 GetSurroundPan() const = 0;
|
||||
/* 0x54 */ virtual f32 GetPan2() const = 0;
|
||||
/* 0x58 */ virtual f32 GetSurroundPan2() const = 0;
|
||||
/* 0x5C */ virtual f32 GetLpfFreq() const = 0;
|
||||
/* 0x60 */ virtual void SetOutputLine(int lineFlag) = 0;
|
||||
/* 0x64 */ virtual void SetMainOutVolume(f32 volume) = 0;
|
||||
/* 0x68 */ virtual void SetMainSend(f32 send) = 0;
|
||||
/* 0x6C */ virtual void SetFxSend(AuxBus bus, f32 send) = 0;
|
||||
/* 0x70 */ virtual void SetRemoteOutVolume(int remoteIndex, f32 volume) = 0;
|
||||
/* 0x74 */ virtual void SetRemoteSend(int remoteIndex, f32 send) = 0;
|
||||
/* 0x78 */ virtual void SetRemoteFxSend(int remoteIndex, f32 send) = 0;
|
||||
/* 0x7C */ virtual int GetOutputLine() const = 0;
|
||||
/* 0x80 */ virtual f32 GetMainOutVolume() const = 0;
|
||||
/* 0x84 */ virtual f32 GetMainSend() const = 0;
|
||||
/* 0x88 */ virtual f32 GetFxSend(AuxBus bus) const = 0;
|
||||
/* 0x8C */ virtual f32 GetRemoteOutVolume(int remoteIndex) const = 0;
|
||||
/* 0x90 */ virtual f32 GetRemoteSend(int remoteIndex) const = 0;
|
||||
/* 0x94 */ virtual f32 GetRemoteFxSend(int remoteIndex) const = 0;
|
||||
|
||||
u32 GetId() const { return mId; }
|
||||
void SetId(u32 id) { mId = id; }
|
||||
|
||||
private:
|
||||
/* 0x04 */ u32 mId;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,214 @@
|
||||
#ifndef NW4HBM_SND_BASIC_SOUND_H
|
||||
#define NW4HBM_SND_BASIC_SOUND_H
|
||||
|
||||
#include <revolution/types.h>
|
||||
#include <revolution/wpad.h>
|
||||
|
||||
#include "MoveValue.h"
|
||||
#include "snd_global.h"
|
||||
#include "snd_types.h"
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
#include "../ut/RuntimeTypeInfo.h"
|
||||
#include "../ut/inlines.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
|
||||
class SoundHandle;
|
||||
class SoundPlayer;
|
||||
|
||||
namespace detail {
|
||||
namespace {
|
||||
class BasicPlayer;
|
||||
}
|
||||
class ExternalSoundPlayer;
|
||||
class PlayerHeap;
|
||||
} // namespace detail
|
||||
|
||||
namespace detail {
|
||||
class BasicSound {
|
||||
public:
|
||||
typedef struct AmbientParamUpdateCallback {
|
||||
typedef enum ParamUpdateFlags {
|
||||
/* 1 */ PARAM_UPDATE_VOLUME = (1 << 0),
|
||||
/* 2 */ PARAM_UPDATE_PAN = (1 << 1),
|
||||
/* 4 */ PARAM_UPDATE_SURROUND_PAN = (1 << 2),
|
||||
/* 8 */ PARAM_UPDATE_PRIORITY = (1 << 3),
|
||||
} ParamUpdateFlags;
|
||||
|
||||
/* 0x0C */ virtual void detail_Update(SoundParam* param, u32 id,
|
||||
BasicSound* sound, const void* arg,
|
||||
u32 flags) = 0;
|
||||
} AmbientParamUpdateCallback;
|
||||
|
||||
typedef struct AmbientArgUpdateCallback {
|
||||
/* 0x0C */ virtual void detail_Update(void* arg, const BasicSound* sound) = 0;
|
||||
} AmbientArgUpdateCallback;
|
||||
|
||||
typedef struct AmbientArgAllocaterCallback {
|
||||
/* 0x0C */ virtual void* detail_AllocAmbientArg(u32 size) = 0;
|
||||
/* 0x10 */ virtual void detail_FreeAmbientArg(void* arg,
|
||||
const BasicSound* sound) = 0;
|
||||
} AmbientArgAllocaterCallback;
|
||||
|
||||
typedef struct AmbientArgInfo {
|
||||
/* 0x00 */ AmbientParamUpdateCallback* paramUpdateCallback;
|
||||
/* 0x04 */ AmbientArgUpdateCallback* argUpdateCallback;
|
||||
/* 0x08 */ AmbientArgAllocaterCallback* argAllocaterCallback;
|
||||
/* 0x0C */ void* arg;
|
||||
/* 0x10 */ u32 argSize;
|
||||
} AmbientArgInfo;
|
||||
|
||||
static const u32 INVALID_ID = 0xFFFFFFFF;
|
||||
static const int PRIORITY_MAX = 127;
|
||||
|
||||
public:
|
||||
BasicSound();
|
||||
|
||||
/* 0x08 */ NW4HBM_UT_RUNTIME_TYPEINFO;
|
||||
/* 0x0C */ virtual ~BasicSound() {}
|
||||
/* 0x10 */ virtual void Update();
|
||||
/* 0x14 */ virtual void StartPrepared();
|
||||
/* 0x18 */ virtual void Stop(int frames = 0);
|
||||
/* 0x1C */ virtual void Pause(bool flag, int frames);
|
||||
/* 0x20 */ virtual void SetAutoStopCounter(int count);
|
||||
/* 0x24 */ virtual void FadeIn(int frames);
|
||||
/* 0x28 */ virtual void Shutdown();
|
||||
/* 0x2C */ virtual bool IsPrepared() const;
|
||||
/* 0x30 */ virtual bool IsPause() const;
|
||||
/* 0x34 */ virtual void SetInitialVolume(f32 volume);
|
||||
/* 0x38 */ virtual void SetVolume(f32 volume, int frames);
|
||||
/* 0x3C */ virtual void SetPitch(f32 pitch);
|
||||
/* 0x40 */ virtual void SetPan(f32 pan);
|
||||
/* 0x44 */ virtual void SetSurroundPan(f32 pan);
|
||||
/* 0x48 */ virtual void SetLpfFreq(f32 freq);
|
||||
/* 0x4C */ virtual void SetPlayerPriority(int priority);
|
||||
/* 0x50 */ virtual bool IsAttachedTempSpecialHandle() = 0;
|
||||
/* 0x54 */ virtual void DetachTempSpecialHandle() = 0;
|
||||
/* 0x58 */ virtual void InitParam();
|
||||
/* 0x5C */ virtual BasicPlayer& GetBasicPlayer() = 0;
|
||||
/* 0x60 */ virtual const BasicPlayer& GetBasicPlayer() const = 0;
|
||||
|
||||
PlayerHeap* GetPlayerHeap() { return mHeap; }
|
||||
void SetPlayerHeap(PlayerHeap* heap) { mHeap = heap; }
|
||||
|
||||
bool IsAttachedGeneralHandle();
|
||||
void DetachGeneralHandle();
|
||||
|
||||
bool IsAttachedTempGeneralHandle();
|
||||
void DetachTempGeneralHandle();
|
||||
|
||||
SoundPlayer* GetSoundPlayer() { return mSoundPlayer; }
|
||||
void SetSoundPlayer(SoundPlayer* player) { mSoundPlayer = player; }
|
||||
|
||||
ExternalSoundPlayer* GetExternalSoundPlayer() { return mExtSoundPlayer; }
|
||||
void SetExternalSoundPlayer(ExternalSoundPlayer* extPlayer) {
|
||||
mExtSoundPlayer = extPlayer;
|
||||
}
|
||||
|
||||
AmbientParamUpdateCallback* GetAmbientParamUpdateCallback() {
|
||||
return mAmbientParamUpdateCallback;
|
||||
}
|
||||
AmbientArgUpdateCallback* GetAmbientArgUpdateCallback() {
|
||||
return mAmbientArgUpdateCallback;
|
||||
}
|
||||
void ClearAmbientArgUpdateCallback() { mAmbientArgUpdateCallback = NULL; }
|
||||
|
||||
AmbientArgAllocaterCallback* GetAmbientArgAllocaterCallback() {
|
||||
return mAmbientArgAllocaterCallback;
|
||||
}
|
||||
|
||||
void* GetAmbientArg() { return mAmbientArg; }
|
||||
SoundParam& GetAmbientParam() { return mAmbientParam; }
|
||||
|
||||
void SetAmbientParamCallback(AmbientParamUpdateCallback* paramUpdateCallback,
|
||||
AmbientArgUpdateCallback* argUpdateCallback,
|
||||
AmbientArgAllocaterCallback* argAllocaterCallback,
|
||||
void* callbackArg);
|
||||
|
||||
void SetPriority(int priority) { mPriority = priority; }
|
||||
|
||||
u32 GetId() const { return mId; }
|
||||
void SetId(u32 id);
|
||||
|
||||
f32 GetMoveVolume() { return mExtMoveVolume.GetValue(); }
|
||||
|
||||
f32 GetInitialVolume() const;
|
||||
f32 GetPan() const;
|
||||
f32 GetSurroundPan() const;
|
||||
f32 GetPitch() const;
|
||||
f32 GetVolume() const;
|
||||
|
||||
void SetOutputLine(int flag);
|
||||
bool IsEnabledOutputLine() const;
|
||||
int GetOutputLine() const;
|
||||
|
||||
f32 GetMainOutVolume() const;
|
||||
void SetMainOutVolume(f32 volume);
|
||||
|
||||
f32 GetRemoteOutVolume(int remote) const;
|
||||
void SetRemoteOutVolume(int remote, f32 volume);
|
||||
|
||||
void SetFxSend(AuxBus bus, f32 send);
|
||||
|
||||
int CalcCurrentPlayerPriority() const {
|
||||
return ut::Clamp(mPriority + mAmbientParam.priority, (s32)0, (s32)PRIORITY_MAX);
|
||||
}
|
||||
|
||||
private:
|
||||
/* 0x04 */ PlayerHeap* mHeap;
|
||||
/* 0x08 */ SoundHandle* mGeneralHandle;
|
||||
/* 0x0C */ SoundHandle* mTempGeneralHandle;
|
||||
/* 0x10 */ SoundPlayer* mSoundPlayer;
|
||||
/* 0x14 */ ExternalSoundPlayer* mExtSoundPlayer;
|
||||
/* 0x18 */ AmbientParamUpdateCallback* mAmbientParamUpdateCallback;
|
||||
/* 0x1C */ AmbientArgUpdateCallback* mAmbientArgUpdateCallback;
|
||||
/* 0x20 */ AmbientArgAllocaterCallback* mAmbientArgAllocaterCallback;
|
||||
/* 0x24 */ void* mAmbientArg;
|
||||
/* 0x28 */ SoundParam mAmbientParam;
|
||||
/* 0x44 */ MoveValue<f32, int> mFadeVolume;
|
||||
/* 0x54 */ MoveValue<f32, int> mPauseFadeVolume;
|
||||
/* 0x64 */ bool mStartFlag;
|
||||
/* 0x65 */ bool mStartedFlag;
|
||||
/* 0x66 */ bool mAutoStopFlag;
|
||||
/* 0x67 */ bool mPauseFlag;
|
||||
/* 0x68 */ bool mPauseFadeFlag;
|
||||
/* 0x69 */ bool mFadeOutFlag;
|
||||
/* 0x6C */ int mAutoStopCounter;
|
||||
/* 0x70 */ u32 mUpdateCounter;
|
||||
/* 0x74 */ u8 mPriority;
|
||||
/* 0x78 */ u32 mId;
|
||||
/* 0x7C */ MoveValue<f32, int> mExtMoveVolume;
|
||||
/* 0x8C */ f32 mInitVolume;
|
||||
/* 0x90 */ f32 mExtPan;
|
||||
/* 0x94 */ f32 mExtSurroundPan;
|
||||
/* 0x98 */ f32 mExtPitch;
|
||||
/* 0x9C */ bool mOutputLineFlagEnable;
|
||||
/* 0xA0 */ int mOutputLineFlag;
|
||||
/* 0xA4 */ f32 mMainOutVolume;
|
||||
/* 0xA8 */ f32 mRemoteOutVolume[WPAD_MAX_CONTROLLERS];
|
||||
|
||||
public:
|
||||
/* 0xB8 */ ut::LinkListNode mPriorityLink;
|
||||
/* 0xC0 */ ut::LinkListNode mSoundPlayerPlayLink;
|
||||
/* 0xC8 */ ut::LinkListNode mSoundPlayerPriorityLink;
|
||||
/* 0xD0 */ ut::LinkListNode mExtSoundPlayerPlayLink;
|
||||
|
||||
friend class SoundHandle;
|
||||
};
|
||||
|
||||
typedef ut::LinkList<BasicSound, offsetof(BasicSound, mPriorityLink)>
|
||||
BasicSoundPrioList;
|
||||
typedef ut::LinkList<BasicSound, offsetof(BasicSound, mSoundPlayerPlayLink)>
|
||||
BasicSoundPlayerPlayList;
|
||||
typedef ut::LinkList<BasicSound, offsetof(BasicSound, mSoundPlayerPriorityLink)>
|
||||
BasicSoundPlayerPrioList;
|
||||
typedef ut::LinkList<BasicSound, offsetof(BasicSound, mExtSoundPlayerPlayLink)>
|
||||
BasicSoundExtPlayList;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,185 @@
|
||||
#ifndef NW4HBM_SND_CHANNEL_H
|
||||
#define NW4HBM_SND_CHANNEL_H
|
||||
|
||||
#include <limits.h> // USHRT_MAX
|
||||
|
||||
#include <revolution/types.h>
|
||||
|
||||
#include "EnvGenerator.h"
|
||||
#include "InstancePool.h"
|
||||
#include "Lfo.h"
|
||||
#include "MoveValue.h"
|
||||
#include "WaveFile.h"
|
||||
#include "snd_global.h"
|
||||
#include "snd_types.h"
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
#include "../db/assert.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
class Channel : public LinkedInstance {
|
||||
public:
|
||||
typedef enum ChannelCallbackStatus {
|
||||
CALLBACK_STATUS_STOPPED = 0,
|
||||
CALLBACK_STATUS_DROP,
|
||||
CALLBACK_STATUS_FINISH,
|
||||
CALLBACK_STATUS_CANCEL
|
||||
} ChannelCallbackStatus;
|
||||
|
||||
typedef void (*ChannelCallback)(Channel* dropChannel, ChannelCallbackStatus status,
|
||||
u32 callbackArg);
|
||||
|
||||
typedef enum LfoTarget {
|
||||
LFO_TARGET_PITCH = 0,
|
||||
LFO_TARGET_VOLUME,
|
||||
LFO_TARGET_PAN
|
||||
} LfoTarget;
|
||||
|
||||
public:
|
||||
Channel();
|
||||
~Channel();
|
||||
|
||||
void InitParam(ChannelCallback callback, u32 callbackArg);
|
||||
void Update(bool doPeriodicProc);
|
||||
void Start(const WaveData& waveData, s32 length);
|
||||
void Release();
|
||||
void Stop();
|
||||
|
||||
void SetAttack(int attack) { mEnvelope.SetAttack(attack); }
|
||||
void SetDecay(int decay) { mEnvelope.SetDecay(decay); }
|
||||
void SetSustain(int sustain) { mEnvelope.SetSustain(sustain); }
|
||||
|
||||
void SetRelease(int release) { mEnvelope.SetRelease(release); }
|
||||
bool IsRelease() const {
|
||||
return mEnvelope.GetStatus() == EnvGenerator::STATUS_RELEASE;
|
||||
}
|
||||
|
||||
void SetLfoParam(const LfoParam& rParam) { mLfo.SetParam(rParam); }
|
||||
void SetLfoTarget(LfoTarget target) { mLfoTarget = target; }
|
||||
|
||||
void Pause(bool pause) {
|
||||
mPauseFlag = pause;
|
||||
mVoice->Pause(pause);
|
||||
}
|
||||
|
||||
bool IsPause() const { return mPauseFlag != false; }
|
||||
bool IsActive() const { return mActiveFlag; }
|
||||
bool IsAutoUpdateSweep() const { return mAutoSweep; }
|
||||
|
||||
void SetUserVolume(f32 volume) { mUserVolume = volume; }
|
||||
void SetUserPitch(f32 pitch) { mUserPitch = pitch; }
|
||||
void SetUserPitchRatio(f32 ratio) { mUserPitchRatio = ratio; }
|
||||
void SetUserPan(f32 pan) { mUserPan = pan; }
|
||||
void SetUserSurroundPan(f32 pan) { mUserSurroundPan = pan; }
|
||||
void SetUserPan2(f32 pan2) { mUserPan2 = pan2; }
|
||||
void SetUserSurroundPan2(f32 pan2) { mUserSurroundPan2 = pan2; }
|
||||
void SetUserLpfFreq(f32 freq) { mUserLpfFreq = freq; }
|
||||
|
||||
void SetOutputLine(int flag) { mOutputLineFlag = flag; }
|
||||
|
||||
void SetMainOutVolume(f32 volume) { mMainOutVolume = volume; }
|
||||
void SetMainSend(f32 send) { mMainSend = send; }
|
||||
void SetFxSend(AuxBus bus, f32 send) { mFxSend[bus] = send; }
|
||||
|
||||
void SetSilence(bool silence, int fadeTimes) {
|
||||
NW4R_ASSERT_MINMAXLT(124, fadeTimes, 0, 0xFFFF);
|
||||
mSilenceVolume.SetTarget(silence ? 0 : SILENCE_VOLUME_MAX, fadeTimes);
|
||||
}
|
||||
|
||||
void SetRemoteOutVolume(int remoteIndex, f32 volume) {
|
||||
NW4R_ASSERT_MINMAX(165, remoteIndex, 0, 4);
|
||||
mRemoteOutVolume[remoteIndex] = volume;
|
||||
}
|
||||
|
||||
void SetRemoteSend(int remoteIndex, f32 send) {
|
||||
NW4R_ASSERT_MINMAX(170, remoteIndex, 0, 4);
|
||||
mRemoteSend[remoteIndex] = send;
|
||||
}
|
||||
|
||||
void SetRemoteFxSend(int remoteIndex, f32 send) {
|
||||
NW4R_ASSERT_MINMAX(175, remoteIndex, 0, 4);
|
||||
mRemoteFxSend[remoteIndex] = send;
|
||||
}
|
||||
|
||||
void UpdateSweep(int count);
|
||||
void SetSweepParam(f32 pitch, int time, bool autoUpdate);
|
||||
f32 GetSweepValue() const;
|
||||
|
||||
void SetInitVolume(f32 volume) { mInitVolume = volume; }
|
||||
void SetInitPan(f32 pan) { mInitPan = pan; }
|
||||
void SetInitSurroundPan(f32 pan) { mInitSurroundPan = pan; }
|
||||
void SetTune(f32 tune) { mTune = tune; }
|
||||
|
||||
void SetKey(int key) { mKey = key; }
|
||||
void SetOriginalKey(int key) { mOriginalKey = key; }
|
||||
|
||||
s32 GetLength() const { return mLength; }
|
||||
void SetLength(s32 length) { mLength = length; }
|
||||
|
||||
Channel* GetNextTrackChannel() const { return mNextLink; }
|
||||
void SetNextTrackChannel(Channel* channel) { mNextLink = channel; }
|
||||
|
||||
static void UpdateAllChannel();
|
||||
static Channel* AllocChannel(int channels, int voices, int priority,
|
||||
ChannelCallback pCallback, u32 callbackArg);
|
||||
static void FreeChannel(Channel* channel);
|
||||
|
||||
static void VoiceCallback(AxVoice* voice, AxVoice::CallbackStatus status,
|
||||
void* arg);
|
||||
|
||||
private:
|
||||
static const u8 SILENCE_VOLUME_MAX = 255;
|
||||
|
||||
static const int KEY_INIT = 60;
|
||||
static const int ORIGINAL_KEY_INIT = 60;
|
||||
|
||||
static const int PRIORITY_RELEASE = 1;
|
||||
|
||||
/* 0x08 */ EnvGenerator mEnvelope;
|
||||
/* 0x20 */ Lfo mLfo;
|
||||
/* 0x38 */ u8 mLfoTarget;
|
||||
/* 0x39 */ bool mPauseFlag;
|
||||
/* 0x3A */ bool mActiveFlag;
|
||||
/* 0x3B */ bool mAllocFlag;
|
||||
/* 0x3C */ bool mAutoSweep;
|
||||
/* 0x40 */ f32 mUserVolume;
|
||||
/* 0x44 */ f32 mUserPitchRatio;
|
||||
/* 0x48 */ f32 mUserPan;
|
||||
/* 0x4C */ f32 mUserSurroundPan;
|
||||
/* 0x50 */ f32 mUserPan2;
|
||||
/* 0x54 */ f32 mUserSurroundPan2;
|
||||
/* 0x58 */ f32 mUserLpfFreq;
|
||||
/* 0x5C */ int mOutputLineFlag;
|
||||
/* 0x60 */ f32 mMainOutVolume;
|
||||
/* 0x64 */ f32 mMainSend;
|
||||
/* 0x68 */ f32 mFxSend[AUX_BUS_NUM];
|
||||
/* 0x74 */ f32 mRemoteOutVolume[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x84 */ f32 mRemoteSend[WPAD_MAX_CONTROLLERS];
|
||||
/* 0x94 */ f32 mRemoteFxSend[WPAD_MAX_CONTROLLERS];
|
||||
/* 0xA4 */ f32 mUserPitch;
|
||||
/* 0xA8 */ f32 mSweepPitch;
|
||||
/* 0xAC */ s32 mSweepCounter;
|
||||
/* 0xB0 */ s32 mSweepLength;
|
||||
/* 0xB4 */ f32 mInitVolume;
|
||||
/* 0xB8 */ f32 mInitPan;
|
||||
/* 0xBC */ f32 mInitSurroundPan;
|
||||
/* 0xC0 */ f32 mTune;
|
||||
/* 0xC4 */ MoveValue<u8, u16> mSilenceVolume;
|
||||
/* 0xCC */ int mKey;
|
||||
/* 0xD0 */ int mOriginalKey;
|
||||
/* 0xD4 */ s32 mLength;
|
||||
/* 0xD8 */ ChannelCallback mCallback;
|
||||
/* 0xDC */ u32 mCallbackData;
|
||||
/* 0xE0 */ AxVoice* mVoice;
|
||||
/* 0xE4 */ Channel* mNextLink;
|
||||
|
||||
static Channel mChannel[AX_MAX_VOICES + 1];
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef NW4HBM_SND_CHANNEL_MANAGER_H
|
||||
#define NW4HBM_SND_CHANNEL_MANAGER_H
|
||||
|
||||
#include "Channel.h"
|
||||
#include "InstanceManager.h"
|
||||
#include "snd_types.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
class ChannelManager : public InstanceManager<Channel, 0> {
|
||||
public:
|
||||
static ChannelManager& GetInstance() {
|
||||
static ChannelManager instance;
|
||||
return instance;
|
||||
}
|
||||
ChannelManager() {}
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef NW4HBM_SND_DISPOSE_CALLBACK_H
|
||||
#define NW4HBM_SND_DISPOSE_CALLBACK_H
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
// we want the vtable to get a unique name but function parameters need not to be unique
|
||||
// so we use a dummy class for that and cast to `DisposeCallback` when needed
|
||||
class DisposeCallbackBase {};
|
||||
|
||||
namespace {
|
||||
|
||||
class DisposeCallback : public DisposeCallbackBase {
|
||||
public:
|
||||
/* 0x00 */ ut::LinkListNode mDisposeLink;
|
||||
|
||||
/* 0x08 */ virtual ~DisposeCallback()
|
||||
#ifdef MAKE_DTOR_ZERO
|
||||
= 0
|
||||
#endif
|
||||
{};
|
||||
|
||||
/* 0x0C */ virtual void InvalidateData(const void* start, const void* end) = 0;
|
||||
/* 0x10 */ virtual void InvalidateWaveData(const void* start,
|
||||
const void* end) = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
typedef ut::LinkList<DisposeCallback, offsetof(DisposeCallback, mDisposeLink)>
|
||||
DisposeCallbackList;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef NW4HBM_SND_DISPOSE_CALLBACK_MANAGER_H
|
||||
#define NW4HBM_SND_DISPOSE_CALLBACK_MANAGER_H
|
||||
|
||||
#include "DisposeCallback.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
class DisposeCallbackManager {
|
||||
public:
|
||||
static DisposeCallbackManager& GetInstance();
|
||||
|
||||
void RegisterDisposeCallback(DisposeCallbackBase* callback);
|
||||
void UnregisterDisposeCallback(DisposeCallbackBase* callback);
|
||||
|
||||
static void Dispose(void* mem, u32 size, void* arg);
|
||||
static void DisposeWave(void* mem, u32 size, void* arg);
|
||||
|
||||
private:
|
||||
DisposeCallbackManager();
|
||||
|
||||
/* 0x00 */ DisposeCallbackList mCallbackList;
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef NW4HBM_SND_DVD_SOUND_ARCHIVE_H
|
||||
#define NW4HBM_SND_DVD_SOUND_ARCHIVE_H
|
||||
|
||||
#include "snd_types.h"
|
||||
|
||||
#include "SoundArchive.h"
|
||||
#include "SoundArchiveFile.h"
|
||||
|
||||
#include "../ut/FileStream.h"
|
||||
|
||||
#include <revolution/dvd.h>
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
class DvdSoundArchive : public SoundArchive {
|
||||
private:
|
||||
class DvdFileStream;
|
||||
|
||||
public:
|
||||
DvdSoundArchive();
|
||||
|
||||
/* 0x08 */ virtual ~DvdSoundArchive();
|
||||
/* 0x0C */ virtual const void* detail_GetFileAddress(u32 id) const { return NULL; }
|
||||
/* 0x10 */ virtual const void* detail_GetWaveDataFileAddress(u32 id) const {
|
||||
return NULL;
|
||||
}
|
||||
/* 0x14 */ virtual int detail_GetRequiredStreamBufferSize() const;
|
||||
/* 0x18 */ virtual ut::FileStream* OpenStream(void* buffer, int size, u32 offset,
|
||||
u32 length) const;
|
||||
/* 0x1C */ virtual ut::FileStream* OpenExtStream(void* buffer, int size,
|
||||
const char* extPath, u32 offset,
|
||||
u32 length) const;
|
||||
|
||||
bool Open(s32 entrynum);
|
||||
bool Open(const char* path);
|
||||
|
||||
void Close();
|
||||
|
||||
bool LoadHeader(void* buffer, u32 size);
|
||||
bool LoadLabelStringData(void* buffer, u32 size);
|
||||
|
||||
u32 GetHeaderSize() const { return mFileReader.GetInfoChunkSize(); }
|
||||
u32 GetLabelStringDataSize() const { return mFileReader.GetLabelStringChunkSize(); }
|
||||
|
||||
private:
|
||||
bool LoadFileHeader();
|
||||
|
||||
private:
|
||||
/* 0x108 */ detail::SoundArchiveFileReader mFileReader;
|
||||
/* 0x14C */ DVDFileInfo mFileInfo;
|
||||
/* 0x188 */ bool mOpen;
|
||||
};
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef NW4HBM_SND_ENV_GENERATOR_H
|
||||
#define NW4HBM_SND_ENV_GENERATOR_H
|
||||
|
||||
#include "../ut/LinkList.h"
|
||||
|
||||
namespace nw4hbm {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
class EnvGenerator {
|
||||
public:
|
||||
typedef enum Status {
|
||||
STATUS_ATTACK = 0,
|
||||
STATUS_DECAY,
|
||||
STATUS_SUSTAIN,
|
||||
STATUS_RELEASE
|
||||
} Status;
|
||||
|
||||
EnvGenerator();
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
f32 GetValue() const;
|
||||
void Update(int msec);
|
||||
|
||||
Status GetStatus() const { return mStatus; }
|
||||
void SetStatus(Status status) { mStatus = status; }
|
||||
|
||||
void SetAttack(int attack);
|
||||
void SetDecay(int decay);
|
||||
void SetSustain(int sustain);
|
||||
void SetRelease(int release);
|
||||
|
||||
private:
|
||||
static const int DECIBEL_SQUARE_TABLE_SIZE = 128;
|
||||
|
||||
static const vf32 VOLUME_INIT;
|
||||
static const int ATTACK_INIT = 127;
|
||||
static const int DECAY_INIT = 127;
|
||||
static const int SUSTAIN_INIT = 127;
|
||||
static const int RELEASE_INIT = 127;
|
||||
|
||||
private:
|
||||
f32 CalcRelease(int release);
|
||||
int CalcDecibelSquare(int scale);
|
||||
|
||||
/* 0x00 */ Status mStatus;
|
||||
/* 0x04 */ f32 mValue;
|
||||
/* 0x08 */ f32 mDecay;
|
||||
/* 0x0C */ f32 mRelease;
|
||||
/* 0x10 */ f32 mAttack;
|
||||
/* 0x14 */ u8 mSustain;
|
||||
/* 0x16 */ u16 padding;
|
||||
|
||||
static const s16 DecibelSquareTable[DECIBEL_SQUARE_TABLE_SIZE];
|
||||
};
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4hbm
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user