Organize code structure, generate CBMD files without premade headers.

This commit is contained in:
Steveice10
2015-01-23 18:37:10 -08:00
parent 78ee395ea5
commit 9360d55bd5
13 changed files with 245 additions and 103 deletions

9
source/3ds/3ds.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef __3DS_H__
#define __3DS_H__
#include "cbmd.h"
#include "lz11.h"
#include "types.h"
#include "util.h"
#endif

81
source/3ds/cbmd.cpp Normal file
View File

@@ -0,0 +1,81 @@
#include "cbmd.h"
#include "lz11.h"
#include <string.h>
#include <malloc.h>
typedef struct {
char magic[4] = {'C', 'B', 'M', 'D'};
u32 zero = 0;
u32 cgfxOffsets[14] = {0};
u8 padding[0x44] = {0};
u32 cwavOffset = 0;
} CBMDHeader;
u8* build_cbmd_data(CBMD cbmd, u32* size, bool bnr) {
u32 headerSize = sizeof(CBMDHeader);
CBMDHeader header;
u8* compressedCGFXs[14] = {0};
u32 compressedCGFXSizes[14] = {0};
u32 offset = headerSize;
for(int i = 0; i < 14; i++) {
if(cbmd.cgfxs[i] != NULL) {
compressedCGFXs[i] = lz11_compress(cbmd.cgfxs[i], cbmd.cgfxSizes[i], &compressedCGFXSizes[i]);
header.cgfxOffsets[i] = offset;
offset += compressedCGFXSizes[i];
}
}
u32 pad = 0;
if(bnr) {
pad = 16 - (offset % 16);
offset += pad;
}
if(cbmd.cwav != NULL) {
header.cwavOffset = offset;
offset += cbmd.cwavSize;
}
u8* output = (u8*) malloc(offset);
u32 pos = 0;
memcpy(output + pos, &header, headerSize);
pos += headerSize;
for(int i = 0; i < 14; i++) {
if(compressedCGFXs[i] != NULL) {
memcpy(output + pos, compressedCGFXs[i], compressedCGFXSizes[i]);
free(compressedCGFXs[i]);
compressedCGFXs[i] = NULL;
pos += compressedCGFXSizes[i];
}
}
if(bnr) {
memset(output + pos, 0, pad);
pos += pad;
}
if(cbmd.cwav != NULL) {
memcpy(output + pos, cbmd.cwav, cbmd.cwavSize);
pos += cbmd.cwavSize;
}
if(size != NULL) {
*size = offset;
}
return output;
}
u8* build_cbmd(CBMD cbmd, u32* size) {
return build_cbmd_data(cbmd, size, false);
}
u8* build_bnr(CBMD cbmd, u32* size) {
return build_cbmd_data(cbmd, size, true);
}

33
source/3ds/cbmd.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef __CBMD_H__
#define __CBMD_H__
#include "types.h"
typedef enum {
CGFX_COMMON,
CGFX_EUR_ENGLISH,
CGFX_EUR_FRENCH,
CGFX_EUR_GERMAN,
CGFX_EUR_ITALIAN,
CGFX_EUR_SPANISH,
CGFX_EUR_DUTCH,
CGFX_EUR_PORTUGESE,
CGFX_EUR_RUSSIAN,
CGFX_JPN_JAPANESE,
CGFX_USA_ENGLISH,
CGFX_USA_FRENCH,
CGFX_USA_SPANISH,
CGFX_USA_PORTUGESE
} CBMDCGFX;
typedef struct {
u8* cgfxs[14] = {NULL};
u32 cgfxSizes[14] = {0};
u8* cwav = NULL;
u32 cwavSize = 0;
} CBMD;
u8* build_cbmd(CBMD cbmd, u32* size);
u8* build_bnr(CBMD cbmd, u32* size);
#endif

126
source/3ds/lz11.cpp Normal file
View File

@@ -0,0 +1,126 @@
#include "lz11.h"
#include <stdio.h>
#include <string.h>
#include <sstream>
#define MIN(a,b) (((a)<(b))?(a):(b))
// Ported from: https://github.com/svn2github/3DS-Explorer/blob/master/3DSExplorer/DSDecmp/Formats/Nitro/LZ11.cs
int lz11_get_occurence_length(u8* newPtr, int newLength, u8* oldPtr, int oldLength, int* disp) {
if(disp != NULL) {
*disp = 0;
}
if(newLength == 0) {
return 0;
}
int maxLength = 0;
for(int i = 0; i < oldLength - 1; i++) {
u8* currentOldStart = oldPtr + i;
int currentLength = 0;
for(int j = 0; j < newLength; j++) {
if(*(currentOldStart + j) != *(newPtr + j)) {
break;
}
currentLength++;
}
if(currentLength > maxLength) {
maxLength = currentLength;
if(disp != NULL) {
*disp = oldLength - i;
}
if(maxLength == newLength) {
break;
}
}
}
return maxLength;
}
u8* lz11_compress(u8* input, u32 inputSize, u32* size) {
if (inputSize > 0xFFFFFF) {
printf("ERROR: LZ11 input is too large.");
return NULL;
}
std::stringstream ss;
u8 header[4] = { 0x11, (u8) (inputSize & 0xFF), (u8) ((inputSize >> 8) & 0xFF), (u8) ((inputSize >> 16) & 0xFF) };
ss.write((char*) header, 4);
int compressedLength = 4;
u8 outbuffer[8 * 4 + 1];
outbuffer[0] = 0;
int bufferlength = 1;
int bufferedBlocks = 0;
int readBytes = 0;
while(readBytes < inputSize) {
if(bufferedBlocks == 8) {
ss.write((char*) outbuffer, bufferlength);
compressedLength += bufferlength;
outbuffer[0] = 0;
bufferlength = 1;
bufferedBlocks = 0;
}
int disp = 0;
int oldLength = MIN(readBytes, 0x1000);
int length = lz11_get_occurence_length(input + readBytes, MIN(inputSize - readBytes, 0x10110), input + readBytes - oldLength, oldLength, &disp);
if(length < 3) {
outbuffer[bufferlength++] = *(input + (readBytes++));
} else {
readBytes += length;
outbuffer[0] |= (u8)(1 << (7 - bufferedBlocks));
if(length > 0x110) {
outbuffer[bufferlength] = 0x10;
outbuffer[bufferlength] |= (u8)(((length - 0x111) >> 12) & 0x0F);
bufferlength++;
outbuffer[bufferlength] = (u8)(((length - 0x111) >> 4) & 0xFF);
bufferlength++;
outbuffer[bufferlength] = (u8)(((length - 0x111) << 4) & 0xF0);
} else if(length > 0x10) {
outbuffer[bufferlength] = 0x00;
outbuffer[bufferlength] |= (u8)(((length - 0x111) >> 4) & 0x0F);
bufferlength++;
outbuffer[bufferlength] = (u8)(((length - 0x111) << 4) & 0xF0);
} else {
outbuffer[bufferlength] = (u8)(((length - 1) << 4) & 0xF0);
}
outbuffer[bufferlength] |= (u8)(((disp - 1) >> 8) & 0x0F);
bufferlength++;
outbuffer[bufferlength] = (u8)((disp - 1) & 0xFF);
bufferlength++;
}
bufferedBlocks++;
}
if(bufferedBlocks > 0) {
ss.write((char*) outbuffer, bufferlength);
compressedLength += bufferlength;
}
if(compressedLength % 4 != 0) {
int padLength = 4 - (compressedLength % 4);
u8 pad[padLength];
memset(pad, 0, (size_t) padLength);
ss.write((char*) pad, padLength);
compressedLength += padLength;
}
u8* buf = (u8*) malloc((size_t) compressedLength);
ss.read((char*) buf, compressedLength);
*size = (u32) compressedLength;
return buf;
}

8
source/3ds/lz11.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __LZ11_H__
#define __LZ11_H__
#include "types.h"
u8* lz11_compress(u8* input, u32 inputSize, u32* size);
#endif

13
source/3ds/types.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef __TYPES_H__
#define __TYPES_H__
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#endif

51
source/3ds/util.cpp Normal file
View File

@@ -0,0 +1,51 @@
#include "util.h"
#include "../lodepng/lodepng.h"
u8 TILE_ORDER[64] = { 0, 1, 8, 9, 2, 3, 10, 11, 16, 17, 24, 25, 18, 19, 26, 27,
4, 5, 12, 13, 6, 7, 14, 15, 20, 21, 28, 29, 22, 23, 30, 31,
32, 33, 40, 41, 34, 35, 42, 43, 48, 49, 56, 57, 50, 51, 58, 59,
36, 37, 44, 45, 38, 39, 46, 47, 52, 53, 60, 61, 54, 55, 62, 63 };
u8* image_to_tiles(const char* image, u32 width, u32 height, u32* size) {
unsigned char* img;
unsigned int imgWidth, imgHeight;
if(lodepng_decode32_file(&img, &imgWidth, &imgHeight, image)) {
printf("ERROR: Could not load png file.\n");
return NULL;
}
if(width == 0) {
width = imgWidth;
}
if(height == 0) {
height = imgHeight;
}
if(imgWidth != width || imgHeight != height) {
printf("ERROR: Image must be exactly %d x %d in size.\n", width, height);
return NULL;
}
u8* converted = (u8*) malloc(width * height * 2);
u32 n = 0;
for(int y = 0; y < height; y += 8) {
for(int x = 0; x < width; x += 8) {
for(int k = 0; k < 8 * 8; k++) {
u32 xx = (u32) (TILE_ORDER[k] & 0x7);
u32 yy = (u32) (TILE_ORDER[k] >> 3);
u8* pixel = img + (((y + yy) * width + (x + xx)) * 4);
converted[n++] = ((pixel[2] >> 4) << 4) | (pixel[3] >> 4);
converted[n++] = ((pixel[0] >> 4) << 4) | (pixel[1] >> 4);
}
}
}
if(size != NULL) {
*size = width * height * 2;
}
return converted;
}

8
source/3ds/util.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef __UTIL_H__
#define __UTIL_H__
#include "types.h"
u8* image_to_tiles(const char* image, u32 width, u32 height, u32* size);
#endif