// System#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>// STL#include <string>#include <map>// C#include <cassert>#include <errno.h>#if 1// GLUT#include <GLUT/glut.h>// OpenGL#include <OpenGL/OpenGL.h>#include <OpenGL/gl.h>#include <OpenGL/glu.h>#else// GLUT#include <glut/glut.h>// OpenGL#include <gl/gl.h>#include <gl/glu.h>#endifusing namespace std;typedef unsigned char u8;typedef unsigned short int u16;typedef unsigned long int u32;typedef signed char s8;typedef signed short int s16;typedef signed long int s32;// - utility functions --------------------------------------------------------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);}#ifndef O_BINARY#define O_BINARY 0#endifint load( const string & name, void ** data ){ size_t size = 0; *data = NULL; int fd = open( name.c_str(), O_RDONLY|O_BINARY, 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 ); } else { printf("%i\n", errno); } return size;}void save(const std::string & name, const void *data, int size){ int fd = open( name.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0666 ); if (fd >= 0) { write( fd, data, size ); close( fd ); }}int load_lzs(const string & name, void ** data ){ // read compressed data u8 *buf; int tsize = load( name, (void**)&buf ); if (buf == NULL) { *data = NULL; return 0; } int isize = get_u32le(buf) + 4; if (isize != tsize) { free(buf); *data = NULL; return 0; } // decompress; int osize = (isize + 255) & ~255; u8 * obuf = (u8 *)malloc(osize); int iofs = 4, oofs = 0; u8 cmd=0, bit=0; while (iofs < isize) { if (bit == 0) { cmd = buf[iofs++]; bit = 8; } if (cmd&1) { obuf[oofs++]=buf[iofs++]; if (oofs==osize) { osize+=256; obuf = (u8*)realloc(obuf, osize); } } else { u8 a = buf[iofs++]; u8 b = buf[iofs++]; u16 o = a | ((b&0xF0)<<4); u8 len = (b&0xF)+3; int rofs = oofs - ((oofs - 18 - o) & 0xFFF); for (int j=0; j<len; j++) { if (rofs < 0) { obuf[oofs++]=0; } else { obuf[oofs++]=obuf[rofs]; } if (oofs==osize) { osize+=256; obuf = (u8*)realloc(obuf, osize); } rofs++; } } cmd>>=1; bit--; } free( buf ); *data = obuf; return oofs;}// - field class --------------------------------------------------------------class CFieldBackground {private: struct TexInfo { int page, pal; bool hc; bool operator<(const TexInfo & rhs) { return memcmp(this, &rhs, sizeof(TexInfo)) < 0; } }; map<TexInfo, int> texInfoMap; u8 * mimData; int mimSize; u8 * datData; int datSize; u8 * bsxData; int bsxSize; struct Texture { u8 * rgba; // data int id; // OpenGL texture ID }; struct Tile { int u, v, pal; // info from the request, pal=-1 for RGBA int s, t; // texture position in OpenGL texture int texture; // Texture }; int getTileI8(int u, int v, int pal); int getTileRGBA(int u, int v); int getTexture(u8 atr1, u8 atr2, u8 x);public: CFieldBackground(); ~CFieldBackground(); void load(const std::string & name); void draw();};CFieldBackground::CFieldBackground(): mimData(NULL), mimSize(0), datData(NULL), datSize(0), bsxData(NULL), bsxSize(0){}CFieldBackground::~CFieldBackground(){}voidCFieldBackground::load(const std::string & name){ // read compressed data string baseName = name.substr(0, name.find('.')); // MIM string mimName = baseName + ".MIM"; mimData = NULL; mimSize = load_lzs( mimName, (void **)&mimData ); // DAT string datName = baseName + ".DAT"; datData = NULL; datSize = load_lzs( datName, (void **)&datData ); save(datName + ".bin", datData, datSize); // BSX string bsxName = baseName + ".BSX"; bsxData = NULL; bsxSize = load_lzs( bsxName, (void **)&bsxData ); save(bsxName + ".bin", bsxData, bsxSize);}int CFieldBackground::getTexture(u8 atr1, u8 atr2, u8 x){ TexInfo texInfo; texInfo.page = (atr1 >> 4); // * 128 int px = texInfo.page * 64 + x; texInfo.pal = px < 512 ? px / 256 : ((px - 512) / 128) + 2; texInfo.hc = false; // atr2 & 1; if (texInfoMap.find(texInfo) != texInfoMap.end()) { return texInfoMap[texInfo]; } printf("%2.2x %2.2x\n", atr1, atr2); int ofs = get_u32le(mimData); int step = get_u32le(mimData+ofs); int npal = get_u16le(mimData+10); int pal_ofs = 12; int pic_ofs = ofs+12; int xsize = get_u16le(mimData+ofs+8)*2; int ysize = get_u16le(mimData+ofs+10); u8 *texture = new u8[256*256*4]; if (texInfo.hc) { int page = texInfo.page * 128; for (int y=0; y<256; y++) { for (int x=0; x<256; x++) { u16 col = get_u16le(mimData + (y*xsize+x*2+page) + pic_ofs); int r = (((col ) & 31) * 255 + 15) / 31; int g = (((col >> 5) & 31) * 255 + 15) / 31; int b = (((col >> 10) & 31) * 255 + 15) / 31; int a = (col & 0x8000) || (col == 0) ? 0 : 255; int addr = (y*256+x) * 4; texture[addr+0] = r; texture[addr+1] = g; texture[addr+2] = b; texture[addr+3] = a; } } } else { int page = texInfo.page * 64; int pal = texInfo.pal * 512; for (int y=0; y<256; y++) { for (int x=0; x<256; x++) { u8 idx = mimData[(y*xsize+x+page) + pic_ofs]; u16 col = get_u16le(mimData + idx*2 + pal_ofs + pal); int r = (((col ) & 31) * 255 + 15) / 31; int g = (((col >> 5) & 31) * 255 + 15) / 31; int b = (((col >> 10) & 31) * 255 + 15) / 31; int a = (col & 0x8000) || (col == 0) ? 0 : 255; int addr = (y*256+x) * 4; texture[addr+0] = r; texture[addr+1] = g; texture[addr+2] = b; texture[addr+3] = a; } } } int textureId; glGenTextures(1, &textureId); glBindTexture( GL_TEXTURE_2D, textureId);#if 0 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );#else glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );#endif glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture); delete texture; texInfoMap[texInfo] = textureId; return textureId;}voidCFieldBackground::draw(){ u32 memaddr[7]; for (int i=0; i<7; i++) { memaddr[i] = get_u32le(datData+i*4); } u32 base = memaddr[0] - 7 * 4; u32 section[7]; for (int i=0; i<7; i++) { section[i] = memaddr[i] - base; } u8 * tilemap = datData + section[2] + get_u32le(datData + section[2]); int count = (get_u32le(datData + section[2] + 4) - get_u32le(datData + section[2])) / 8;#if 1 printf("---- %4.4x\n", count); for (int i=0; i<get_u32le(datData + section[2]); i++) { printf("%2.2x ", (u8*)(datData + section[2])[i]); } printf("\n----\n"); for (int i=0; i<get_u32le(datData + section[2] + 8)-get_u32le(datData + section[2] + 4); i++) { printf("%2.2x ", (u8*)(datData + section[2] + get_u32le(datData + section[2] + 4))[i]); } printf("\n----\n");#endif for (int i=0; i<count; i++) { s16 tx = (s16)get_u16le(tilemap + 8 * i + 0) + 256; s16 ty = (s16)get_u16le(tilemap + 8 * i + 2) + 256; u8 sx = tilemap[8 * i + 4]; u8 sy = tilemap[8 * i + 5]; u8 atr1 = tilemap[8 * i + 6]; u8 atr2 = tilemap[8 * i + 7]; // printf("%2.2x %2.2x|", atr1, atr2); glBindTexture(GL_TEXTURE_2D, getTexture(atr1, atr2, sx)); glBegin(GL_QUADS); glTexCoord2i(sx, sy); glVertex2i(tx, ty); glTexCoord2i(sx+15, sy); glVertex2i(tx+16, ty); glTexCoord2i(sx+15, sy+15); glVertex2i(tx+16, ty+16); glTexCoord2i(sx, sy+15); glVertex2i(tx, ty+16); glEnd(); } //printf("\n");#if 0 tilemap = datData + section[2] + get_u32le(datData + section[2] + 4); count = get_u16le(tilemap); for (int i=0; i<count; i++) { s16 tx = (s16)get_u16le(tilemap + 14 * i + 0 + 2) + 512; s16 ty = (s16)get_u16le(tilemap + 14 * i + 2 + 2) + 256; u8 sx = tilemap[14 * i + 4 + 2]; u8 sy = tilemap[14 * i + 5 + 2]; u8 atr1 = tilemap[14 * i + 6 + 2]; u8 atr2 = tilemap[14 * i + 7 + 2]; // printf("%2.2x %2.2x\n", atr1, atr2); glBindTexture(GL_TEXTURE_2D, getTexture(atr1, atr2, sx)); glBegin(GL_QUADS); glTexCoord2i(sx, sy); glVertex2i(tx, ty); glTexCoord2i(sx+15, sy); glVertex2i(tx+16, ty); glTexCoord2i(sx+15, sy+15); glVertex2i(tx+16, ty+16); glTexCoord2i(sx, sy+15); glVertex2i(tx, ty+16); glEnd(); }#endif}CFieldBackground g_FieldBackground;// - OpenGL stuff --------------------------------------------------------------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){ // render glClearColor(0, 0, 0, 1.00); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); g_FieldBackground.draw(); glFlush();}void SpecialHandler(int key, int x, int y){#if 0 switch (key) { case GLUT_KEY_UP: rot_x -= 4; if (rot_x < -64) { rot_x = -64; } break; case GLUT_KEY_DOWN: rot_x += 4; if (rot_x > 64) { rot_x = 64; } break; case GLUT_KEY_LEFT: rot_y -= 5; break; case GLUT_KEY_RIGHT: rot_y += 5; break; } glutPostRedisplay();#endif}void KeyboardHandler(unsigned char key, int x, int y){ switch (key) { case 27: exit(0); break; }}int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "fieldview <field.dat>\n"); } else { // get current directory char cwd[1024]; getcwd(cwd, sizeof(cwd)); // init opengl and glut 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); // Setup OpenGL glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(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 /*1.0f/255.0f*/); glDisable(GL_LINE_SMOOTH); glShadeModel(GL_SMOOTH); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(1.0f/256.0f, 1.0f/256.0f, 1); glTranslatef(0.5f, 0.5f, 0.0f); // Setup projection matrices glViewport(0, 0, 640, 480); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0, 640, 480, 0.0, 0.0, 1.0); // if the filename is not absolute try to add the current work directory. string path; if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] != 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') { path = string(cwd) + "/"; } // load the background data g_FieldBackground.load(path + argv[1]); // main (this will never return) glutMainLoop(); } return 0;}