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:
TakaRikka
2025-12-16 06:55:07 -08:00
committed by GitHub
parent c8104b6d62
commit 8185d87f85
235 changed files with 32438 additions and 320 deletions
@@ -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 */
+4 -1
View File
@@ -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:
+849
View File
@@ -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);
}
+160
View File
@@ -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);
}
+343
View File
@@ -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, &currentDir);
errors += VerifyFAT(card, &currentFat);
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);
}
+126
View File
@@ -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);
}
+108
View File
@@ -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);
}
+89
View File
@@ -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);
}
+102
View File
@@ -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);
}
+137
View File
@@ -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);
}
+394
View File
@@ -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;
}
+138
View File
@@ -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);
}
+174
View File
@@ -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;
}
+100
View File
@@ -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);
}
+82
View File
@@ -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);
}
+105
View File
@@ -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;
}
+174
View File
@@ -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;
}
+70
View File
@@ -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);
}
+156
View File
@@ -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);
}
+124
View File
@@ -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);
}
+405
View File
@@ -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);
}
+123
View File
@@ -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);
}
+104
View File
@@ -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
+295
View File
@@ -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
+11
View File
@@ -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