mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
ma2d1 support
This commit is contained in:
@@ -14,6 +14,7 @@ option(BUILD_SM64 "Build with Super Mario 64 support" ON)
|
||||
option(BUILD_MK64 "Build with Mario Kart 64 support" ON)
|
||||
option(BUILD_SF64 "Build with Star Fox 64 support" ON)
|
||||
option(BUILD_FZERO "Build with F-Zero X support" ON)
|
||||
option(BUILD_MARIO_ARTIST "Build with Mario Artist support" ON)
|
||||
option(BUILD_NAUDIO "Build with NAudio support" ON)
|
||||
|
||||
################################################################################
|
||||
@@ -84,6 +85,12 @@ else()
|
||||
list(FILTER SRC_DIR EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/src/factories/fzerox/*")
|
||||
endif()
|
||||
|
||||
if(BUILD_MARIO_ARTIST)
|
||||
add_definitions(-DMARIO_ARTIST_SUPPORT)
|
||||
else()
|
||||
list(FILTER SRC_DIR EXCLUDE REGEX "${CMAKE_CURRENT_SOURCE_DIR}/src/factories/mario_artist/*")
|
||||
endif()
|
||||
|
||||
if(BUILD_NAUDIO)
|
||||
add_definitions(-DNAUDIO_SUPPORT)
|
||||
else()
|
||||
|
||||
@@ -3,6 +3,221 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// defines
|
||||
|
||||
#define GET_BIT(buf, bit) ((buf)[(bit) / 8] & (1 << (7 - ((bit) % 8))))
|
||||
|
||||
// types
|
||||
typedef struct
|
||||
{
|
||||
int *indexes;
|
||||
int allocated;
|
||||
int count;
|
||||
int start;
|
||||
} lookback;
|
||||
|
||||
// functions
|
||||
#define LOOKBACK_COUNT 256
|
||||
#define LOOKBACK_INIT_SIZE 128
|
||||
static lookback *lookback_init(void)
|
||||
{
|
||||
lookback *lb = malloc(LOOKBACK_COUNT * sizeof(*lb));
|
||||
for (int i = 0; i < LOOKBACK_COUNT; i++) {
|
||||
lb[i].allocated = LOOKBACK_INIT_SIZE;
|
||||
lb[i].indexes = malloc(lb[i].allocated * sizeof(*lb[i].indexes));
|
||||
lb[i].count = 0;
|
||||
lb[i].start = 0;
|
||||
}
|
||||
return lb;
|
||||
}
|
||||
|
||||
static void lookback_free(lookback *lb)
|
||||
{
|
||||
for (int i = 0; i < LOOKBACK_COUNT; i++) {
|
||||
free(lb[i].indexes);
|
||||
}
|
||||
free(lb);
|
||||
}
|
||||
|
||||
static inline void lookback_push(lookback *lkbk, unsigned char val, int index)
|
||||
{
|
||||
lookback *lb = &lkbk[val];
|
||||
if (lb->count == lb->allocated) {
|
||||
lb->allocated *= 4;
|
||||
lb->indexes = realloc(lb->indexes, lb->allocated * sizeof(*lb->indexes));
|
||||
}
|
||||
lb->indexes[lb->count++] = index;
|
||||
}
|
||||
|
||||
static void PUT_BIT(unsigned char *buf, int bit, int val)
|
||||
{
|
||||
unsigned char mask = 1 << (7 - (bit % 8));
|
||||
unsigned int offset = bit / 8;
|
||||
buf[offset] = (buf[offset] & ~(mask)) | (val ? mask : 0);
|
||||
}
|
||||
|
||||
// used to find longest matching stream in buffer
|
||||
// buf: buffer
|
||||
// start_offset: offset in buf to look back from
|
||||
// max_search: max number of bytes to find
|
||||
// found_offset: returned offset found (0 if none found)
|
||||
// returns max length of matching stream (0 if none found)
|
||||
static int find_longest(const unsigned char *buf, int start_offset, int max_search, int *found_offset, lookback *lkbk)
|
||||
{
|
||||
int best_length = 0;
|
||||
int best_offset = 0;
|
||||
int cur_length;
|
||||
int search_len;
|
||||
int farthest, off, i;
|
||||
int lb_idx;
|
||||
const unsigned char first = buf[start_offset];
|
||||
lookback *lb = &lkbk[first];
|
||||
|
||||
// buf
|
||||
// | off start max
|
||||
// V |+i-> |+i-> |
|
||||
// |--------------raw-data-----------------|
|
||||
// |+i-> | |+i->
|
||||
// +cur_length
|
||||
|
||||
// check at most the past 4096 values
|
||||
farthest = MAX(start_offset - 4096, 0);
|
||||
// find starting index
|
||||
for (lb_idx = lb->start; lb_idx < lb->count && lb->indexes[lb_idx] < farthest; lb_idx++) {}
|
||||
lb->start = lb_idx;
|
||||
for ( ; lb_idx < lb->count && lb->indexes[lb_idx] < start_offset; lb_idx++) {
|
||||
off = lb->indexes[lb_idx];
|
||||
// check at most requested max or up until start
|
||||
search_len = MIN(max_search, start_offset - off);
|
||||
for (i = 0; i < search_len; i++) {
|
||||
if (buf[start_offset + i] != buf[off + i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_length = i;
|
||||
// if matched up until start, continue matching in already matched parts
|
||||
if (cur_length == search_len) {
|
||||
// check at most requested max less current length
|
||||
search_len = max_search - cur_length;
|
||||
for (i = 0; i < search_len; i++) {
|
||||
if (buf[start_offset + cur_length + i] != buf[off + i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_length += i;
|
||||
}
|
||||
if (cur_length > best_length) {
|
||||
best_offset = start_offset - off;
|
||||
best_length = cur_length;
|
||||
}
|
||||
}
|
||||
|
||||
// return best reverse offset and length (may be 0)
|
||||
*found_offset = best_offset;
|
||||
return best_length;
|
||||
}
|
||||
|
||||
int32_t yay0_encode(const uint8_t *in_buf, uint32_t length, uint8_t* out_buf) {
|
||||
unsigned char *bit_buf;
|
||||
unsigned char *comp_buf;
|
||||
unsigned char *uncomp_buf;
|
||||
unsigned int bit_length;
|
||||
unsigned int comp_offset;
|
||||
unsigned int uncomp_offset;
|
||||
unsigned int bytes_proc = 0;
|
||||
int bytes_written;
|
||||
int bit_idx = 0;
|
||||
int comp_idx = 0;
|
||||
int uncomp_idx = 0;
|
||||
lookback *lookbacks;
|
||||
|
||||
// initialize lookback buffer
|
||||
lookbacks = lookback_init();
|
||||
|
||||
// allocate some temporary buffers worst case size
|
||||
bit_buf = malloc((length + 7) / 8); // 1-bit/byte
|
||||
comp_buf = malloc(length); // 16-bits/2bytes
|
||||
uncomp_buf = malloc(length); // all uncompressed
|
||||
memset(bit_buf, 0, (length + 7) / 8);
|
||||
|
||||
// encode data
|
||||
// special case for first byte
|
||||
lookback_push(lookbacks, in_buf[0], 0);
|
||||
uncomp_buf[uncomp_idx] = in_buf[0];
|
||||
uncomp_idx += 1;
|
||||
bytes_proc += 1;
|
||||
PUT_BIT(bit_buf, bit_idx++, 1);
|
||||
while (bytes_proc < length) {
|
||||
int offset;
|
||||
int max_length = MIN(length - bytes_proc, 0x111);
|
||||
int longest_match = find_longest(in_buf, bytes_proc, max_length, &offset, lookbacks);
|
||||
// push current byte before checking next longer match
|
||||
lookback_push(lookbacks, in_buf[bytes_proc], bytes_proc);
|
||||
if (longest_match > 2) {
|
||||
int lookahead_offset;
|
||||
// lookahead to next byte to see if longer match
|
||||
int lookahead_length = MIN(length - bytes_proc - 1, 0x111);
|
||||
int lookahead_match = find_longest(in_buf, bytes_proc + 1, lookahead_length, &lookahead_offset, lookbacks);
|
||||
// better match found, use uncompressed + lookahead compressed
|
||||
if ((longest_match + 1) < lookahead_match) {
|
||||
// uncompressed byte
|
||||
uncomp_buf[uncomp_idx] = in_buf[bytes_proc];
|
||||
uncomp_idx++;
|
||||
PUT_BIT(bit_buf, bit_idx, 1);
|
||||
bytes_proc++;
|
||||
longest_match = lookahead_match;
|
||||
offset = lookahead_offset;
|
||||
bit_idx++;
|
||||
lookback_push(lookbacks, in_buf[bytes_proc], bytes_proc);
|
||||
}
|
||||
// first byte already pushed above
|
||||
for (int i = 1; i < longest_match; i++) {
|
||||
lookback_push(lookbacks, in_buf[bytes_proc + i], bytes_proc + i);
|
||||
}
|
||||
// compressed block
|
||||
comp_buf[comp_idx] = (((longest_match - 3) & 0x0F) << 4) |
|
||||
(((offset - 1) >> 8) & 0x0F);
|
||||
comp_buf[comp_idx + 1] = (offset - 1) & 0xFF;
|
||||
comp_idx += 2;
|
||||
PUT_BIT(bit_buf, bit_idx, 0);
|
||||
bytes_proc += longest_match;
|
||||
} else {
|
||||
// uncompressed byte
|
||||
uncomp_buf[uncomp_idx] = in_buf[bytes_proc];
|
||||
uncomp_idx++;
|
||||
PUT_BIT(bit_buf, bit_idx, 1);
|
||||
bytes_proc++;
|
||||
}
|
||||
bit_idx++;
|
||||
}
|
||||
|
||||
// compute final sizes and offsets
|
||||
// +7 so int division accounts for all bits
|
||||
bit_length = ((bit_idx + 7) / 8);
|
||||
// compressed data after control bits and aligned to 4-byte boundary
|
||||
comp_offset = ALIGN(YAY0_HEADER_LENGTH + bit_length, 4);
|
||||
uncomp_offset = comp_offset + comp_idx;
|
||||
bytes_written = uncomp_offset + uncomp_idx;
|
||||
|
||||
// output header
|
||||
memcpy(out_buf, "Yay0", 4);
|
||||
write_u32_be(&out_buf[4], length);
|
||||
write_u32_be(&out_buf[8], comp_offset);
|
||||
write_u32_be(&out_buf[12], uncomp_offset);
|
||||
// output data
|
||||
memcpy(&out_buf[YAY0_HEADER_LENGTH], bit_buf, bit_length);
|
||||
memcpy(&out_buf[comp_offset], comp_buf, comp_idx);
|
||||
memcpy(&out_buf[uncomp_offset], uncomp_buf, uncomp_idx);
|
||||
|
||||
// free allocated buffers
|
||||
free(bit_buf);
|
||||
free(comp_buf);
|
||||
free(uncomp_buf);
|
||||
lookback_free(lookbacks);
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint8_t* yay0_decode(const uint8_t* in_buf, uint32_t* out_size){
|
||||
|
||||
const uint8_t* in = in_buf;
|
||||
|
||||
@@ -2,4 +2,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define YAY0_HEADER_LENGTH 16
|
||||
|
||||
extern int32_t yay0_encode(const uint8_t *in_buf, uint32_t length, uint8_t* out_buf);
|
||||
extern uint8_t* yay0_decode(const uint8_t* in, uint32_t* out_size);
|
||||
@@ -0,0 +1,281 @@
|
||||
#include "yay1.h"
|
||||
#include "libmio0/utils.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// defines
|
||||
|
||||
#define GET_BIT(buf, bit) ((buf)[(bit) / 8] & (1 << (7 - ((bit) % 8))))
|
||||
|
||||
// types
|
||||
typedef struct
|
||||
{
|
||||
int *indexes;
|
||||
int allocated;
|
||||
int count;
|
||||
int start;
|
||||
} lookback;
|
||||
|
||||
// functions
|
||||
#define LOOKBACK_COUNT 256
|
||||
#define LOOKBACK_INIT_SIZE 128
|
||||
static lookback *lookback_init(void)
|
||||
{
|
||||
lookback *lb = malloc(LOOKBACK_COUNT * sizeof(*lb));
|
||||
for (int i = 0; i < LOOKBACK_COUNT; i++) {
|
||||
lb[i].allocated = LOOKBACK_INIT_SIZE;
|
||||
lb[i].indexes = malloc(lb[i].allocated * sizeof(*lb[i].indexes));
|
||||
lb[i].count = 0;
|
||||
lb[i].start = 0;
|
||||
}
|
||||
return lb;
|
||||
}
|
||||
|
||||
static void lookback_free(lookback *lb)
|
||||
{
|
||||
for (int i = 0; i < LOOKBACK_COUNT; i++) {
|
||||
free(lb[i].indexes);
|
||||
}
|
||||
free(lb);
|
||||
}
|
||||
|
||||
static inline void lookback_push(lookback *lkbk, unsigned char val, int index)
|
||||
{
|
||||
lookback *lb = &lkbk[val];
|
||||
if (lb->count == lb->allocated) {
|
||||
lb->allocated *= 4;
|
||||
lb->indexes = realloc(lb->indexes, lb->allocated * sizeof(*lb->indexes));
|
||||
}
|
||||
lb->indexes[lb->count++] = index;
|
||||
}
|
||||
|
||||
static void PUT_BIT(unsigned char *buf, int bit, int val)
|
||||
{
|
||||
unsigned char mask = 1 << (7 - (bit % 8));
|
||||
unsigned int offset = bit / 8;
|
||||
buf[offset] = (buf[offset] & ~(mask)) | (val ? mask : 0);
|
||||
}
|
||||
|
||||
// used to find longest matching stream in buffer
|
||||
// buf: buffer
|
||||
// start_offset: offset in buf to look back from
|
||||
// max_search: max number of bytes to find
|
||||
// found_offset: returned offset found (0 if none found)
|
||||
// returns max length of matching stream (0 if none found)
|
||||
static int find_longest(const unsigned char *buf, int start_offset, int max_search, int *found_offset, lookback *lkbk)
|
||||
{
|
||||
int best_length = 0;
|
||||
int best_offset = 0;
|
||||
int cur_length;
|
||||
int search_len;
|
||||
int farthest, off, i;
|
||||
int lb_idx;
|
||||
const unsigned char first = buf[start_offset];
|
||||
lookback *lb = &lkbk[first];
|
||||
|
||||
// buf
|
||||
// | off start max
|
||||
// V |+i-> |+i-> |
|
||||
// |--------------raw-data-----------------|
|
||||
// |+i-> | |+i->
|
||||
// +cur_length
|
||||
|
||||
// check at most the past 4096 values
|
||||
farthest = MAX(start_offset - 4096, 0);
|
||||
// find starting index
|
||||
for (lb_idx = lb->start; lb_idx < lb->count && lb->indexes[lb_idx] < farthest; lb_idx++) {}
|
||||
lb->start = lb_idx;
|
||||
for ( ; lb_idx < lb->count && lb->indexes[lb_idx] < start_offset; lb_idx++) {
|
||||
off = lb->indexes[lb_idx];
|
||||
// check at most requested max or up until start
|
||||
search_len = MIN(max_search, start_offset - off);
|
||||
for (i = 0; i < search_len; i++) {
|
||||
if (buf[start_offset + i] != buf[off + i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_length = i;
|
||||
// if matched up until start, continue matching in already matched parts
|
||||
if (cur_length == search_len) {
|
||||
// check at most requested max less current length
|
||||
search_len = max_search - cur_length;
|
||||
for (i = 0; i < search_len; i++) {
|
||||
if (buf[start_offset + cur_length + i] != buf[off + i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_length += i;
|
||||
}
|
||||
if (cur_length > best_length) {
|
||||
best_offset = start_offset - off;
|
||||
best_length = cur_length;
|
||||
}
|
||||
}
|
||||
|
||||
// return best reverse offset and length (may be 0)
|
||||
*found_offset = best_offset;
|
||||
return best_length;
|
||||
}
|
||||
|
||||
int32_t yay1_encode(const uint8_t *in_buf, uint32_t length, uint8_t* out_buf) {
|
||||
unsigned char *bit_buf;
|
||||
unsigned char *comp_buf;
|
||||
unsigned char *uncomp_buf;
|
||||
unsigned int bit_length;
|
||||
unsigned int comp_offset;
|
||||
unsigned int uncomp_offset;
|
||||
unsigned int bytes_proc = 0;
|
||||
int bytes_written;
|
||||
int bit_idx = 0;
|
||||
int comp_idx = 0;
|
||||
int uncomp_idx = 0;
|
||||
lookback *lookbacks;
|
||||
|
||||
// initialize lookback buffer
|
||||
lookbacks = lookback_init();
|
||||
|
||||
// allocate some temporary buffers worst case size
|
||||
bit_buf = malloc((length + 7) / 8); // 1-bit/byte
|
||||
comp_buf = malloc(length); // 16-bits/2bytes
|
||||
uncomp_buf = malloc(length); // all uncompressed
|
||||
memset(bit_buf, 0, (length + 7) / 8);
|
||||
|
||||
// encode data
|
||||
// special case for first byte
|
||||
lookback_push(lookbacks, in_buf[0], 0);
|
||||
uncomp_buf[uncomp_idx] = in_buf[0];
|
||||
uncomp_idx += 1;
|
||||
bytes_proc += 1;
|
||||
PUT_BIT(bit_buf, bit_idx++, 1);
|
||||
while (bytes_proc < length) {
|
||||
int offset;
|
||||
int max_length = MIN(length - bytes_proc, 0x111);
|
||||
int longest_match = find_longest(in_buf, bytes_proc, max_length, &offset, lookbacks);
|
||||
// push current byte before checking next longer match
|
||||
lookback_push(lookbacks, in_buf[bytes_proc], bytes_proc);
|
||||
if (longest_match > 2) {
|
||||
int lookahead_offset;
|
||||
// lookahead to next byte to see if longer match
|
||||
int lookahead_length = MIN(length - bytes_proc - 1, 0x111);
|
||||
int lookahead_match = find_longest(in_buf, bytes_proc + 1, lookahead_length, &lookahead_offset, lookbacks);
|
||||
// better match found, use uncompressed + lookahead compressed
|
||||
if ((longest_match + 1) < lookahead_match) {
|
||||
// uncompressed byte
|
||||
uncomp_buf[uncomp_idx] = in_buf[bytes_proc];
|
||||
uncomp_idx++;
|
||||
PUT_BIT(bit_buf, bit_idx, 1);
|
||||
bytes_proc++;
|
||||
longest_match = lookahead_match;
|
||||
offset = lookahead_offset;
|
||||
bit_idx++;
|
||||
lookback_push(lookbacks, in_buf[bytes_proc], bytes_proc);
|
||||
}
|
||||
// first byte already pushed above
|
||||
for (int i = 1; i < longest_match; i++) {
|
||||
lookback_push(lookbacks, in_buf[bytes_proc + i], bytes_proc + i);
|
||||
}
|
||||
// compressed block
|
||||
comp_buf[comp_idx] = (((longest_match - 3) & 0x0F) << 4) |
|
||||
(((offset - 1) >> 8) & 0x0F);
|
||||
comp_buf[comp_idx + 1] = (offset - 1) & 0xFF;
|
||||
comp_idx += 2;
|
||||
PUT_BIT(bit_buf, bit_idx, 0);
|
||||
bytes_proc += longest_match;
|
||||
} else {
|
||||
// uncompressed byte
|
||||
uncomp_buf[uncomp_idx] = in_buf[bytes_proc];
|
||||
uncomp_idx++;
|
||||
PUT_BIT(bit_buf, bit_idx, 1);
|
||||
bytes_proc++;
|
||||
}
|
||||
bit_idx++;
|
||||
}
|
||||
|
||||
// compute final sizes and offsets
|
||||
// +7 so int division accounts for all bits
|
||||
bit_length = ((bit_idx + 7) / 8);
|
||||
// compressed data after control bits and aligned to 4-byte boundary
|
||||
comp_offset = ALIGN(YAY1_HEADER_LENGTH + bit_length, 4);
|
||||
uncomp_offset = comp_offset + comp_idx;
|
||||
bytes_written = uncomp_offset + uncomp_idx;
|
||||
|
||||
// output header
|
||||
memcpy(out_buf, "Yay1", 4);
|
||||
write_u32_be(&out_buf[4], length);
|
||||
write_u32_be(&out_buf[8], comp_offset);
|
||||
write_u32_be(&out_buf[12], uncomp_offset);
|
||||
// output data
|
||||
memcpy(&out_buf[YAY1_HEADER_LENGTH], bit_buf, bit_length);
|
||||
memcpy(&out_buf[comp_offset], comp_buf, comp_idx);
|
||||
memcpy(&out_buf[uncomp_offset], uncomp_buf, uncomp_idx);
|
||||
|
||||
// free allocated buffers
|
||||
free(bit_buf);
|
||||
free(comp_buf);
|
||||
free(uncomp_buf);
|
||||
lookback_free(lookbacks);
|
||||
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
uint8_t* yay1_decode(const uint8_t* in_buf, uint32_t* out_size){
|
||||
|
||||
const uint8_t* in = in_buf;
|
||||
|
||||
if(strncmp(in, "Yay1", 4) != 0){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32_t decompressed_size = read_u32_be(in + 4);
|
||||
uint32_t link_table_offset = read_u32_be(in + 8);
|
||||
uint32_t chunk_offset = read_u32_be(in + 12);
|
||||
|
||||
uint32_t link_table_idx = link_table_offset;
|
||||
uint32_t chunk_idx = chunk_offset;
|
||||
uint32_t other_idx = 16;
|
||||
|
||||
uint32_t mask_bit_counter = 0;
|
||||
uint32_t current_mask = 0;
|
||||
uint32_t idx = 0;
|
||||
|
||||
uint8_t* out = malloc(decompressed_size);
|
||||
memset(out, 0, decompressed_size);
|
||||
*out_size = decompressed_size;
|
||||
|
||||
while(idx < decompressed_size){
|
||||
if(mask_bit_counter == 0){
|
||||
current_mask = read_u32_be(in + other_idx);
|
||||
other_idx += 4;
|
||||
mask_bit_counter = 32;
|
||||
}
|
||||
|
||||
if(current_mask & 0x80000000){
|
||||
out[idx] = in[chunk_idx];
|
||||
idx++;
|
||||
chunk_idx++;
|
||||
} else {
|
||||
uint16_t link = read_u16_be(in + link_table_idx);
|
||||
link_table_idx += 2;
|
||||
uint32_t offset = idx - (link & 0xFFF);
|
||||
uint32_t count = link >> 12;
|
||||
|
||||
if(count == 0){
|
||||
uint8_t count_modifier = in[chunk_idx];
|
||||
chunk_idx++;
|
||||
count = count_modifier + 18;
|
||||
} else {
|
||||
count += 2;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < count; i++){
|
||||
out[idx] = out[offset + i - 1];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
current_mask <<= 1;
|
||||
mask_bit_counter--;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define YAY1_HEADER_LENGTH 16
|
||||
|
||||
extern int32_t yay1_encode(const uint8_t *in_buf, uint32_t length, uint8_t* out_buf);
|
||||
extern uint8_t* yay1_decode(const uint8_t* in, uint32_t* out_size);
|
||||
@@ -75,6 +75,10 @@
|
||||
#include "factories/fzerox/GhostRecordFactory.h"
|
||||
#endif
|
||||
|
||||
#ifdef MARIO_ARTIST_SUPPORT
|
||||
#include "factories/mario_artist/MA2D1Factory.h"
|
||||
#endif
|
||||
|
||||
#ifdef NAUDIO_SUPPORT
|
||||
#include "factories/naudio/v0/AudioHeaderFactory.h"
|
||||
#include "factories/naudio/v0/BankFactory.h"
|
||||
@@ -169,6 +173,10 @@ void Companion::Init(const ExportType type) {
|
||||
this->RegisterFactory("FZX:GHOST", std::make_shared<FZX::GhostRecordFactory>());
|
||||
#endif
|
||||
|
||||
#ifdef MARIO_ARTIST_SUPPORT
|
||||
this->RegisterFactory("MA:MA2D1", std::make_shared<MA::MA2D1Factory>());
|
||||
#endif
|
||||
|
||||
#ifdef NAUDIO_SUPPORT
|
||||
this->RegisterFactory("NAUDIO:V0:AUDIO_HEADER", std::make_shared<AudioHeaderFactory>());
|
||||
this->RegisterFactory("NAUDIO:V0:SEQUENCE", std::make_shared<SequenceFactory>());
|
||||
|
||||
@@ -9,6 +9,8 @@ extern "C" {
|
||||
#include "n64graphics/n64graphics.h"
|
||||
#include "BaseFactory.h"
|
||||
#include <libmio0/mio0.h>
|
||||
#include <libyay0/yay0.h>
|
||||
#include <libyay0/yay1.h>
|
||||
}
|
||||
|
||||
static bool isTable = false;
|
||||
@@ -31,6 +33,7 @@ static const std::unordered_map <std::string, TextureFormat> sTextureFormats = {
|
||||
static const std::unordered_map <std::string, CompressionType> sCompressionTypes = {
|
||||
{ "MIO0", CompressionType::MIO0 },
|
||||
{ "YAY0", CompressionType::YAY0 },
|
||||
{ "YAY1", CompressionType::YAY1 },
|
||||
{ "YAZ0", CompressionType::YAZ0 },
|
||||
};
|
||||
|
||||
@@ -86,6 +89,16 @@ ExportResult CompressedTextureHeaderExporter::Export(std::ostream &write, std::s
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = mio0_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
case CompressionType::YAY0:
|
||||
worstSize = YAY0_HEADER_LENGTH + ((data.size()+7)/8) + data.size();
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = yay0_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
case CompressionType::YAY1:
|
||||
worstSize = YAY1_HEADER_LENGTH + ((data.size()+7)/8) + data.size();
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = yay1_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
default:
|
||||
// UNIMPLEMENTED
|
||||
throw std::runtime_error("Unsupported Compressed Texture Type");
|
||||
@@ -151,6 +164,16 @@ ExportResult CompressedTextureCodeExporter::Export(std::ostream &write, std::sha
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = mio0_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
case CompressionType::YAY0:
|
||||
worstSize = YAY0_HEADER_LENGTH + ((data.size()+7)/8) + data.size();
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = yay0_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
case CompressionType::YAY1:
|
||||
worstSize = YAY1_HEADER_LENGTH + ((data.size()+7)/8) + data.size();
|
||||
compressedData = static_cast<uint8_t*>(std::calloc(worstSize, sizeof(uint8_t)));
|
||||
compressedSize = yay1_encode(data.data(), data.size(), compressedData);
|
||||
break;
|
||||
default:
|
||||
// UNIMPLEMENTED
|
||||
throw std::runtime_error("Unsupported Compressed Texture Type");
|
||||
@@ -329,6 +352,8 @@ std::string getcomptype(CompressionType type) {
|
||||
return "MIO0";
|
||||
case CompressionType::YAY0:
|
||||
return "YAY0";
|
||||
case CompressionType::YAY1:
|
||||
return "YAY1";
|
||||
case CompressionType::YAZ0:
|
||||
return "YAZ0";
|
||||
default:
|
||||
@@ -350,7 +375,7 @@ std::optional<std::shared_ptr<IParsedData>> CompressedTextureFactory::parse(std:
|
||||
if (!sCompressionTypes.contains(compression)) {
|
||||
SPDLOG_ERROR("Compresed Texture entry at {:X} in yaml missing compression type\n\
|
||||
Please add one of the following compression types\n\
|
||||
MIO0, YAY0 (Unsupported), YAZ0 (Unsupported)", offset);
|
||||
MIO0, YAY0, YAY1, YAZ0 (Unsupported)", offset);
|
||||
return std::nullopt;
|
||||
}
|
||||
compressionType = sCompressionTypes.at(compression);
|
||||
@@ -447,7 +472,7 @@ std::optional<std::shared_ptr<IParsedData>> CompressedTextureFactory::parse_modd
|
||||
if (!sCompressionTypes.contains(compression)) {
|
||||
SPDLOG_ERROR("Compresed Texture entry at {:X} in yaml missing compression type\n\
|
||||
Please add one of the following compression types\n\
|
||||
MIO0, YAY0 (Unsupported), YAZ0 (Unsupported)", offset);
|
||||
MIO0, YAY0, YAY1, YAZ0 (Unsupported)", offset);
|
||||
return std::nullopt;
|
||||
}
|
||||
compressionType = sCompressionTypes.at(compression);
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "MA2D1Factory.h"
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
#include "Companion.h"
|
||||
#include "utils/Decompressor.h"
|
||||
#include "utils/TorchUtils.h"
|
||||
|
||||
ExportResult MA::MA2D1HeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) {
|
||||
const auto symbol = GetSafeNode(node, "symbol", entryName);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
ExportResult MA::MA2D1CodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
|
||||
const auto symbol = GetSafeNode(node, "symbol", entryName);
|
||||
const auto offset = GetSafeNode<uint32_t>(node, "offset");
|
||||
const auto data = std::static_pointer_cast<MA2D1Data>(raw);
|
||||
|
||||
write << "char " << symbol << "_header" << "[] = { ";
|
||||
|
||||
for (size_t i = 0; i < data->mFormat.size(); i++) {
|
||||
if (i != 0) {
|
||||
write << ", ";
|
||||
}
|
||||
|
||||
write << "\'" << data->mFormat.at(i) << "\'";
|
||||
}
|
||||
|
||||
write << ", \'" << ((data->mWidth / 100) % 10) << "\'";
|
||||
write << ", \'" << ((data->mWidth / 10) % 10) << "\'";
|
||||
write << ", \'" << ((data->mWidth / 1) % 10) << "\'";
|
||||
|
||||
write << ", \'" << ((data->mHeight / 100) % 10) << "\'";
|
||||
write << ", \'" << ((data->mHeight / 10) % 10) << "\'";
|
||||
write << ", \'" << ((data->mHeight / 1) % 10) << "\'";
|
||||
|
||||
write << ", \'" << ((data->mSize / 100000) % 10) << "\'";
|
||||
write << ", \'" << ((data->mSize / 10000) % 10) << "\'";
|
||||
write << ", \'" << ((data->mSize / 1000) % 10) << "\'";
|
||||
write << ", \'" << ((data->mSize / 100) % 10) << "\'";
|
||||
write << ", \'" << ((data->mSize / 10) % 10) << "\'";
|
||||
write << ", \'" << ((data->mSize / 1) % 10) << "\'";
|
||||
|
||||
write << " };\n\n";
|
||||
|
||||
return offset + 0x10;
|
||||
}
|
||||
|
||||
ExportResult MA::MA2D1BinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
|
||||
// Nothing Required Here For Binary Exporting
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<IParsedData>> MA::MA2D1Factory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
|
||||
auto [_, segment] = Decompressor::AutoDecode(node, buffer);
|
||||
const auto offset = GetSafeNode<uint32_t>(node, "offset");
|
||||
const auto symbol = GetSafeNode<std::string>(node, "symbol");
|
||||
LUS::BinaryReader reader(segment.data, segment.size);
|
||||
|
||||
reader.SetEndianness(Torch::Endianness::Big);
|
||||
|
||||
YAML::Node thumbnail;
|
||||
thumbnail["type"] = "TEXTURE";
|
||||
thumbnail["ctype"] = "u16";
|
||||
thumbnail["format"] = "RGBA16";
|
||||
thumbnail["width"] = 24;
|
||||
thumbnail["height"] = 24;
|
||||
thumbnail["offset"] = offset;
|
||||
thumbnail["symbol"] = symbol + "_thumb";
|
||||
Companion::Instance->AddAsset(thumbnail);
|
||||
|
||||
reader.Seek(0x480, LUS::SeekOffsetType::Start);
|
||||
|
||||
char headerBuffer[0x10];
|
||||
|
||||
for (size_t i = 0; i < sizeof(headerBuffer); i++) {
|
||||
headerBuffer[i] = reader.ReadChar();
|
||||
}
|
||||
|
||||
// Override offset
|
||||
node["offset"] = offset + 0x480;
|
||||
|
||||
std::string format(headerBuffer, headerBuffer + 4);
|
||||
|
||||
uint32_t width = std::stoi(std::string(headerBuffer + 4, 3));
|
||||
uint32_t height = std::stoi(std::string(headerBuffer + 7, 3));
|
||||
uint32_t size = std::stoi(std::string(headerBuffer + 10, 6));
|
||||
|
||||
YAML::Node image;
|
||||
if (format == "NCMP") {
|
||||
image["type"] = "COMPRESSED_TEXTURE";
|
||||
image["compression"] = "YAY1";
|
||||
} else {
|
||||
image["type"] = "TEXTURE";
|
||||
}
|
||||
|
||||
image["ctype"] = "u16";
|
||||
image["format"] = "RGBA16";
|
||||
image["width"] = width;
|
||||
image["height"] = height;
|
||||
image["offset"] = offset + 0x490;
|
||||
image["symbol"] = symbol + "_image";
|
||||
Companion::Instance->AddAsset(image);
|
||||
|
||||
return std::make_shared<MA2D1Data>(format, width, height, size);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <factories/BaseFactory.h>
|
||||
|
||||
namespace MA {
|
||||
|
||||
class MA2D1Data : public IParsedData {
|
||||
public:
|
||||
std::string mFormat;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
uint32_t mSize;
|
||||
|
||||
MA2D1Data(std::string format, uint32_t width, uint32_t height, uint32_t size) :
|
||||
mFormat(format),
|
||||
mWidth(width),
|
||||
mHeight(height),
|
||||
mSize(size) {}
|
||||
};
|
||||
|
||||
class MA2D1HeaderExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class MA2D1BinaryExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class MA2D1CodeExporter : public BaseExporter {
|
||||
ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override;
|
||||
};
|
||||
|
||||
class MA2D1Factory : public BaseFactory {
|
||||
public:
|
||||
std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override;
|
||||
inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override {
|
||||
return {
|
||||
REGISTER(Code, MA2D1CodeExporter)
|
||||
REGISTER(Header, MA2D1HeaderExporter)
|
||||
REGISTER(Binary, MA2D1BinaryExporter)
|
||||
};
|
||||
}
|
||||
bool HasModdedDependencies() override { return true; }
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
extern "C" {
|
||||
#include <libmio0/mio0.h>
|
||||
#include <libyay0/yay0.h>
|
||||
#include <libyay0/yay1.h>
|
||||
#include <libmio0/tkmk00.h>
|
||||
}
|
||||
|
||||
@@ -43,6 +44,17 @@ DataChunk* Decompressor::Decode(const std::vector<uint8_t>& buffer, const uint32
|
||||
gCachedChunks[offset] = new DataChunk{ decompressed, size };
|
||||
return gCachedChunks[offset];
|
||||
}
|
||||
case CompressionType::YAY1: {
|
||||
uint32_t size = 0;
|
||||
uint8_t* decompressed = yay1_decode(in_buf, &size);
|
||||
|
||||
if(!decompressed){
|
||||
throw std::runtime_error("Failed to decode YAY1");
|
||||
}
|
||||
|
||||
gCachedChunks[offset] = new DataChunk{ decompressed, size };
|
||||
return gCachedChunks[offset];
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Unknown compression type");
|
||||
}
|
||||
@@ -106,6 +118,7 @@ DecompressedData Decompressor::AutoDecode(YAML::Node& node, std::vector<uint8_t>
|
||||
// Extract a compressed file which contains many assets.
|
||||
switch(type) {
|
||||
case CompressionType::YAY0:
|
||||
case CompressionType::YAY1:
|
||||
case CompressionType::MIO0: {
|
||||
offset = ASSET_PTR(offset);
|
||||
|
||||
@@ -181,6 +194,10 @@ CompressionType Decompressor::GetCompressionType(std::vector<uint8_t>& buffer, c
|
||||
return CompressionType::YAY0;
|
||||
}
|
||||
|
||||
if (header == "Yay1") {
|
||||
return CompressionType::YAY1;
|
||||
}
|
||||
|
||||
if (header == "Yaz0") {
|
||||
return CompressionType::YAZ0;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ enum class CompressionType {
|
||||
None,
|
||||
MIO0,
|
||||
YAY0,
|
||||
YAY1,
|
||||
YAZ0,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user