Files
SpaghettiKart/src/racing/memory.c
T
MegaMech 016b16a484 Fix menu bug & kart textures (#32)
* Fix menu bug

* Fix undefined behaviour

* Fix kart textures

* Fix boost texture

* Rename as per review

* Fix buffer overflows

---------

Co-authored-by: MegaMech <7255464+MegaMech@users.noreply.github.com>
2024-08-02 17:04:08 -06:00

1583 lines
48 KiB
C

#include <libultraship.h>
#include <libultra/types.h>
#include <align_asset_macro.h>
#include <macros.h>
#include <string.h>
#include <common_structs.h>
#include <segments.h>
#include <decode.h>
#include <stubs.h>
#include "memory.h"
#include "main.h"
#include "code_800029B0.h"
#include "math_util.h"
#include "courses/courseTable.h"
#include "defines.h"
#include <assets/mario_raceway_displaylists.h>
#include <assets/mario_raceway_vertices.h>
#include <assets/mario_raceway_data.h>
#include <assets/luigi_raceway_displaylists.h>
#include <assets/luigi_raceway_vertices.h>
#include <assets/luigi_raceway_data.h>
#include <assets/royal_raceway_displaylists.h>
#include <assets/royal_raceway_vertices.h>
#include <assets/royal_raceway_data.h>
#include <assert.h>
#include <course_offsets.h>
#include <stdio.h>
s32 sGfxSeekPosition;
s32 sPackedSeekPosition;
static u8 sMemoryPool[0xFFFFF]; // Stock memory pool size: 0xAB630
uintptr_t sPoolEnd = sMemoryPool + sizeof(sMemoryPool);
uintptr_t sPoolFreeSpace;
struct MainPoolBlock *sPoolListHeadL;
struct MainPoolBlock *sPoolListHeadR;
struct MainPoolState *gMainPoolState = NULL;
struct UnkStruct_802B8CD4 D_802B8CD4[] = {
0
};
s32 D_802B8CE4 = 0; // pad
s32 memoryPadding[2];
#define PRINT_MEMPOOL \
printf("\nPool Start: 0x%llX, Pool End: 0x%llX, size: 0x%llX\ngNextFreeMemoryAddress: 0x%llX\n\n", sMemoryPool, \
sMemoryPool + sizeof(sMemoryPool), (sMemoryPool + sizeof(sMemoryPool)) - sMemoryPool, gNextFreeMemoryAddress)
/**
* @brief Returns the address of the next available memory location and updates the memory pointer
* to reference the next location of available memory based provided size to allocate.
* @param size of memory to allocate.
* @return Address of free memory
*/
void *get_next_available_memory_addr(uintptr_t size) {
uintptr_t freeSpace = (uintptr_t) gNextFreeMemoryAddress;
size = ALIGN16(size);
gNextFreeMemoryAddress += size;
if (gNextFreeMemoryAddress > sPoolEnd) {
printf("[memory.c] get_next_available_memory_addr(): Memory Pool Out of Bounds! Out of memory!\n");
PRINT_MEMPOOL;
assert(false);
}
//printf("\nNEXT MEM ADDR 0x%llX\n\n", freeSpace[0]);
return (void *) freeSpace;
}
/**
* @brief Stores the physical memory addr for segmented memory in `gSegmentTable` using the segment number as an index.
*
* This function takes a segment number and a pointer to a memory address, and stores the address in the `gSegmentTable` array
* at the specified segment index. The stored address is truncated to a 29-bit value to ensure that it fits within the
* memory address. This allows converting between segmented memory and physical memory.
*
* @param segment A segment number from 0x0 to 0xF to set the base address.
* @param addr A pointer containing the physical memory address of the data.
* @return The stored base address, truncated to a 29-bit value.
*/
uintptr_t set_segment_base_addr(s32 segment, void *addr) {
gSegmentTable[segment] = (uintptr_t) addr & 0x1FFFFFFF;
return gSegmentTable[segment];
}
uintptr_t set_segment_base_addr_x64(s32 segment, void *addr) {
gSegmentTable[segment] = (uintptr_t) addr;
return gSegmentTable[segment];
}
/**
* @brief Returns the physical memory location of a segment.
* @param permits segment numbers from 0x0 to 0xF.
*/
void *get_segment_base_addr(s32 segment) {
return (void *) (gSegmentTable[segment] | 0x80000000);
}
/**
* @brief converts an RSP segment + offset address to a normal memory address
*/
void *segmented_to_virtual(const void *addr) {
size_t segment = (uintptr_t) addr >> 24;
size_t offset = (uintptr_t) addr & 0x00FFFFFF;
return (void *) ((gSegmentTable[segment] + offset));
}
void *segment_offset_to_virtual(uint32_t segment, uint32_t offset) {
return (void *) (gSegmentTable[segment] + ( (offset / 8) * sizeof(Gfx) ) );
}
void *segment_vtx_to_virtual(size_t offset) {
//printf("seg_vtx_to_virt: 0x%llX to 0x%llX\n", offset, (gSegmentTable[0x04] + offset));
return (void *) (gSegmentTable[0x04] + (offset));
}
void *segmented_texture_to_virtual(size_t offset) {
//printf("seg_texture_to_virt: 0x%llX to 0x%llX\n", offset, (gSegmentTable[0x05] + offset));
return (void *) (gSegmentTable[0x05] + (offset));
}
void *segmented_uintptr_t_to_virtual(uintptr_t addr) {
uint32_t newAddr = (uint32_t) addr;
size_t segment = (uintptr_t) newAddr >> 24;
size_t offset = (uintptr_t) newAddr & 0x00FFFFFF;
uint32_t numCommands = offset / 8;
offset = numCommands * sizeof(Gfx);
//printf("seg_uintptr_t_to_virt: 0x%llX to 0x%llX\n", newAddr, (gSegmentTable[segment] + offset));
return (void *) ((gSegmentTable[segment] + offset));
}
void *segmented_gfx_to_virtual(const void *addr) {
size_t segment = (uintptr_t) addr >> 24;
size_t offset = (uintptr_t) addr & 0x00FFFFFF;
uint32_t numCommands = offset / 8;
offset = numCommands * sizeof(Gfx);
//printf("seg_gfx_to_virt: 0x%llX to 0x%llX\n", addr, (gSegmentTable[segment] + offset));
return (void *) ((gSegmentTable[segment] + offset));
}
void move_segment_table_to_dmem(void) {
s32 i;
for (i = 0; i < 16; i++) {
__gSPSegment(gDisplayListHead++, i, gSegmentTable[i]);
}
}
/**
* @brief Sets the starting location for allocating memory and calculates pool size.
*
* Default memory size, 701.984 Kilobytes.
*/
void initialize_memory_pool() {
uintptr_t poolStart = sMemoryPool;
//uintptr_t sPoolEnd = sMemoryPool + sizeof(sMemoryPool);
bzero(sMemoryPool, sizeof(sMemoryPool));
poolStart = ALIGN16(poolStart);
// Truncate to a 16-byte boundary.
sPoolEnd &= ~0xF;
gFreeMemorySize = (sPoolEnd - poolStart) - 0x10;
gNextFreeMemoryAddress = poolStart;
PRINT_MEMPOOL;
}
/**
* @brief Allocates memory and adjusts gFreeMemorySize.
*/
void *allocate_memory(size_t size) {
uintptr_t freeSpace;
size = ALIGN16(size);
gFreeMemorySize -= size;
if (gFreeMemorySize < 0) {
printf("[memory.c] allocate_memory(): gFreeMemorySize below zero!\n");
printf("gFreeMemorySize: 0x%X", gFreeMemorySize);
PRINT_MEMPOOL;
assert(false);
}
freeSpace = (uintptr_t ) gNextFreeMemoryAddress;
gNextFreeMemoryAddress += size;
if (gNextFreeMemoryAddress > sPoolEnd) {
printf("[memory.c] allocate_memory(): Memory Pool Out of Bounds! Out of memory!\n");
PRINT_MEMPOOL;
assert(false);
}
return (void *) freeSpace;
}
UNUSED void func_802A7D54(s32 arg0, s32 arg1) {
gD_80150158[arg0].unk0 = arg0;
gD_80150158[arg0].unk8 = arg1;
}
/**
* @brief Allocate and DMA.
*/
void *load_data(uintptr_t startAddr, uintptr_t endAddr) {
void *allocated;
uintptr_t size = endAddr - startAddr;
allocated = allocate_memory(size);
if (allocated != 0) {
dma_copy((u8 *)allocated, (u8 *)startAddr, size);
}
return (void *) allocated;
}
UNUSED void main_pool_init(uintptr_t start, uintptr_t end) {
start = ALIGN16(start);
end = ALIGN16(end - 15);
sPoolFreeSpace = (end - start) - 16;
sPoolListHeadL = (struct MainPoolBlock *) start;
sPoolListHeadR = (struct MainPoolBlock *) end;
sPoolListHeadL->prev = NULL;
sPoolListHeadL->next = NULL;
sPoolListHeadR->prev = NULL;
sPoolListHeadR->next = NULL;
}
/**
* Allocate a block of memory from the pool of given size, and from the
* specified side of the pool (MEMORY_POOL_LEFT or MEMORY_POOL_RIGHT).
* If there is not enough space, return NULL.
*/
UNUSED void *main_pool_alloc(uintptr_t size, uintptr_t side) {
struct MainPoolBlock *newListHead;
void *addr = NULL;
size = ALIGN16(size) + 8;
if (sPoolFreeSpace >= size) {
sPoolFreeSpace -= size;
if (side == MEMORY_POOL_LEFT) {
newListHead = (struct MainPoolBlock *) ((u8 *) sPoolListHeadL + size);
sPoolListHeadL->next = newListHead;
newListHead->prev = sPoolListHeadL;
addr = (u8 *) sPoolListHeadL + 8;
sPoolListHeadL = newListHead;
} else {
newListHead = (struct MainPoolBlock *) ((u8 *) sPoolListHeadR - size);
sPoolListHeadR->prev = newListHead;
newListHead->next = sPoolListHeadR;
sPoolListHeadR = newListHead;
addr = (u8 *) sPoolListHeadR + 8;
}
}
return addr;
}
/**
* Free a block of memory that was allocated from the pool. The block must be
* the most recently allocated block from its end of the pool, otherwise all
* newer blocks are freed as well.
* Return the amount of free space left in the pool.
*/
UNUSED uintptr_t main_pool_free(void *addr) {
struct MainPoolBlock *block = (struct MainPoolBlock *) ((u8 *) addr - 8);
struct MainPoolBlock *oldListHead = (struct MainPoolBlock *) ((u8 *) addr - 8);
if (oldListHead < sPoolListHeadL) {
while (oldListHead->next != NULL) {
oldListHead = oldListHead->next;
}
sPoolListHeadL = block;
sPoolListHeadL->next = NULL;
sPoolFreeSpace += (uintptr_t) oldListHead - (uintptr_t) sPoolListHeadL;
} else {
while (oldListHead->prev != NULL) {
oldListHead = oldListHead->prev;
}
sPoolListHeadR = block->next;
sPoolListHeadR->prev = NULL;
sPoolFreeSpace += (uintptr_t) sPoolListHeadR - (uintptr_t) oldListHead;
}
return sPoolFreeSpace;
}
// main_pool_realloc
UNUSED void *main_pool_realloc(void *addr, uintptr_t size) {
void *newAddr = NULL;
struct MainPoolBlock *block = (struct MainPoolBlock *) ((u8 *) addr - 8);
if (block->next == sPoolListHeadL) {
main_pool_free(addr);
newAddr = main_pool_alloc(size, MEMORY_POOL_LEFT);
}
return newAddr;
}
UNUSED uintptr_t main_pool_available(void) {
return sPoolFreeSpace - 8;
}
UNUSED uintptr_t main_pool_push_state(void) {
struct MainPoolState *prevState = gMainPoolState;
uintptr_t freeSpace = sPoolFreeSpace;
struct MainPoolBlock *lhead = sPoolListHeadL;
struct MainPoolBlock *rhead = sPoolListHeadR;
gMainPoolState = main_pool_alloc(sizeof(*gMainPoolState), MEMORY_POOL_LEFT);
gMainPoolState->freeSpace = freeSpace;
gMainPoolState->listHeadL = lhead;
gMainPoolState->listHeadR = rhead;
gMainPoolState->prev = prevState;
return sPoolFreeSpace;
}
/**
* Restore pool state from a previous call to main_pool_push_state. Return the
* amount of free space left in the pool.
*/
UNUSED uintptr_t main_pool_pop_state(void) {
sPoolFreeSpace = gMainPoolState->freeSpace;
sPoolListHeadL = gMainPoolState->listHeadL;
sPoolListHeadR = gMainPoolState->listHeadR;
gMainPoolState = gMainPoolState->prev;
return sPoolFreeSpace;
}
// similar to sm64 dma_read
UNUSED void *func_802A80B0(u8 *dest, u8 *srcStart, u8 *srcEnd) {
void *addr;
uintptr_t size = srcStart - dest;
addr = main_pool_alloc(size, (uintptr_t) srcEnd);
if (addr != 0) {
osInvalDCache(addr, size);
osPiStartDma(&gDmaIoMesg, OS_MESG_PRI_NORMAL, OS_READ, (uintptr_t) dest, addr, size,
&gDmaMesgQueue);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, OS_MESG_BLOCK);
}
return addr;
}
// replaces call to dynamic_dma_read with dma_read.
UNUSED void *load_segment(s32 segment, u8 *srcStart, u8 *srcEnd, u8 *side) {
void *addr = func_802A80B0(srcStart, srcEnd, side);
if (addr != NULL) {
set_segment_base_addr(segment, addr);
}
return addr;
}
// Similar to sm64 load_to_fixed_pool_addr?
UNUSED void *func_802A8190(s32 arg0, u8 *arg1) {
//uintptr_t srcSize = ALIGN16(srcEnd - srcStart);
//uintptr_t destSize = ALIGN16((u8 *) sPoolListHeadR - destAddr);
void *addr;
uintptr_t temp_v0 = D_802B8CD4[arg0].unk4;
uintptr_t temp_v1 = D_802B8CD4[arg0].unk8;
uintptr_t temp_v2 = D_802B8CD4[arg0].unk2;
addr = func_802A80B0((u8 *) temp_v0, (u8 *) temp_v1, arg1);
//dest = main_pool_alloc(destSize, MEMORY_POOL_RIGHT);
if (addr != 0) {
set_segment_base_addr(temp_v2, addr);
}
return (void *) addr;
}
UNUSED void func_802A81EC(void) {
s32 temp_s0;
s16 *phi_s1;
s32 phi_s0;
phi_s1 = (s16 *) &D_802B8CD4;
phi_s0 = 0;
do {
if ((*phi_s1 & 1) != 0) {
func_802A8190(phi_s0, 0);
}
temp_s0 = phi_s0 + 1;
phi_s1 += 8;
phi_s0 = temp_s0;
} while (phi_s0 != 3);
}
UNUSED struct AllocOnlyPool *alloc_only_pool_init(uintptr_t size, uintptr_t side) {
void *addr;
struct AllocOnlyPool *subPool = NULL;
size = ALIGN4(size);
addr = main_pool_alloc(size + sizeof(struct AllocOnlyPool), side);
if (addr != NULL) {
subPool = (struct AllocOnlyPool *) addr;
subPool->totalSpace = size;
subPool->usedSpace = (s32) addr + sizeof(struct AllocOnlyPool);
subPool->startPtr = 0;
subPool->freePtr = (u8 *) addr + sizeof(struct AllocOnlyPool);
}
return subPool;
}
UNUSED uintptr_t func_802A82AC(s32 arg0) {
uintptr_t temp_v0;
uintptr_t phi_v1;
temp_v0 = D_801502A0 - arg0;
phi_v1 = 0;
if (temp_v0 >= (uintptr_t) gDisplayListHead) {
D_801502A0 = temp_v0;
phi_v1 = temp_v0;
}
return phi_v1;
}
/**
* @brief Returns pointer to mio0 compressed Vtx.
*/
u8 *dma_compressed_vtx(u8 *start, u8 *end) {
u8 *freeSpace;
uintptr_t size;
size = ALIGN16(end - start);
freeSpace = (u8 *) gNextFreeMemoryAddress;
dma_copy(freeSpace, start, size);
gNextFreeMemoryAddress += size;
return freeSpace;
}
// unused mio0 decode func.
UNUSED uintptr_t func_802A8348(s32 arg0, s32 arg1, s32 arg2) {
uintptr_t offset;
UNUSED void *pad;
uintptr_t oldAddr;
void *newAddr;
offset = ALIGN16(arg1 * arg2);
oldAddr = gNextFreeMemoryAddress;
newAddr = (void *) (oldAddr + offset);
pad = &newAddr;
// osInvalDCache(newAddr, offset);
//osPiStartDma(&gDmaIoMesg, 0, 0, (uintptr_t) &_other_texturesSegmentRomStart[SEGMENT_OFFSET(arg0)], newAddr, offset, &gDmaMesgQueue);
// osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, 1);
func_80040030((u8 *) newAddr, (u8 *) oldAddr);
gNextFreeMemoryAddress += offset;
return oldAddr;
}
UNUSED u8 *func_802A841C(u8* arg0, s32 arg1, s32 arg2) {
u8 *temp_v0;
void *temp_a0;
temp_v0 = (u8 *) gNextFreeMemoryAddress;
temp_a0 = temp_v0 + arg2;
arg1 = ALIGN16(arg1);
arg2 = ALIGN16(arg2);
osInvalDCache(temp_a0, arg1);
//osPiStartDma(&gDmaIoMesg, 0, 0, (uintptr_t) &_other_texturesSegmentRomStart[SEGMENT_OFFSET(arg0)],temp_a0, arg1, &gDmaMesgQueue);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, 1);
func_80040030((u8 *) temp_a0, temp_v0);
gNextFreeMemoryAddress += arg2;
return temp_v0;
}
u8 *dma_textures(const char *texture, size_t arg1, size_t arg2) {
u8 *temp_v0;
void *temp_a0;
u8* tex = (u8 *) LOAD_ASSET(texture);
temp_v0 = (u8 *) allocate_memory(arg2); // gNextFreeMemoryAddress;
temp_a0 = temp_v0 + arg2;
arg1 = ALIGN16(arg1);
arg2 = ALIGN16(arg2);
//osInvalDCache((void *) temp_a0, arg1);
// osPiStartDma(&gDmaIoMesg, 0, 0, (uintptr_t) &_other_texturesSegmentRomStart[SEGMENT_OFFSET(texture)], (void *)temp_a0, arg1, &gDmaMesgQueue);
// osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, (int) 1);
// mio0decode((u8 *) temp_a0, temp_v0);
memcpy(temp_v0, tex, arg2);
//gNextFreeMemoryAddress += arg2;
return temp_v0;
}
uintptr_t MIO0_0F(u8 *arg0, uintptr_t arg1, uintptr_t arg2) {
uintptr_t oldHeapEndPtr;
void *temp_v0;
arg1 = ALIGN16(arg1);
arg2 = ALIGN16(arg2);
oldHeapEndPtr = gHeapEndPtr;
temp_v0 = (void *) gNextFreeMemoryAddress;
osInvalDCache(temp_v0, arg1);
//osPiStartDma(&gDmaIoMesg, 0, 0, (uintptr_t) &_other_texturesSegmentRomStart[SEGMENT_OFFSET(arg0)], temp_v0, arg1, &gDmaMesgQueue);
osRecvMesg(&gDmaMesgQueue, &gMainReceivedMesg, 1);
mio0decode((u8 *) temp_v0, (u8 *) oldHeapEndPtr);
gHeapEndPtr += arg2;
return oldHeapEndPtr;
}
void func_802A86A8(CourseVtx *courseVtx, Vtx *vtx, size_t arg1) {
s32 tmp = ALIGN16(arg1 * 0x10);
size_t i;
s8 temp_a0;
s8 temp_a3;
s8 flags;
//gHeapEndPtr -= tmp;
//vtx = (Vtx *) gHeapEndPtr;
// s32 to uintptr_t comparison required for matching.
for (i = 0; i < arg1; i++) {
if (gIsMirrorMode) {
vtx->v.ob[0] = -courseVtx->ob[0];
} else {
vtx->v.ob[0] = courseVtx->ob[0];
}
vtx->v.ob[1] = (courseVtx->ob[1] * vtxStretchY);
temp_a0 = courseVtx->ca[0];
temp_a3 = courseVtx->ca[1];
flags = temp_a0 & 3;
flags |= (temp_a3 << 2) & 0xC;
vtx->v.ob[2] = courseVtx->ob[2];
vtx->v.tc[0] = courseVtx->tc[0];
vtx->v.tc[1] = courseVtx->tc[1];
vtx->v.cn[0] = (temp_a0 & 0xFC);
vtx->v.cn[1] = (temp_a3 & 0xFC);
vtx->v.cn[2] = courseVtx->ca[2];
vtx->v.flag = flags;
vtx->v.cn[3] = 0xFF;
vtx++;
courseVtx++;
}
}
void decompress_vtx(CourseVtx *arg0, uintptr_t vertexCount) {
s32 size = ALIGN16(vertexCount * 0x18);
void *freeSpace;
u8 *vtxCompressed = arg0;
UNUSED s32 pad;
freeSpace = (void *) gNextFreeMemoryAddress;
gNextFreeMemoryAddress += size;
mio0decode(vtxCompressed, (u8 *) freeSpace);
//func_802A86A8((CourseVtx *) freeSpace, vertexCount);
set_segment_base_addr(4, (void *) gHeapEndPtr);
}
UNUSED void func_802A8844(void) {
}
void unpack_lights(Gfx *arg0, UNUSED u8 *arg1, s8 arg2) {
UNUSED s32 pad;
s32 a = (arg2 * 0x18) + 0x9000008;
s32 b = (arg2 * 0x18) + 0x9000000;
Gfx macro[] = {gsSPNumLights(NUMLIGHTS_1)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
arg0[sGfxSeekPosition].words.w0 = 0x3860010;
arg0[sGfxSeekPosition].words.w1 = a;
sGfxSeekPosition++;
arg0[sGfxSeekPosition].words.w0 = 0x3880010;
arg0[sGfxSeekPosition].words.w1 = b;
sGfxSeekPosition++;
}
void unpack_displaylist(Gfx *arg0, u8 *args, UNUSED s8 opcode) {
uintptr_t temp_v0 = args[sPackedSeekPosition++];
uintptr_t temp_t7 = ((args[sPackedSeekPosition++]) << 8 | temp_v0) * 8;
arg0[sGfxSeekPosition].words.w0 = 0x06000000;
// Segment seven addr
arg0[sGfxSeekPosition].words.w1 = segment_offset_to_virtual(0x07, temp_t7); // (0x07000000 + temp_t7); // (gSegmentTable[segment] + ( (offset / 8) * sizeof(Gfx) ) );
sGfxSeekPosition++;
}
// end displaylist
void unpack_end_displaylist(Gfx *arg0, UNUSED u8 *arg1, UNUSED s8 arg2) {
arg0[sGfxSeekPosition].words.w0 = (uintptr_t)(uint8_t)G_ENDDL << 24;
arg0[sGfxSeekPosition].words.w1 = 0;
sGfxSeekPosition++;
}
void unpack_set_geometry_mode(Gfx *arg0, UNUSED u8 *arg1, UNUSED s8 arg2) {
Gfx macro[] = {gsSPSetGeometryMode(G_CULL_BACK)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_clear_geometry_mode(Gfx *arg0, UNUSED u8 *arg1, UNUSED s8 arg2) {
Gfx macro[] = {gsSPClearGeometryMode(G_CULL_BACK)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_cull_displaylist(Gfx *arg0, UNUSED u8 *arg1, UNUSED s8 arg2) {
Gfx macro[] = {gsSPCullDisplayList(0, 7)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_combine_mode1(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetCombineMode(G_CC_MODULATERGBA, G_CC_MODULATERGBA)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_combine_mode2(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetCombineMode(G_CC_MODULATERGBDECALA, G_CC_MODULATERGBDECALA)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_combine_mode_shade(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetCombineMode(G_CC_SHADE, G_CC_SHADE)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_combine_mode4(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetCombineMode(G_CC_MODULATERGBDECALA, G_CC_MODULATERGBDECALA)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_combine_mode5(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetCombineMode(G_CC_DECALRGBA, G_CC_DECALRGBA)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_render_mode_opaque(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetRenderMode(G_RM_AA_ZB_OPA_SURF, G_RM_AA_ZB_OPA_SURF2)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_render_mode_tex_edge(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetRenderMode(G_RM_AA_ZB_TEX_EDGE, G_RM_AA_ZB_TEX_EDGE2)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_render_mode_translucent(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetRenderMode(G_RM_AA_ZB_XLU_SURF, G_RM_AA_ZB_XLU_SURF2)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_render_mode_opaque_decal(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetRenderMode(G_RM_AA_ZB_OPA_DECAL, G_RM_AA_ZB_OPA_DECAL)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_render_mode_translucent_decal(Gfx *arg0, UNUSED u8 *arg1, UNUSED uintptr_t arg2) {
Gfx macro[] = {gsDPSetRenderMode(G_RM_AA_ZB_XLU_DECAL, G_RM_AA_ZB_XLU_DECAL)};
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_tile_sync(Gfx *gfx, u8 *args, s8 opcode) {
Gfx tileSync[] = { gsDPTileSync() };
uintptr_t temp_a0;
uintptr_t lo;
uintptr_t hi;
s32 width;
s32 height;
s32 fmt;
s32 siz;
s32 line;
s32 tmem;
s32 cms;
s32 masks;
s32 cmt;
s32 maskt;
s32 lrs;
s32 lrt;
UNUSED s32 pad[4];
tmem = 0;
switch (opcode) {
case 26:
width = 32;
height = 32;
fmt = 0;
break;
case 44:
width = 32;
height = 32;
fmt = 0;
tmem = 256;
break;
case 27:
width = 64;
height = 32;
fmt = 0;
break;
case 28:
width = 32;
height = 64;
fmt = 0;
break;
case 29:
width = 32;
height = 32;
fmt = 3;
break;
case 30:
width = 64;
height = 32;
fmt = 3;
break;
case 31:
width = 32;
height = 64;
fmt = 3;
break;
}
// Set arguments
siz = G_IM_SIZ_16b_BYTES;
line = ((((width * 2) + 7) >> 3));
temp_a0 = args[sPackedSeekPosition++];
cms = temp_a0 & 0xF;
masks = (temp_a0 & 0xF0) >> 4;
temp_a0 = args[sPackedSeekPosition++];
cmt = temp_a0 & 0xF;
maskt = (temp_a0 & 0xF0) >> 4;
// Generate gfx
gfx[sGfxSeekPosition].words.w0 = tileSync->words.w0;
gfx[sGfxSeekPosition].words.w1 = tileSync->words.w1;
sGfxSeekPosition++;
lo = ((uintptr_t)(uint8_t)G_SETTILE << 24) | (fmt << 21) | (siz << 19) | (line << 9) | tmem;
hi = ((cmt) << 18) | ((maskt) << 14) | ((cms) << 8) | ((masks) << 4);
gfx[sGfxSeekPosition].words.w0 = lo;
gfx[sGfxSeekPosition].words.w1 = hi;
sGfxSeekPosition++;
lrs = (width - 1) << 2;
lrt = (height - 1) << 2;
lo = ((uintptr_t)(uint8_t)G_SETTILESIZE << 24);
hi = (lrs << 12) | lrt;
gfx[sGfxSeekPosition].words.w0 = lo;
gfx[sGfxSeekPosition].words.w1 = hi;
sGfxSeekPosition++;
}
void unpack_tile_load_sync(Gfx *gfx, u8 *args, s8 opcode) {
UNUSED uintptr_t var;
Gfx tileSync[] = { gsDPTileSync() };
Gfx loadSync[] = { gsDPLoadSync() };
uintptr_t arg;
uintptr_t lo;
uintptr_t hi;
uintptr_t addr;
uintptr_t width;
uintptr_t height;
uintptr_t fmt;
uintptr_t siz;
uintptr_t tmem;
uintptr_t tile;
size_t offset;
switch (opcode) {
case 32:
width = 32;
height = 32;
fmt = 0;
break;
case 33:
width = 64;
height = 32;
fmt = 0;
break;
case 34:
width = 32;
height = 64;
fmt = 0;
break;
case 35:
width = 32;
height = 32;
fmt = 3;
break;
case 36:
width = 64;
height = 32;
fmt = 3;
break;
case 37:
width = 32;
height = 64;
fmt = 3;
break;
}
// Set arguments
// Waa?
var = args[sPackedSeekPosition];
// Generates a texture address.
offset = args[sPackedSeekPosition++] << 11;
addr = SEGMENT_ADDR(0x05, offset);
sPackedSeekPosition++;
arg = args[sPackedSeekPosition++];
siz = G_IM_SIZ_16b;
tmem = (arg & 0xF);
tile = (arg & 0xF0) >> 4;
// Generate gfx
lo = ((uintptr_t)(uint8_t)G_SETTIMG << 24) | (fmt << 21) | (siz << 19);
gfx[sGfxSeekPosition].words.w0 = lo;
gfx[sGfxSeekPosition].words.w1 = segmented_texture_to_virtual(offset);
sGfxSeekPosition++;
gfx[sGfxSeekPosition].words.w0 = tileSync->words.w0;
gfx[sGfxSeekPosition].words.w1 = tileSync->words.w1;
sGfxSeekPosition++;
lo = ((uintptr_t)(uint8_t)G_SETTILE << 24) | (fmt << 21) | (siz << 19) | tmem;
hi = tile << 24;
gfx[sGfxSeekPosition].words.w0 = lo;
gfx[sGfxSeekPosition].words.w1 = hi;
sGfxSeekPosition++;
gfx[sGfxSeekPosition].words.w0 = loadSync->words.w0;
gfx[sGfxSeekPosition].words.w1 = loadSync->words.w1;
sGfxSeekPosition++;
lo = (uintptr_t)(uint8_t)G_LOADBLOCK << 24;
hi = (tile << 24) | (MIN((width * height) - 1, 0x7FF) << 12) | CALC_DXT(width, G_IM_SIZ_16b_BYTES);
gfx[sGfxSeekPosition].words.w0 = lo;
gfx[sGfxSeekPosition].words.w1 = hi;
sGfxSeekPosition++;
}
void unpack_texture_on(Gfx *arg0, UNUSED u8 *args, UNUSED s8 arg2) {
Gfx macro[] = { gsSPTexture(0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON) };
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_texture_off(Gfx *arg0, UNUSED u8 *args, UNUSED s8 arg2) {
Gfx macro[] = { gsSPTexture(0x1, 0x1, 0, G_TX_RENDERTILE, G_OFF) };
arg0[sGfxSeekPosition].words.w0 = macro->words.w0;
arg0[sGfxSeekPosition].words.w1 = macro->words.w1;
sGfxSeekPosition++;
}
void unpack_vtx1(Gfx *gfx, u8 *args, UNUSED s8 arg2) {
uintptr_t temp_t7;
uintptr_t temp_t7_2;
uintptr_t temp = args[sPackedSeekPosition++];
uintptr_t temp2 = ((args[sPackedSeekPosition++] << 8) | temp) * 0x10;
temp = args[sPackedSeekPosition++];
temp_t7 = temp & 0x3F;
temp = args[sPackedSeekPosition++];
temp_t7_2 = temp & 0x3F;
gfx[sGfxSeekPosition].words.w0 = ((uintptr_t)(uint8_t)G_VTX << 24) | (temp_t7_2 * 2 << 16) | (((temp_t7 << 10) + ((0x10 * temp_t7) - 1)));
gfx[sGfxSeekPosition].words.w1 = (uintptr_t) segment_vtx_to_virtual(temp2);
sGfxSeekPosition++;
}
void unpack_vtx2(Gfx *gfx, u8 *args, s8 arg2) {
uintptr_t temp_t9;
uintptr_t temp_v1;
uintptr_t temp_v2;
temp_v1 = args[sPackedSeekPosition++];
temp_v2 = ((args[sPackedSeekPosition++] << 8) | temp_v1) * 0x10;
temp_t9 = arg2 - 50;
gfx[sGfxSeekPosition].words.w0 = ((uintptr_t)(uint8_t)G_VTX << 24) | ((temp_t9 << 10) + (((temp_t9) * 0x10) - 1));
gfx[sGfxSeekPosition].words.w1 = (uintptr_t) segment_vtx_to_virtual(temp_v2);
sGfxSeekPosition++;
}
void unpack_triangle(Gfx *gfx, u8 *args, UNUSED s8 arg2) {
uintptr_t temp_v0;
uintptr_t phi_a0;
uintptr_t phi_a2;
uintptr_t phi_a3;
temp_v0 = args[sPackedSeekPosition++];
if (gIsMirrorMode) {
phi_a3 = temp_v0 & 0x1F;
phi_a2 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_a2 |= (temp_v0 & 3) * 8;
phi_a0 = (temp_v0 >> 2) & 0x1F;
} else {
phi_a0 = temp_v0 & 0x1F;
phi_a2 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_a2 |= (temp_v0 & 3) * 8;
phi_a3 = (temp_v0 >> 2) & 0x1F;
}
gfx[sGfxSeekPosition].words.w0 = ((uintptr_t)(uint8_t)G_TRI1 << 24);
gfx[sGfxSeekPosition].words.w1 = ((phi_a0 * 2) << 16) | ((phi_a2 * 2) << 8) | (phi_a3 * 2);
sGfxSeekPosition++;
}
void unpack_quadrangle(Gfx *gfx, u8 *args, UNUSED s8 arg2) {
uintptr_t temp_v0;
uintptr_t phi_t0;
uintptr_t phi_a3;
uintptr_t phi_a0;
uintptr_t phi_t2;
uintptr_t phi_t1;
uintptr_t phi_a2;
temp_v0 = args[sPackedSeekPosition++];
if (gIsMirrorMode) {
phi_t0 = temp_v0 & 0x1F;
phi_a3 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_a3 |= (temp_v0 & 3) * 8;
phi_a0 = (temp_v0 >> 2) & 0x1F;
} else {
phi_a0 = temp_v0 & 0x1F;
phi_a3 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_a3 |= (temp_v0 & 3) * 8;
phi_t0 = (temp_v0 >> 2) & 0x1F;
}
temp_v0 = args[sPackedSeekPosition++];
if (gIsMirrorMode) {
phi_a2 = temp_v0 & 0x1F;
phi_t1 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_t1 |= (temp_v0 & 3) * 8;
phi_t2 = (temp_v0 >> 2) & 0x1F;
} else {
phi_t2 = temp_v0 & 0x1F;
phi_t1 = (temp_v0 >> 5) & 7;
temp_v0 = args[sPackedSeekPosition++];
phi_t1 |= (temp_v0 & 3) * 8;
phi_a2 = (temp_v0 >> 2) & 0x1F;
}
gfx[sGfxSeekPosition].words.w0 =
((uintptr_t)(uint8_t)G_TRI2 << 24) | ((phi_a0 * 2) << 16) | ((phi_a3 * 2) << 8) | (phi_t0 * 2);
gfx[sGfxSeekPosition].words.w1 = ((phi_t2 * 2) << 16) | ((phi_t1 * 2) << 8) | (phi_a2 * 2);
sGfxSeekPosition++;
}
void unpack_spline_3D(Gfx *gfx, u8 *arg1, UNUSED s8 arg2) {
uintptr_t temp_v0;
uintptr_t phi_a0;
uintptr_t phi_t0;
uintptr_t phi_a3;
uintptr_t phi_a2;
temp_v0 = arg1[sPackedSeekPosition++];
if (gIsMirrorMode != 0) {
phi_a0 = temp_v0 & 0x1F;
phi_a2 = ((temp_v0 >> 5) & 7);
temp_v0 = arg1[sPackedSeekPosition++];
phi_a2 |= ((temp_v0 & 3) * 8);
phi_a3 = (temp_v0 >> 2) & 0x1F;
phi_t0 = ((temp_v0 >> 7) & 1);
temp_v0 = arg1[sPackedSeekPosition++];
phi_t0 |= (temp_v0 & 0xF) * 2;
} else {
phi_t0 = temp_v0 & 0x1F;
phi_a3 = ((temp_v0 >> 5) & 7);
temp_v0 = arg1[sPackedSeekPosition++];
phi_a3 |= ((temp_v0 & 3) * 8);
phi_a2 = (temp_v0 >> 2) & 0x1F;
phi_a0 = ((temp_v0 >> 7) & 1);
temp_v0 = arg1[sPackedSeekPosition++];
phi_a0 |= (temp_v0 & 0xF) * 2;
}
gfx[sGfxSeekPosition].words.w0 = ((uintptr_t)(uint8_t)G_LINE3D << 24);
gfx[sGfxSeekPosition].words.w1 =
((phi_a0 * 2) << 24) | ((phi_t0 * 2) << 16) | ((phi_a3 * 2) << 8) | (phi_a2 * 2);
sGfxSeekPosition++;
}
UNUSED void func_802A9AEC(void) {
}
/**
* Unpacks course packed displaylists by iterating through each byte of the packed file.
* Each packed displaylist entry has an opcode and any number of arguments.
* The opcodes range from 0 to 87 which are used to run the relevant unpack function.
* The file pointer increments when arguments are used. This way,
* displaylist_unpack will always read an opcode and not an argument by accident.
*
* @warning opcodes that do not contain a definition in the switch are ignored. If an undefined opcode
* contained arguments the unpacker might try to unpack those arguments.
* This issue is prevented so long as the packed file adheres to correct opcodes and unpack code
* increments the file pointer the correct number of times.
*/
void displaylist_unpack(Gfx *gfx, u8 *data, uintptr_t arg2) {
u8 *packed_dl = data;
//uintptr_t addr;
u8 opcode;
// finalDisplaylistOffset = ALIGN16(finalDisplaylistOffset) + 8;
// gHeapEndPtr -= finalDisplaylistOffset;
// addr = gHeapEndPtr;
// gfx = (Gfx *) gHeapEndPtr;
sGfxSeekPosition = 0;
sPackedSeekPosition = 0;
while(true) {
// Seek to the next byte
opcode = packed_dl[sPackedSeekPosition++];
// Break when the eof has been reached denoted by opcode 0xFF
if (opcode == 0xFF) break;
switch (opcode) {
case 0x0:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x1:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x2:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x3:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x4:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x5:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x6:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x7:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x8:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x9:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xA:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xB:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xC:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xD:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xE:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0xF:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x10:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x11:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x12:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x13:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x14:
unpack_lights(gfx, packed_dl, opcode);
break;
case 0x15:
unpack_combine_mode1(gfx, packed_dl, arg2);
break;
case 0x16:
unpack_combine_mode2(gfx, packed_dl, arg2);
break;
case 0x17:
unpack_combine_mode_shade(gfx, packed_dl, arg2);
break;
case 0x2E:
unpack_combine_mode4(gfx, packed_dl, arg2);
break;
case 0x53:
unpack_combine_mode5(gfx, packed_dl, arg2);
break;
case 0x18:
unpack_render_mode_opaque(gfx, packed_dl, arg2);
break;
case 0x19:
unpack_render_mode_tex_edge(gfx, packed_dl, arg2);
break;
case 0x2F:
unpack_render_mode_translucent(gfx, packed_dl, arg2);
break;
case 0x54:
unpack_render_mode_opaque_decal(gfx, packed_dl, arg2);
break;
case 0x55:
unpack_render_mode_translucent_decal(gfx, packed_dl, arg2);
break;
case 0x1A:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x2C:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x1B:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x1C:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x1D:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x1E:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x1F:
unpack_tile_sync(gfx, packed_dl, opcode);
break;
case 0x20:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x21:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x22:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x23:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x24:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x25:
unpack_tile_load_sync(gfx, packed_dl, opcode);
break;
case 0x26:
unpack_texture_on(gfx, packed_dl, opcode);
break;
case 0x27:
unpack_texture_off(gfx, packed_dl, opcode);
break;
case 0x28:
unpack_vtx1(gfx, packed_dl, opcode);
break;
case 0x33:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x34:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x35:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x36:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x37:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x38:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x39:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3A:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3B:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3C:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3D:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3E:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x3F:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x40:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x41:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x42:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x43:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x44:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x45:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x46:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x47:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x48:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x49:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4A:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4B:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4C:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4D:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4E:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x4F:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x50:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x51:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x52:
unpack_vtx2(gfx, packed_dl, opcode);
break;
case 0x29:
unpack_triangle(gfx, packed_dl, opcode);
break;
case 0x58:
unpack_quadrangle(gfx, packed_dl, opcode);
break;
case 0x30:
unpack_spline_3D(gfx, packed_dl, opcode);
break;
case 0x2D:
unpack_cull_displaylist(gfx, packed_dl, opcode);
break;
case 0x2A:
unpack_end_displaylist(gfx, packed_dl, opcode);
break;
case 0x56:
unpack_set_geometry_mode(gfx, packed_dl, opcode);
break;
case 0x57:
unpack_clear_geometry_mode(gfx, packed_dl, opcode);
break;
case 0x2B:
unpack_displaylist(gfx, packed_dl, opcode);
break;
default:
// Skip unknown values
break;
}
}
//set_segment_base_addr(0x7, (void *) addr);
}
struct UnkStr_802AA7C8 {
u8 *unk0;
uintptr_t unk4;
uintptr_t unk8;
uintptr_t unkC;
};
void decompress_textures(uintptr_t arg0) {
struct UnkStr_802AA7C8 *phi_s0 =
(struct UnkStr_802AA7C8 *) arg0;
struct UnkStr_802AA7C8 *temp_s0;
uintptr_t temp_t2;
u8 *temp_a0;
uintptr_t phi_v0;
uintptr_t sp20;
phi_v0 = 0;
temp_s0 = phi_s0;
while (true) {
temp_a0 = phi_s0->unk0;
if ((temp_a0) == 0) {
break;
}
phi_v0 += phi_s0->unk8;
phi_s0++;
}
phi_s0 = temp_s0;
gHeapEndPtr -= phi_v0;
sp20 = gHeapEndPtr;
while (true) {
temp_a0 = phi_s0->unk0;
if ((temp_a0) == 0) {
break;
}
MIO0_0F(temp_a0, phi_s0->unk4, phi_s0->unk8);
phi_s0++;
}
gHeapEndPtr = sp20;
temp_t2 = gHeapEndPtr;
set_segment_base_addr(0x5, (void *) temp_t2);
}
void *decompress_segments(u8 *start, u8 *end) {
int bp = 0;
return;
UNUSED uintptr_t pad;
uintptr_t sp28;
uintptr_t size = ALIGN16(end - start);
u8 *heapEnd;
uintptr_t freeSpace;
heapEnd = (u8 *) gHeapEndPtr - size;
// sp20 = temp_a0;
dma_copy(heapEnd, start, size);
sp28 = (uintptr_t) (heapEnd + 4);
sp28 = ALIGN16(sp28);
freeSpace = (uintptr_t ) gNextFreeMemoryAddress;
mio0decode(heapEnd, (u8 *)freeSpace);
gNextFreeMemoryAddress += sp28;
return (void *)freeSpace;
}
extern const course_texture mario_raceway_textures[30];
/* To help verify if ptrs are pointing within segments see gfx_pc.cpp gfx_step() */
uintptr_t vtxSegEnd;
uintptr_t dlSegEnd;
uintptr_t texSegEnd; size_t texSegSize;
Gfx *testaaa;
/**
* @brief Loads & DMAs course data. Vtx, textures, displaylists, etc.
* @param courseId
*/
typedef struct {
char* data;
char* vtx;
size_t vtxSize;
course_texture* textures;
char* displaylists;
size_t dlSize;
} NewCourseTable;
NewCourseTable gNewCourseTable[] = {
{
.data = d_course_mario_raceway_dl_0,
.vtx = d_course_mario_raceway_vertex,
.vtxSize = 5757,
.textures = mario_raceway_textures,
.displaylists = d_course_mario_raceway_packed_dls,
.dlSize = 3367
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = NULL,
.vtx = NULL,
.vtxSize = 0,
.textures = NULL,
.displaylists = NULL,
.dlSize = 0
}, {
.data = d_course_royal_raceway_dl_0,
.vtx = d_course_royal_raceway_vertex,
.vtxSize = 8306,
.textures = royal_raceway_textures,
.displaylists = d_course_royal_raceway_packed_dls,
.dlSize = 5670
}, {
.data = d_course_luigi_raceway_dl_0,
.vtx = d_course_luigi_raceway_vertex,
.vtxSize = 5936,
.textures = luigi_raceway_textures,
.displaylists = d_course_luigi_raceway_packed_dls,
.dlSize = 6377
}
};
/** Load Lakitu Textures **/
u8 *load_lakitu_textures_x64(const char** textureList, size_t length) {
// Calculate lakitu texture size to allocate
size_t size = 0;
for (size_t i = 0; i < length; i++) {
size += ResourceGetTexSizeByName(textureList[i]);
}
u8 *textures = (u8 *) gNextFreeMemoryAddress;
gNextFreeMemoryAddress += size;
size_t offset = 0;
for (size_t i = 0; i < length; i++) {
u8 *tex = (u8 *) LOAD_ASSET(textureList[i]);
size_t texSize = ResourceGetTexSizeByName(textureList[i]);
//printf("\nTEX SIZE: %X\n\n", texSize);
memcpy(&textures[offset], tex, texSize);
offset += texSize;
}
return textures;
}
void load_course(s32 courseId) {
printf("Loading Course Data\n");
char* data = gNewCourseTable[courseId].data;
char* vtxData = gNewCourseTable[courseId].vtx;
size_t vtxSize = gNewCourseTable[courseId].vtxSize;
course_texture *textures = gNewCourseTable[courseId].textures;
char* displaylists = gNewCourseTable[courseId].displaylists;
size_t dlSize = gNewCourseTable[courseId].dlSize;
// Convert course vtx to vtx
CourseVtx *cvtx = (CourseVtx *) LOAD_ASSET(vtxData);
Vtx *vtx = (Vtx *) allocate_memory(sizeof(Vtx) * vtxSize);
gSegmentTable[4] = &vtx[0];
func_802A86A8(cvtx, vtx, vtxSize);
vtxSegEnd = &vtx[vtxSize];
// Load and allocate memory for course textures
course_texture *asset = textures;
u8 *freeMemory = NULL;
u8 *texture = NULL;
size_t size = 0;
texSegSize = 0;
while (asset->addr) {
size = ResourceGetTexSizeByName(asset->addr);
freeMemory = (u8 *) allocate_memory(size);
texture = (u8 *) LOAD_ASSET(asset->addr);
if (texture) {
if (asset == &textures[0]) {
gSegmentTable[5] = &freeMemory[0];
}
memcpy(freeMemory, texture, size);
texSegSize += size;
// printf("Texture Addr: 0x%llX, size 0x%X\n", &freeMemory[0], size);
}
asset++;
}
texSegEnd = &((u8 *)gSegmentTable[5])[texSegSize];
// Extract packed DLs
u8 *packed = (u8 *) LOAD_ASSET(displaylists);
Gfx *gfx = (Gfx *) allocate_memory(sizeof(Gfx) * dlSize); // Size of unpacked DLs
gSegmentTable[7] = &gfx[0];
displaylist_unpack(gfx, packed, 0);
dlSegEnd = &gfx[dlSize];
}