// GLUT#include <GLUT/glut.h>// OpenGL#include <OpenGL/gl.h>#include <OpenGL/glu.h>// System#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>// STL#include <string>// ZLib#include <zlib.h>using namespace std;typedef unsigned char u8;typedef unsigned short u16;typedef unsigned int u32;const char * ff7Path = "<path to your ff7 directory>";// This is a table that contains 16-bit unicode codes for all chars in the FF7 font. (US/NTSC Version)const u16 charMatrix[] = { 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x00c4, 0x00c1, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1, 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8, 0x00ea, 0x00eb, 0x00ed, 0x0069, 0x00ec, 0x00ef, 0x00f1, 0x00f3, 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc, 0x0000, 0x00b0, 0x00a2, 0x00a3, 0x0000, 0x0000, 0x0000, 0x00df, 0x0000, 0x0000, 0x0000, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8, 0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x03a3, 0x03a0, 0x03c0, 0x2321, 0x00aa, 0x00ba, 0x03a9, 0x00e6, 0x00f8, 0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x0394, 0x00ab, 0x00bb, 0x2026, 0x0000, 0x0041, 0x0041, 0x004f, 0x0152, 0x0153, 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x2662, 0x00ff, 0x0178, 0x2044, 0x0000, 0x2039, 0x203a, 0x1278, 0x1279, 0x275a, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c5, 0x00ca, 0x0041, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049, 0x004f, 0x004f, 0x0000, 0x004f, 0x0055, 0x0055, 0x0055, 0x007c, 0x02c6, 0x02dc, 0x02c9, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7};u8 * ucodeToChar;void * kernelBinData;void * windowBinData;GLuint fontTextures[8];u16 get_u16le(void const * const buf){ return ((u8*)buf)[0] | (((u8*)buf)[1]<<8);}u32 get_u32le(void const * const buf){ return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16) | (((u8*)buf)[3]<<24);}int load(const string & name, void ** data){ size_t size = 0; *data = NULL; int fd = open(name.c_str(), O_RDONLY, 0); if (fd >= 0) { struct stat sb; if (fstat(fd, &sb) >= 0) { assert(sb.st_size > 0); void *tmp = malloc(sb.st_size); if (tmp!=NULL) { if (read(fd, tmp, sb.st_size) == sb.st_size) { *data = tmp; size = sb.st_size; } else { free(tmp); } } } close(fd); } return size;}intload_bingzip(const string & fileName, void ** buf){ // load library u8 * buffer = NULL; int size = load(fileName, (void**)&buffer); // calc overall decompressed size and number of blocks int offset = 0; int output_size = 0; int output_count = 0; while (offset < size) { int comp_size = get_u16le(buffer + offset + 0); int uncomp_size = get_u16le(buffer + offset + 2); offset += 6; offset += comp_size; output_size += uncomp_size; output_count ++; } // allocate enough memory for output buffer int bufsize = output_size + output_count * sizeof(u32); u32 * table = (u32*)malloc(bufsize); // decompress all blocks with zlib z_stream s; memset(&s, 0, sizeof(z_stream)); s.next_out = (Bytef *)(table + output_count); s.avail_out = output_size; s.total_out = 0; offset = 0; int count = 0; int out_offset = output_count * sizeof(u32); while (offset < size) { table[count++] = out_offset; int comp_size = get_u16le(buffer + offset + 0); int uncomp_size = get_u16le(buffer + offset + 2); int unknown = get_u16le(buffer + offset + 4); offset += 6; s.next_in = buffer + offset; s.avail_in = comp_size; s.total_in = 0; offset += comp_size; out_offset += uncomp_size; // compressed/uncompressed? inflateInit2(&s, 16 | 15); inflate(&s, Z_FINISH); inflateEnd(&s); } free(buffer); *buf = table; return bufsize;}void build_font_textures(){ u32 * table = static_cast<u32*>(windowBinData); u8 * data = static_cast<u8*>(windowBinData); glGenTextures(8, fontTextures); u8 * fontData = data + table[1]; u32 id = get_u32le(fontData + 0); u32 type = get_u32le(fontData + 4); u32 clut_size = get_u16le(fontData + 16); u32 clut_count = get_u16le(fontData + 18); u32 pic_ofs = clut_size * clut_count * 2 + 20; u32 width = get_u16le(fontData + pic_ofs + 8) * 4; u32 height = get_u16le(fontData + pic_ofs + 10); u8 * bitmap = new u8[256 * 256 * 4]; for (unsigned int i=0; i<clut_count; i++) { u8 clut[256 * 4]; for (unsigned int j = 0; j<clut_size; j++) { u16 col = get_u16le(fontData + 20 + (i * clut_size + j) * 2); clut[j * 4 + 0] = (col & 31) * 255 / 31; clut[j * 4 + 1] = ((col >> 5) & 31) * 255 / 31; clut[j * 4 + 2] = ((col >> 10) & 31) * 255 / 31; clut[j * 4 + 3] = (col >> 15) * 255; } for (unsigned int y=0; y<height; y++) { for (unsigned int x=0; x<width; x++) { u8 pixel = fontData[pic_ofs + 12 + y * (width / 2) + x / 2]; int index = x & 1 ? pixel >> 4 : pixel & 15; bitmap[(y * 256 + x) * 4 + 0] = clut[index * 4 + 0]; bitmap[(y * 256 + x) * 4 + 1] = clut[index * 4 + 1]; bitmap[(y * 256 + x) * 4 + 2] = clut[index * 4 + 2]; bitmap[(y * 256 + x) * 4 + 3] = clut[index * 4 + 3]; } } glBindTexture(GL_TEXTURE_2D, fontTextures[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5_A1, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, bitmap); } delete[] bitmap;}unsigned int getKernelStringCount(unsigned int i){ u32 * table = static_cast<u32*>(kernelBinData); u8 * data = static_cast<u8*>(kernelBinData); u8 * base = data + table[i + 9]; return get_u16le(base) / 2;}voidgetKernelString(unsigned int i, unsigned int j, wstring & s){ u32 * table = static_cast<u32*>(kernelBinData); u8 * data = static_cast<u8*>(kernelBinData); u8 * base = data + table[i + 9]; u8 * ptr = base + get_u16le(base + j * 2); if (*ptr != 0xFF) { while (*ptr != 0xFF) { if (*ptr == 0xf9) { // simple string compression, reference an earlier substring ptr++; int dist = ((*ptr) & 0x3F)+2; int count = ((*ptr) >> 6)*2+4; for (int k=0; (k<count) && (*(ptr-dist+k)!=0xFF); k++) { s += charMatrix[*(ptr-dist+k)]; } ptr++; } else if (*ptr == 0xf8) { // unknown escape code.. ptr++; ptr++; } else { s += charMatrix[*ptr]; ptr++; } } }}// build inverse lookup table from unicode to FF7 font indexvoidbuild_ucode_to_char_table(){ ucodeToChar = new u8[65536]; memset(ucodeToChar, 0, 65536); for (unsigned int i=0; i<sizeof(charMatrix)/sizeof(charMatrix[0]); i++) { ucodeToChar[charMatrix[i]] = i; }}void drawString(int colour, int x, int y, const wstring & text){ u32 * table = static_cast<u32*>(windowBinData); u8 * data = static_cast<u8*>(windowBinData); u8 * widthTable = data + table[2]; glBindTexture(GL_TEXTURE_2D, fontTextures[colour]); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glBegin(GL_QUADS); for (wstring::const_iterator i = text.begin(); i != text.end(); i++) { u8 glyph = ucodeToChar[*i]; int gx = (glyph % 21) * 12; int gy = (glyph / 21) * 12; glTexCoord2i(gx, gy); glVertex2i(x, y); glTexCoord2i(gx, gy + 12); glVertex2i(x, y + 12); glTexCoord2i(gx + 12, gy + 12); glVertex2i(x + 12, y + 12); glTexCoord2i(gx + 12, gy); glVertex2i(x + 12, y); x += widthTable[glyph] & 0x0F; } glEnd();}void ReshapeWindowFunc(int width, int height){ glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, width, height, 0.0, 0.0, 1.0);}void MainRenderLoop(void){ glClearColor(0.0f, 0.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawString(0, 8, 8, L"Kernel Strings:"); for (unsigned int i=0; i<getKernelStringCount(10); i++) { wstring text; getKernelString(10, i, text); drawString(i&7, 16, i*12+20, text.c_str()); } glFlush();}void SpecialHandler(int key, int x, int y){}void KeyboardHandler(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}intmain(int argc, char * argv[]){ // glut stuff glutInit(&argc, (char **) argv); glutInitWindowSize(640, 480); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH); glutCreateWindow(argv[0]); glutDisplayFunc(MainRenderLoop); glutIdleFunc(MainRenderLoop); glutReshapeFunc(ReshapeWindowFunc); glutKeyboardFunc(KeyboardHandler); glutSpecialFunc(SpecialHandler); // opengl stuff glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0f); glViewport(0, 0, 640, 480); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(1.0f/256.0f, 1.0f/256.0f, 1.0f); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 640, 480, 0.0, 0.0, 1.0); load_bingzip(string(ff7Path) + "/INIT/KERNEL.BIN", &kernelBinData); load_bingzip(string(ff7Path) + "/INIT/WINDOW.BIN", &windowBinData); build_font_textures(); build_ucode_to_char_table(); glutMainLoop(); delete[] ucodeToChar; return 0;}