Last active
June 14, 2022 21:29
-
-
Save MegaLoler/a141dda8871f7912c984f80d96c0427d to your computer and use it in GitHub Desktop.
my random chocobo mystery dungeon psx romhacking scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#define COLOR 5 | |
#define OFFSET (256*128) | |
#define WIDTH 256 | |
#define HEIGHT 64//(512 - 8) | |
#define PAGES 1 | |
#define MAX_ENTRIES 4096 | |
typedef struct clut_entry_t { | |
int stp; /* transparency control bit */ | |
float r; /* red */ | |
float g; /* green */ | |
float b; /* blue */ | |
} clut_entry_t; | |
clut_entry_t *read_clt_file (char *path) { | |
FILE *fp; | |
clut_entry_t *entries; | |
fp = fopen (path, "rb"); | |
/* read all the clut entries */ | |
entries = (clut_entry_t *) malloc (MAX_ENTRIES * sizeof (clut_entry_t)); | |
uint16_t clut; | |
int i = 0; | |
while (fread (&clut, 2, 1, fp) > 0) { | |
int r, g, b; | |
/* read a clut entry */ | |
clut_entry_t *entry = &entries[i++]; | |
r = (clut >> 0) & 0x1f; | |
g = (clut >> 5) & 0x1f; | |
b = (clut >> 10) & 0x1f; | |
entry->stp = (clut >> 15) & 1; | |
entry->r = r / 31.; | |
entry->g = g / 31.; | |
entry->b = b / 31.; | |
} | |
fclose (fp); | |
return entries; | |
} | |
uint32_t lookup (int index, clut_entry_t *palette) { | |
clut_entry_t entry = palette[index + 64 * COLOR]; | |
uint8_t r = entry.r * 255; | |
uint8_t g = entry.g * 255; | |
uint8_t b = entry.b * 255; | |
uint8_t a = (entry.r == 0 && entry.g == 0 && entry.b == 0 && entry.stp == 0) | |
? 0 : 255; | |
uint32_t color = (r << 0) | |
+ (g << 8) | |
+ (b << 16) | |
+ (a << 24); | |
return color; | |
} | |
void decode (FILE *fp, uint32_t *buffer, clut_entry_t *pal) { | |
/* 2bpp, interleaved */ | |
fseek (fp, OFFSET, SEEK_SET); | |
int size = WIDTH * HEIGHT / PAGES; | |
for (int i = 0; i < size;) { | |
uint8_t byte; | |
int a, b, c, d; | |
fread (&byte, 1, 1, fp); | |
a = (byte >> 0) & 0x03; /* buffer a */ | |
b = (byte >> 2) & 0x03; /* buffer b */ | |
c = (byte >> 4) & 0x03; /* buffer a */ | |
d = (byte >> 6) & 0x03; /* buffer b */ | |
buffer[i] = lookup (a, pal); | |
//buffer[i + size] = lookup (b, pal); | |
i++; | |
buffer[i] = lookup (c, pal); | |
//buffer[i + size] = lookup (d, pal); | |
i++; | |
} | |
} | |
int main (int argc, char **argv) { | |
/* 32-bit image buffers */ | |
uint32_t *buffer; | |
/* palette */ | |
clut_entry_t *palette; | |
/* file paths */ | |
char *pxl_path; | |
char *clt_path; | |
char *png_path; | |
/* file handles */ | |
FILE *fp; | |
/* parse arguments */ | |
if (argc != 4) { | |
fprintf (stderr, "usage: %s [input.pxl] [input.clt] [output.png]\n", | |
argv[0]); | |
return EXIT_FAILURE; | |
} | |
pxl_path = argv[1]; | |
clt_path = argv[2]; | |
png_path = argv[3]; | |
/* decode the palette */ | |
palette = read_clt_file (clt_path); | |
/* allocate buffer */ | |
printf ("allocating 32-bit image buffers for %dx%d pixels...\n", | |
WIDTH, HEIGHT); | |
if ((buffer = (uint32_t *) malloc (WIDTH * HEIGHT * sizeof(uint32_t))) | |
== NULL) { | |
fprintf (stderr, "failure to allocate first image buffer.\n"); | |
return EXIT_FAILURE; | |
} | |
/* decode input */ | |
printf ("opening pxl file \"%s\"...\n", pxl_path); | |
if ((fp = fopen (pxl_path, "rb")) == NULL) { | |
fprintf (stderr, "failure to open pxl file \"%s\".\n", pxl_path); | |
return EXIT_FAILURE; | |
} | |
printf ("decoding...\n"); | |
decode (fp, buffer, palette); | |
fclose (fp); | |
/* write out image buffers */ | |
printf ("writing 32-bit %dx%d data to \"%s\"...\n", | |
WIDTH, HEIGHT, png_path); | |
stbi_write_png (png_path, WIDTH, HEIGHT, 4, | |
buffer, sizeof (uint32_t) * WIDTH); | |
/* cleanup */ | |
printf ("done.\n"); | |
free (palette); | |
free (buffer); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <math.h> | |
#define STB_IMAGE_IMPLEMENTATION | |
#include "stb_image.h" | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
/* font dimensions */ | |
#define CHAR_WIDTH 8 // 12 | |
#define CHAR_HEIGHT 8 // 12 | |
/* image dimensions */ | |
#define WIDTH 256 | |
#define HEIGHT 64 // 256 | |
#define Y_OFFSET 256 // 0 | |
int main (int argc, char **argv) { | |
/* read the font file */ | |
int w,h,n; | |
uint8_t *font = stbi_load ("font.png", &w, &h, &n, 4); | |
if (font == NULL) { | |
fprintf (stderr, "couldnt open font.png\n"); | |
return EXIT_FAILURE; | |
} | |
puts ("ok."); | |
/* render image */ | |
int x_chars = WIDTH / CHAR_WIDTH; | |
int y_chars = HEIGHT / CHAR_HEIGHT; | |
int i = 0; | |
printf ("got to chop %d x %d = %d...\n", x_chars, y_chars, x_chars*y_chars); | |
for (int y = 0; y < y_chars; y++) { | |
for (int x = 0; x < x_chars; x++) { | |
int sxo = x * CHAR_WIDTH; | |
int syo = y * CHAR_HEIGHT + Y_OFFSET; | |
printf ("doin #%03d... (%d, %d) (x=%d, y=%d)\n", i, x, y, sxo, syo); | |
uint8_t *buffer = (uint8_t *) malloc (CHAR_WIDTH * CHAR_HEIGHT * 4); | |
for (int dy = 0; dy < CHAR_HEIGHT; dy++) { | |
for (int dx = 0; dx < CHAR_WIDTH; dx++) { | |
int sx = sxo + dx; | |
int sy = syo + dy; | |
int si = (sx + sy * WIDTH) * 4; | |
int di = (dx + dy * CHAR_WIDTH) * 4; | |
buffer[di + 0] = font[si + 0]; | |
buffer[di + 1] = font[si + 1]; | |
buffer[di + 2] = font[si + 2]; | |
buffer[di + 3] = font[si + 3]; | |
} | |
} | |
/* write the png file out */ | |
char path[256]; | |
sprintf (path, "out/%03d.png", i); | |
if (stbi_write_png (path, | |
CHAR_WIDTH, CHAR_HEIGHT, | |
/* rgba */ 4, | |
buffer, | |
/* stride */ CHAR_WIDTH * 4) == 0) { | |
fprintf (stderr, "error writing %s\n", path); | |
return EXIT_FAILURE; | |
} | |
free (buffer); | |
i++; | |
} | |
} | |
puts ("BYE."); | |
stbi_image_free (font); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
font1dir = 'font1' | |
font2dir = 'font2' | |
chars1 = 441 | |
chars2 = 256 | |
def row (i, path, y): | |
return f'<td><img src="{path}/{i:03}.png"></img></td>' if y else '<td></td>' | |
def template(): | |
N = 16 | |
nrows = max (chars1, chars2) | |
d,m = divmod(nrows, N) | |
ntables = d + 1 if m > 0 else 0 | |
table_sizes = [N] * d + [m] | |
tables = [] | |
for x in range(ntables): | |
tr = table_sizes[x] | |
rows1 = [row(i+x*N, font1dir, i+x*N<chars1) for i in range(tr)] | |
rows2 = [row(i+x*N, font2dir, i+x*N<chars2) for i in range(tr)] | |
rows = [f'<tr><td>{n+x*N}</td>{a+b}</tr>' for a,b,n in zip(rows1, rows2, | |
range(N))] | |
t = ''.join(rows) | |
tables.append(f'''<table> | |
<tr><th>#</th><th>big</th><th>lil</th></tr> | |
{t} | |
</table>''') | |
return f''' | |
<html> | |
<head> | |
<title>chocobo no fushigi na dungeon font table</title> | |
<style type="text/css"> | |
body {{ | |
background-color: black; | |
color: white; | |
font-size: 12px; | |
font-family: mono; | |
}} | |
table {{ | |
margin-left:auto; | |
margin-right:auto; | |
float:left; | |
padding-right: 48px; | |
padding-bottom: 16px; | |
font-size: 12px; | |
font-family: mono; | |
}} | |
td {{ | |
text-align: center; | |
font-size: 12px; | |
font-family: mono; | |
}} | |
</style> | |
</head> | |
<body> | |
<h1>chocobo no fushigi na dungeon font tables !!!!</h1> | |
{''.join(tables)} | |
</body> | |
</html> | |
''' | |
with open('index.html', 'w') as f: | |
f.write(template()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
width = 1 | |
chars = {} | |
with open(sys.argv[1], 'rb') as f: | |
data = f.read() | |
l = len(data) | |
print ('length: ', l, l/2, l/3, l/4) | |
for c in data: | |
if c in chars: | |
chars[c] += 1 | |
else: | |
chars[c] = 1 | |
char_keys = chars.keys() | |
sorted_chars = sorted(char_keys, key=lambda x: -chars[x]) | |
for x in sorted_chars: | |
p = chars[x]/l | |
print (f'{x}\t= {chars[x]}\t({p:.4f}%)') | |
print ('there r this many chars total: ', len(char_keys)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
def gen_row(page: int, offset: int, num: int) -> bytes: | |
assert 1 <= page <= 3 | |
a = ord(str(page)[0]) | |
b, c = divmod(offset, 0x10) | |
b = ord(hex(b)[-1]) | |
c = ord(hex(c)[-1]) | |
chars = [] | |
for i in range(num): | |
chars.append(page) | |
chars.append(offset+i) | |
return bytes([0x4, 0x1, a, b, c, 0xf, 0x4, 0x0] + chars + [0xd, 0xa]) | |
rows = [] | |
for page in range(1,4): | |
rows += [gen_row(page, b*8, 8) for b in range(256//8)] | |
data = b''.join(rows) + b'\x00' | |
#print (data) | |
with open('out.bin', 'wb') as f: | |
f.write(data) | |
def mk(p, n): | |
a, b = divmod(n*8, 0x10) | |
a = hex(a)[-1] | |
b = hex(b)[-1] | |
return f'{p}{a}{b}' | |
page1 = [mk(1, x) for x in range(256//8)] | |
page2 = [mk(2, x) for x in range(256//8)] | |
page3 = [mk(3, x) for x in range(256//8)] | |
tablerows = [f'<tr><td><img src="screenshots/{a}.PNG" /></td><td><img src="screenshots/{b}.PNG" /></td><td><img src="screenshots/{c}.PNG" /></td></tr>' for a,b,c in zip(page1, page2,page3)] | |
trows = ''.join(tablerows) | |
html = f''' | |
<html> | |
<head><title>chocobo no fushigi na dungeon kanji screenshots</title> | |
<style> | |
body{{background-color:black;}}</style> | |
<body> | |
<table> | |
{trows} | |
</table> | |
</body> | |
</html> | |
''' | |
with open('index.html', 'w') as f: | |
f.write(html) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
typedef struct clut_entry_t { | |
int stp; /* transparency control bit */ | |
float r; /* red */ | |
float g; /* green */ | |
float b; /* blue */ | |
} clut_entry_t; | |
clut_entry_t *read_clt_file (char *path, int *n_entries) { | |
FILE *fp; | |
// uint32_t id; | |
// uint32_t flag; | |
// uint32_t bnum; | |
// uint16_t dx, dy; | |
// uint16_t w, h; | |
clut_entry_t *entries; | |
fp = fopen (path, "r"); | |
/* read the clt header */ | |
// fread (&id, 4, 1, fp); | |
// fread (&flag, 4, 1, fp); | |
// fread (&bnum, 4, 1, fp); | |
// fread (&dx, 2, 1, fp); | |
// fread (&dy, 2, 1, fp); | |
// fread (&w, 2, 1, fp); | |
// fread (&h, 2, 1, fp); | |
/* read all the clut entries */ | |
//n_entries = (bnum - 12) / 2; | |
*n_entries = 2048; | |
entries = (clut_entry_t *) malloc (*n_entries * sizeof (clut_entry_t)); | |
for (int i = 0; i < *n_entries; i++) { | |
uint16_t clut; | |
int r, g, b; | |
/* read a clut entry */ | |
clut_entry_t *entry = &entries[i]; | |
fread (&clut, 2, 1, fp); | |
r = (clut >> 0) & 0x1f; | |
g = (clut >> 5) & 0x1f; | |
b = (clut >> 10) & 0x1f; | |
entry->stp = clut & (1 << 15); | |
entry->r = r / 31.; | |
entry->g = g / 31.; | |
entry->b = b / 31.; | |
} | |
fclose (fp); | |
return entries; | |
} | |
int *read_pxl_file (char *path, int *width, int *height) { | |
FILE *fp; | |
// uint32_t id; | |
// uint32_t flag; | |
// uint32_t bnum; | |
// uint16_t dx, dy; | |
// uint16_t w, h; | |
int *buffer; | |
fp = fopen (path, "r"); | |
/* read the clt header */ | |
// fread (&id, 4, 1, fp); | |
// fread (&flag, 4, 1, fp); | |
// fread (&bnum, 4, 1, fp); | |
// fread (&dx, 2, 1, fp); | |
// fread (&dy, 2, 1, fp); | |
// fread (&w, 2, 1, fp); | |
// fread (&h, 2, 1, fp); | |
/* read all the clut entries */ | |
*width = 256;//*2; | |
*height = 512*8*8; | |
buffer = (int *) malloc (*width * *height * sizeof (int)); | |
for (int i = 0; i < *width * *height; i += 4) { | |
uint16_t word; | |
int pix0, pix1, pix2, pix3; | |
/* read a word */ | |
fread (&word, 2, 1, fp); | |
pix0 = (word >> 0) & 0xf; | |
pix1 = (word >> 4) & 0xf; | |
pix2 = (word >> 8) & 0xf; | |
pix3 = (word >> 12) & 0xf; | |
buffer[i + 0] = pix0; | |
buffer[i + 1] = pix1; | |
buffer[i + 2] = pix2; | |
buffer[i + 3] = pix3; | |
} | |
fclose (fp); | |
return buffer; | |
} | |
int main (int argc, char **argv) { | |
/* image data */ | |
int width, height; | |
int *image; /* indexed format */ | |
uint8_t *buffer; /* rgba format */ | |
int n_pal; | |
clut_entry_t *palette; | |
/* input files */ | |
char *pxl_path; | |
char *clt_path; | |
/* output file */ | |
char *png_path; | |
/* make sure all the args are specified */ | |
if (argc != 4) { | |
fprintf (stderr, "usage: %s [input.pxl] [input.clt] [output.png]\n", | |
argv[0]); | |
return EXIT_FAILURE; | |
} | |
/* read the args */ | |
pxl_path = argv[1]; | |
clt_path = argv[2]; | |
png_path = argv[3]; | |
/* read the palette data */ | |
palette = read_clt_file (clt_path, &n_pal); | |
/* read the image data */ | |
image = read_pxl_file (pxl_path, &width, &height); | |
/* convert to png */ | |
buffer = (uint8_t *) malloc (width * height * 4); | |
for (int i = 0; i < width * height * 4; i += 4) { | |
int transparent; | |
int index = image[i/4]; | |
clut_entry_t entry = palette[index]; | |
transparent = entry.r == entry.g == entry.b == entry.stp == 0; | |
buffer[i + 0] = (uint8_t) (entry.r * 255); | |
buffer[i + 1] = (uint8_t) (entry.g * 255); | |
buffer[i + 2] = (uint8_t) (entry.b * 255); | |
buffer[i + 3] = 255;//transparent ? 0 : 255; | |
} | |
/* write the png file */ | |
if (stbi_write_png (png_path, | |
width, height, | |
/* rgba */ 4, | |
buffer, | |
/* stride */ width * 4) == 0) { | |
fprintf (stderr, "error writing png file\n"); | |
return EXIT_FAILURE; | |
} | |
/* also write out the index file */ | |
FILE *fp = fopen ("out.index", "w"); | |
fwrite (image, sizeof (int), width * height, fp); | |
fclose (fp); | |
/* cleanup */ | |
free (palette); | |
free (image); | |
free (buffer); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import struct | |
fmt = 'B' | |
#fmt = 'H' | |
print (f'using fmt="{fmt}"') | |
print (f'reading from {sys.argv[1]}') | |
print (f'writing to {sys.argv[2]}') | |
with open(sys.argv[1], "r") as f: | |
s = f.read().split() | |
s = list(filter(lambda c: c!='?', s)) | |
i = list(map(int, s)) | |
with open(sys.argv[2], "wb") as f2: | |
f2.write(struct.pack('<'+fmt*len(i), *i)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#define WIDTH 256 | |
#define BLOCK_SIZE 16 | |
#define MAX_ENTRIES 4096 | |
typedef struct clut_entry_t { | |
int stp; /* transparency control bit */ | |
float r; /* red */ | |
float g; /* green */ | |
float b; /* blue */ | |
} clut_entry_t; | |
clut_entry_t *read_clt_file (char *path, int *n_entries) { | |
FILE *fp; | |
clut_entry_t *entries; | |
fp = fopen (path, "rb"); | |
/* read all the clut entries */ | |
entries = (clut_entry_t *) malloc (MAX_ENTRIES * sizeof (clut_entry_t)); | |
uint16_t clut; | |
*n_entries = 0; | |
while (fread (&clut, 2, 1, fp) > 0) { | |
int r, g, b; | |
/* read a clut entry */ | |
clut_entry_t *entry = &entries[(*n_entries)++]; | |
r = (clut >> 0) & 0x1f; | |
g = (clut >> 5) & 0x1f; | |
b = (clut >> 10) & 0x1f; | |
entry->stp = (clut >> 15) & 1; | |
entry->r = r / 31.; | |
entry->g = g / 31.; | |
entry->b = b / 31.; | |
} | |
fclose (fp); | |
return entries; | |
} | |
uint32_t lookup (int index, clut_entry_t *palette) { | |
clut_entry_t entry = palette[index]; | |
uint8_t r = entry.r * 255; | |
uint8_t g = entry.g * 255; | |
uint8_t b = entry.b * 255; | |
uint8_t a = (entry.r == 0 && entry.g == 0 && entry.b == 0 && entry.stp == 0) | |
? 0 : 255; | |
uint32_t color = (r << 0) | |
+ (g << 8) | |
+ (b << 16) | |
+ (a << 24); | |
return color; | |
} | |
int main (int argc, char **argv) { | |
/* 32-bit image buffer */ | |
int blocks_per_line = WIDTH / BLOCK_SIZE; | |
int width = WIDTH; | |
int height; | |
uint32_t *buffer; | |
/* palette */ | |
int n_entries; | |
clut_entry_t *palette; | |
/* file paths */ | |
char *clt_path; | |
char *png_path; | |
/* parse arguments */ | |
if (argc != 3) { | |
fprintf (stderr, "usage: %s [input.clt] [output.png]\n", | |
argv[0]); | |
return EXIT_FAILURE; | |
} | |
clt_path = argv[1]; | |
png_path = argv[2]; | |
/* decode the palette */ | |
printf ("reading palette file...\n"); | |
palette = read_clt_file (clt_path, &n_entries); | |
printf ("read %d entries.\n", n_entries); | |
/* allocate buffer */ | |
height = BLOCK_SIZE * n_entries / blocks_per_line; | |
printf ("allocating 32-bit image buffer for %dx%d pixels...\n", | |
width, height); | |
if ((buffer = (uint32_t *) malloc (width * height * sizeof(uint32_t))) | |
== NULL) { | |
fprintf (stderr, "failure to allocate image buffer.\n"); | |
return EXIT_FAILURE; | |
} | |
/* creating palette image */ | |
for (int i = 0; i < n_entries; i++) { | |
int bx = i % blocks_per_line; | |
int by = i / blocks_per_line; | |
int ox = bx * BLOCK_SIZE; | |
int oy = by * BLOCK_SIZE; | |
for (int y = oy; y < oy + BLOCK_SIZE; y++) | |
for (int x = ox; x < ox + BLOCK_SIZE; x++) | |
buffer[x + y * width] = lookup (i, palette); | |
} | |
/* write out image buffers */ | |
printf ("writing 32-bit %dx%d data to \"%s\"...\n", | |
width, height, png_path); | |
stbi_write_png (png_path, width, height, 4, | |
buffer, sizeof (uint32_t) * width); | |
/* cleanup */ | |
printf ("done.\n"); | |
free (palette); | |
free (buffer); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#define STB_IMAGE_IMPLEMENTATION | |
#include "stb_image.h" | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#define BIG_FONT_PATH "big.png" | |
#define SMALL_FONT_PATH "small.png" | |
#define IN_PATH "in.bin" | |
#define OUT_PATH "out.png" | |
#define WIDTH 256 | |
#define HEIGHT (12*4) | |
typedef struct point_t { | |
int x; | |
int y; | |
} point_t; | |
typedef struct font_t { | |
uint32_t *atlas; | |
point_t atlas_size; | |
point_t page_size; | |
point_t char_size; | |
} font_t; | |
point_t get_char_pos (font_t *font, int i_character, int i_page) { | |
int pages_per_line = font->atlas_size.x / font->page_size.x; | |
int chars_per_line = font->page_size.x / font->char_size.x; | |
point_t page_pos; | |
page_pos.x = i_page % pages_per_line * font->page_size.x; | |
page_pos.y = i_page / pages_per_line * font->page_size.y; | |
point_t char_pos; | |
char_pos.x = i_character % chars_per_line * font->char_size.x + page_pos.x; | |
char_pos.y = i_character / chars_per_line * font->char_size.y + page_pos.y; | |
return char_pos; | |
} | |
font_t *load_font (char *atlas_path, | |
int page_width, int page_height, | |
int char_width, int char_height) { | |
font_t *font = (font_t *) malloc (sizeof (font_t)); | |
int comp; | |
font->atlas = (uint32_t *) stbi_load (atlas_path, | |
&font->atlas_size.x, | |
&font->atlas_size.y, | |
&comp, 4); | |
if (font->atlas == NULL) { | |
free (font); | |
return NULL; | |
} | |
font->page_size.x = page_width; | |
font->page_size.y = page_height; | |
font->char_size.x = char_width; | |
font->char_size.y = char_height; | |
return font; | |
} | |
void destroy_font (font_t *font) { | |
free (font->atlas); | |
free (font); | |
} | |
void blit (uint32_t *source, point_t source_pos, int source_width, | |
uint32_t *dest, point_t dest_pos, int dest_width, | |
int width, int height) { | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
int sx = source_pos.x + x; | |
int sy = source_pos.y + y; | |
int dx = dest_pos.x + x; | |
int dy = dest_pos.y + y; | |
int si = sx + sy * source_width; | |
int di = dx + dy * dest_width; | |
dest[di] = source[si]; | |
} | |
} | |
} | |
int main (int argc, char **argv) { | |
/* load the fonts */ | |
font_t *big_font = load_font (BIG_FONT_PATH, 256, 252, 12, 12); | |
if (big_font == NULL) { | |
fprintf (stderr, "failed to load font \"%s\".\n", BIG_FONT_PATH); | |
return EXIT_FAILURE; | |
} | |
font_t *small_font = load_font (BIG_FONT_PATH, 256, 64, 8, 8); | |
if (small_font == NULL) { | |
fprintf (stderr, "failed to load font \"%s\".\n", SMALL_FONT_PATH); | |
return EXIT_FAILURE; | |
} | |
font_t *font = big_font; | |
/* allocate image */ | |
uint32_t *buffer = (uint32_t *) malloc (sizeof (uint32_t) * WIDTH * HEIGHT); | |
memset (buffer, 0, sizeof (uint32_t) * WIDTH * HEIGHT); | |
/* process input file */ | |
FILE *fp = fopen (IN_PATH, "rb"); | |
if (fp == NULL) { | |
fprintf (stderr, "failed to open input file \"%s\".\n", IN_PATH); | |
return EXIT_FAILURE; | |
} | |
int chars_per_line = WIDTH / font->char_size.x; | |
uint8_t byte; | |
unsigned int c; | |
int color = 0; | |
point_t cursor; | |
cursor.x = cursor.y = 0; | |
point_t source_pos; | |
while (fread (&byte, 1, 1, fp)) { | |
point_t dest_pos; | |
dest_pos.x = cursor.x * font->char_size.x; | |
dest_pos.y = cursor.y * font->char_size.y; | |
switch (byte) { | |
case 0x0: | |
goto end; | |
case 0x1: | |
fread (&byte, 1, 1, fp); | |
c = byte + 0x100 - 16; | |
goto print; | |
case 0x2: | |
fread (&byte, 1, 1, fp); | |
c = byte + 0x200 - 16; | |
goto print; | |
case 0x3: | |
fread (&byte, 1, 1, fp); | |
c = byte + 0x300 - 16; | |
goto print; | |
case 0x4: | |
fread (&color, 1, 1, fp); | |
break; | |
case 0x5: | |
case 0x6: | |
case 0x7: | |
case 0x8: | |
case 0x9: | |
break; | |
case 0xa: | |
cursor.x = 0; | |
cursor.y++; | |
break; | |
case 0xb: | |
case 0xc: | |
case 0xd: | |
case 0xe: | |
break; | |
case 0xf: | |
goto move; | |
default: { | |
c = byte - 16; | |
print: | |
source_pos = get_char_pos (font, c, color); | |
blit (font->atlas, source_pos, font->atlas_size.x, | |
buffer, dest_pos, WIDTH, | |
font->char_size.x, font->char_size.y); | |
move: | |
cursor.x++; | |
if (cursor.x >= chars_per_line) { | |
cursor.x = 0; | |
cursor.y++; | |
} | |
} | |
} | |
} | |
end: | |
fclose (fp); | |
/* write out image */ | |
if (stbi_write_png (OUT_PATH, WIDTH, HEIGHT, 4, buffer, 4 * WIDTH) == 0) { | |
fprintf (stderr, "error writing to \"%s\".\n", OUT_PATH); | |
return EXIT_FAILURE; | |
} | |
/* cleanup */ | |
free (buffer); | |
destroy_font (big_font); | |
destroy_font (small_font); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
with open(sys.argv[1], 'rb') as f: | |
source = f.read() | |
with open(sys.argv[2], 'wb') as f2: | |
f2.write(bytes((b - a)%256 for a,b in zip(source[:-1], source[1:]))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <math.h> | |
#define STB_IMAGE_IMPLEMENTATION | |
#include "stb_image.h" | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
/* font dimensions */ | |
#define CHAR_WIDTH 8 | |
#define CHAR_HEIGHT 8 | |
/* output image dimensions */ | |
#define OUT_WIDTH 512 | |
void blit (uint8_t *source, int sx, int sy, int sw, | |
uint8_t *dest, int dx, int dy, int dw, | |
int width, int height) { | |
for (int y = 0; y < height; y++) { | |
for (int x = 0; x < width; x++) { | |
int _sx = sx + x; | |
int _sy = sy + y; | |
int _dx = dx + x; | |
int _dy = dy + y; | |
int si = _sx + _sy * sw; | |
int di = _dx + _dy * dw; | |
dest[di * 4 + 0] = source[si * 4 + 0]; | |
dest[di * 4 + 1] = source[si * 4 + 1]; | |
dest[di * 4 + 2] = source[si * 4 + 2]; | |
dest[di * 4 + 3] = source[si * 4 + 3]; | |
} | |
} | |
} | |
int font_w, font_h; | |
int main (int argc, char **argv) { | |
if (argc != 3) { | |
fprintf (stderr, "usage: render [font.png] [input.bin]\n"); | |
exit(1); | |
} | |
char *font_path = argv[1]; | |
char *in_path = argv[2]; | |
/* read in all the text to render...... */ | |
uint8_t s[256 * 256 * 64]; | |
puts ("reading input..."); | |
FILE *fp = fopen (in_path, "rb"); | |
uint8_t c; | |
int len = 0; | |
int MAX = 256*256; | |
while (fread (&c, 1, 1, fp) > 0 && len < MAX) | |
s[len++] = c; | |
fclose (fp); | |
puts ("ok."); | |
printf ("read %d chars.\n", len); | |
printf ("reading font from %s...\n", font_path); | |
/* read the font file */ | |
int n; | |
uint8_t *font = stbi_load (font_path, &font_w, &font_h, &n, 4); | |
if (font == NULL) { | |
fprintf (stderr, "couldnt open font.png\n"); | |
return EXIT_FAILURE; | |
} | |
puts ("ok."); | |
/* render image */ | |
int width = OUT_WIDTH; | |
int height = (int) ceil ((float) len / width * CHAR_WIDTH) * CHAR_HEIGHT; | |
int size = width * height * 4; | |
printf ("allocating image of size %d x %d...\n", width, height); | |
uint8_t *buffer = (uint8_t *) malloc (size + 10); | |
if(buffer==NULL){ | |
fprintf (stderr, "dude FAILED to allocate buffer\n"); | |
exit(1); | |
} | |
puts ("ok."); | |
int chars_line = (int) (width / CHAR_WIDTH); | |
int chars_line_font = (int) (font_w / CHAR_WIDTH); | |
printf ("characters per line = %d\n", chars_line); | |
puts ("rendering...\n"); | |
int SIZE = 1; | |
for (int i = 0; i < len; i += SIZE) { | |
int c = 0; | |
for (int j = 0; j < SIZE; j++) { | |
uint8_t byte = s[i+j]; | |
c+=byte*pow(256, j); | |
} | |
int dx = (i/SIZE) % chars_line * CHAR_WIDTH; | |
int dy = (i/SIZE) / chars_line * CHAR_HEIGHT; | |
int sx = c % chars_line_font * CHAR_WIDTH; | |
int sy = c / chars_line_font * CHAR_HEIGHT + 256; | |
if (sy > font_h - CHAR_HEIGHT) | |
{ | |
printf ("WARNING sy=%d; skiipng\n", sy); | |
} else{ | |
blit (font, sx, sy, font_w, buffer, dx, dy, width, CHAR_WIDTH, CHAR_HEIGHT); | |
} | |
} | |
puts ("ok."); | |
puts ("writing to out.png..."); | |
/* write the png file out */ | |
if (stbi_write_png ("out.png", | |
width, height, | |
/* rgba */ 4, | |
buffer, | |
/* stride */ width * 4) == 0) { | |
fprintf (stderr, "error writing out.png\n"); | |
return EXIT_FAILURE; | |
} | |
puts ("ok."); | |
puts ("BYE."); | |
stbi_image_free (font); | |
return EXIT_SUCCESS; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
with open(sys.argv[1], 'rb') as f: | |
source = f.read() | |
with open(sys.argv[2], 'rb') as f: | |
search_str = f.read() | |
#test strings lol | |
#source = b'abcdefg12346def187324defp.l,c' | |
#search_str = b'def' | |
print (f'==== {sys.argv[1]} ==== {sys.argv[2]} ====') | |
print(f'searchin for', search_str,f'in {len(source)} bytes') | |
occurences = [] | |
buf = b'' | |
i = 0 # buf num | |
j = 0# char num | |
t = 0# timer for progress | |
totes = len(source) | |
for c in source: | |
if t == 1024*1024*32: | |
t = 0 | |
p = j / totes | |
print (f'...{p:.4f}% ({j} / {totes})') | |
if c == search_str[i]: | |
buf += c | |
i+=1 | |
if i == len(search_str): | |
buf = 0 | |
occurences.append(j-i+1) | |
print (f'found @ pos={j-i+1}') | |
i = 0 | |
else: | |
buf = 0 | |
i = 0 | |
t += 1 | |
j += 1 | |
print (f'found {len(occurences)} occurences') | |
if (len(occurences)>0): | |
print (' DING DING DING DING DING DING DING DING DING DING DING!!!!!!!!!') | |
print ('found here:', occurences) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
#encoding: utf-8 | |
# script to extract the script from chocobo no fushigi na dungeon .bin file | |
# and to inject the script back after changes hav been made !!! | |
import struct | |
import os | |
import sys | |
MSG_BIN_OFFSET = 0x1714c800 | |
MSG_BIN_SIZE = 0x40000 | |
BIN_SIZE = 709332624 | |
CHUNK_DELIMITER = '\n\n\\\n\n' | |
ITEM_DELIMITER = '\n\n' | |
# decode translation table | |
decode_table = 'あいうえおかきくけこさしすせそたヴ!ァィゥ'\ | |
'ェォッ()。+,-./0123456789'\ | |
':ー〜・⋯?「ABCDEFGHIJKLMN'\ | |
'OPQRSTUVWXYZャュョベボ」abc'\ | |
'defghijklmnopqrstuvwx'\ | |
'yzパピプペポちつてとなにぬねのはひふへほ'\ | |
'まみむめもやゆよらりるれろわをんがぎぐげご'\ | |
'ざじずぜぞだぢづでどばびぶべぼぱぴぶぺぽぁ'\ | |
'ぃぅぇぉっゃゅょアイウエオカキクケコサシス'\ | |
'セソタチツテトナニヌネノハヒフヘホマミムメ'\ | |
'モヤユヨラリルレロワヲンガギグゲゴザジズゼ'\ | |
'ゾダヂヅデドバビブ' | |
# encode translation table | |
encode_table_a = '()*+,-./0123456789:—~•…?“ABCDEFGHIJKLMNOPQRSTUVWXYZ' | |
encode_table_b = '”abcdefghijklmnopqrstuvwxyz' | |
encode_table = {'!': 33} | |
for i, c in enumerate(encode_table_a): | |
encode_table[c] = i + 40 | |
for i, c in enumerate(encode_table_b): | |
encode_table[c] = i + 96 | |
# special sequences | |
END_TK = 'end' | |
COLOR_TK = 'color' | |
SPEED_TK = 'speed' | |
DELAY_TK = 'delay' | |
NAME_TK = 'name' | |
EVENT_TK = 'event' | |
WAIT_TK = 'wait' | |
CLOSE_TK = 'close' | |
tk_val = { | |
END_TK: 0x0, | |
COLOR_TK: 0x4, | |
SPEED_TK: 0x5, | |
DELAY_TK: 0x6, | |
NAME_TK: 0xb, | |
EVENT_TK: 0xc, | |
WAIT_TK: 0xd, | |
CLOSE_TK: 0xe, | |
} | |
# colors | |
colors = ['white', 'red', 'green', 'blue', 'yellow', 'gray'] | |
for i, color in enumerate(colors): | |
tk_val[color] = i | |
def token(*args): | |
s =' '.join([f'{x}' for x in args]) | |
return f'<{s}>' | |
def encode_text(text: str) -> bytes: | |
i = 0 | |
out = b'' | |
while i < len(text): | |
c = text[i] | |
if c in decode_table: | |
value = decode_table.index(c) + 16 | |
page = value // 0x100 | |
byte = value % 0x100 | |
if page > 0: | |
out += bytes([page]) | |
out += bytes([byte]) | |
elif c == '\n': | |
out += bytes([0xa]) | |
elif c == ' ': | |
out += bytes([0xf]) | |
elif c == '<': | |
buf = '' | |
i += 1 | |
while text[i] != '>': | |
buf += text[i] | |
i += 1 | |
args = buf.split() | |
args = [tk_val[arg] if arg in tk_val else int(arg) for arg in args] | |
out += bytes(args) | |
elif c in encode_table: | |
out += bytes([encode_table[c]]) | |
else: | |
raise Exception(f'cannot encode char "{c}"') | |
i += 1 | |
return out | |
def decode_text(text: bytes) -> str: | |
i = 0 | |
out = '' | |
def dec_char (c): | |
i = c - 16 | |
if i < len(decode_table): | |
return decode_table[i] | |
else: | |
page = c // 0x100 | |
byte = c % 0x100 | |
if page == 0: | |
return token(byte) | |
else: | |
return token(page, byte) | |
while i < len(text): | |
c = int(text[i]) | |
if c == 0x0: | |
out += token(END_TK) | |
elif c == 0x1: | |
out += dec_char(text[i + 1] + 0x100) | |
i += 1 | |
elif c == 0x2: | |
out += dec_char(text[i + 1] + 0x200) | |
i += 1 | |
elif c == 0x3: | |
out += dec_char(text[i + 1] + 0x300) | |
i += 1 | |
elif c == 0x4: | |
out += token(COLOR_TK, colors[int(text[i + 1])]) | |
i += 1 | |
elif c == 0x5: | |
out += token(SPEED_TK, int(text[i + 1])) | |
i += 1 | |
elif c == 0x6: | |
out += token(DELAY_TK, int(text[i + 1])) | |
i += 1 | |
elif c == 0x7: | |
out += token(c, int(text[i + 1])) | |
i += 1 | |
elif c == 0xa: | |
out += '\n' | |
elif c == 0xb: | |
out += token(NAME_TK) | |
elif c == 0xc: | |
out += token(EVENT_TK) | |
elif c == 0xd: | |
out += token(WAIT_TK) | |
elif c == 0xe: | |
out += token(CLOSE_TK) | |
elif c == 0xf: | |
out += ' ' | |
else: | |
if c < 16: | |
out += token(c) | |
else: | |
out += dec_char(c) | |
i += 1 | |
return out | |
def do_encode(bin_path: str, script_path: str): | |
assert os.path.getsize(bin_path) == BIN_SIZE | |
# first read in the script file | |
with open(script_path, 'rb') as f: | |
script = f.read().decode('utf8').strip() | |
# split out the chunks | |
chunks_str = script.split(CHUNK_DELIMITER) | |
# split out the text items | |
for i, chunk_str in enumerate(chunks_str): | |
chunks_str[i] = chunk_str.split(ITEM_DELIMITER) | |
# encode each chunk | |
chunks = [[encode_text(item) for item in chunk] for chunk in chunks_str] | |
# format each chunk with offsets and stuff | |
chunk_datas = [] | |
for chunk in chunks: | |
num_items = len(chunk) | |
offset = num_items * 2 | |
offsets = [offset] | |
for item in chunk[:-1]: | |
offset += len(item) | |
offsets.append(offset) | |
assert len(offsets) == num_items | |
offsets_bytes = struct.pack(f'<{"H"*num_items}', *offsets) | |
chunk_data = offsets_bytes + b''.join(chunk) | |
padding = 0x8000 - len(chunk_data) | |
chunk_data += b'\0' * padding | |
chunk_datas.append(chunk_data) | |
data = b''.join(chunk_datas) | |
# write out to msg.bin file in the bin | |
assert len(data) == MSG_BIN_SIZE | |
with open(bin_path, 'r+b') as f: | |
# we gotta deal with the sector offsets so.... | |
# lets break the data into sectors! | |
num_sectors = MSG_BIN_SIZE // 0x800 | |
starts = [i * 0x800 for i in range(num_sectors)] | |
sectors = [data[o:o+0x800] for o in starts] | |
# now figure out the actual in file offsets for each sector | |
sector = MSG_BIN_OFFSET // 0x800 | |
offset = sector * 0x930 + 0x18 | |
# write all the sectors | |
for s in sectors: | |
f.seek(offset) | |
f.write(s) | |
offset += 0x930 | |
def do_decode(bin_path: str, script_path: str): | |
assert os.path.getsize(bin_path) == BIN_SIZE | |
# first read in the msg file from the bin file | |
# that means we gotta extract the msg file from the bin file | |
# stripping the extra meta data in the bin file | |
# (sector data or something?) | |
with open(bin_path, 'rb') as f: | |
# so uh, first read in the sectors relevant here | |
sector = MSG_BIN_OFFSET // 0x800 | |
sector_offset = sector * 0x930 | |
num_sectors = MSG_BIN_SIZE // 0x800 | |
sectors_size = num_sectors * 0x930 | |
f.seek(sector_offset) | |
sector_data = f.read(sectors_size) | |
# now strip the meta data from the sectors | |
starts = [i * 0x930 for i in range(num_sectors)] | |
sectors = [sector_data[o+0x18:o+0x818] for o in starts] | |
data = b''.join(sectors) | |
assert len(data) == MSG_BIN_SIZE | |
with open('msg.bin', 'wb') as g: | |
g.write(data) | |
# split it into 0x8000 chunks | |
chunks = [data[i:i+0x8000] for i in range(0, len(data), 0x8000)] | |
# decode each chunk | |
chunks_str = [] | |
for chunk in chunks: | |
# strip off the trailing null bytes | |
while chunk[-1] == 0: | |
chunk = chunk[:-1] | |
# figure out how many text items there are in this chunk | |
# this is implied by the offset to the first item | |
# which immediately follows the 16bit offset array | |
first_offset = struct.unpack('<H', chunk[:2])[0] | |
num_items = first_offset // 2 | |
# read all of the offsets | |
offsets = list(struct.unpack(f'<{"H"*num_items}', chunk[:first_offset])) | |
# get the ending offsets | |
end_offsets = offsets[1:] + [len(chunk)] | |
# collect all the text items | |
items = [decode_text(chunk[start:end]) for start, end in zip(offsets, end_offsets)] | |
# accumulate | |
chunks_str.append(items) | |
# write to output file | |
out = CHUNK_DELIMITER.join([ITEM_DELIMITER.join(items) for items in chunks_str]) | |
with open(script_path, 'wb') as f: | |
f.write(out.encode('utf8')) | |
if __name__ == '__main__': | |
if len(sys.argv) != 4: | |
print(f'usage: {sys.argv[0]} [encode|decode] [game.bin] [script.txt]') | |
exit(1) | |
if sys.argv[1] == 'encode': | |
do_encode(sys.argv[2], sys.argv[3]) | |
elif sys.argv[1] == 'decode': | |
do_decode(sys.argv[2], sys.argv[3]) | |
else: | |
print('first argument must be "encode" or "decode"') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment