(PSX) FF7 battle stage viewer?

  • Thread starter Thread starter Lazy Bastard
  • Start date Start date
Status
Not open for further replies.
L

Lazy Bastard

Guest
Zangan was created for the PC version, but there's no commonly-referred-to app for the PSX version.

I've come across this thread: https://www.ff7catalog.com/threads/1775/

...which contains micky's app for viewing PSX FF7 battle stages, but after considerable effort to get it to compile (which I finally managed after slapping together a myriad of old libs and include files, and editing the source a bit), it dies with a segmentation fault when fed its expected argument (with no argument, it reminds me to provide a file name for the stage I want to load; with the file name specified, it dies). Reviewing the posts in that thread, I'm not sure anyone actually got it to work in Windows (micky had it working in Linux). In case I'm wrong, does anyone have a compiled, working copy of this app? Or, can anyone else manage to compile it into a working program?

Next I stumbled upon this thread: https://www.ff7catalog.com/threads/2447/

...which seems to imply that Cyberman had a semi-working program for viewing PSX FF7 battle stage files. So, would anyone (including Cyberman) happen to have a copy of that? Or, any further documentation than I've found in these two threads?

There's only this very brief description on the wiki: http://wiki.qhimm.com/view/FF7/Battle/Battle_Field

Any help or nudge in the right direction is appreciated. I didn't build micky's app on this machine, but I can grab my modified source and post that, along with gdb output for debugging reference, if anyone wants to look at what the hell is crashing this app (seems to be a screwy array, but I don't see what's broken about it).

Thanks in advance.
 
Grosse Gott.
I shall help you look for it.


*Update* - http://wiki.qhimm.com/view/FF7/Battle/Battle_scenesCode: [Select]
Code:
There are few programs written that will help you edit scene.bin file: Scene Reader  SceneEdit  Scenester  Proud Clod
Spinningcone.com - now that is an interesting name for a company website.


Oh wait, the website is still under construction.
 
Last edited:
Those are for editing battle scenes, not battle stages. I'm aware of those, but they aren't what I'm looking for. Battle stage files contain the actual background image data.

For the PC version, there is Zangan:

Zangan.jpg
 
Yup, I knew it. Sorry about that. Um, maybe I should ask other members of this forum?


Have you tried to edit a scene.bin with Zangan for the Final Fantasy VII for the Playstation? I may have read that the scene.bin may be structured in a way that it may be edited. Or I am just completely wrong.
 
Last edited:
FF7 PSX stage files are in the STAGE1\ and STAGE2\ directories, with file names of the format STAGExx.LZS. SCENE.BIN is not related.

And nope, Zangan doesn't open STAGExx.LZS files, whether they're compressed or decompressed. One reason would be TIM texture data rather than TEX, but I suspect some of the other data is rearranged or encoded differently as well.

Even if I sit down and break a few STAGExx.LZS files down and document their contingent parts, it won't get me to a viewer, since I don't have any experience in writing graphic-viewing apps. Plus, it seems like at least a couple of other people have completely or nearly-completely mapped out the format, so I'd just be re-inventing the wheel, so to speak.
 
Last edited:
I just tried mine again... it should still work. Try running a debug build in visual studio and let me know where it crashes. You can set the argument in the project settings. It needs to be a full path to a stage in  STAGE1 or STAGE2. I guess STAGE04.LZS is the one you've got in the windows viewer.
 
Thank Heavens, a solution. Wait, visual studio? Oh, Microsoft Visual Studio 2012. I shall see if I can figure out a way to edit the data with it.
 
Last edited:
I'm using MinGW, but I can use gdb to provide debugging data (and that'll likely be more useful anyway, since you're using Linux).

First, here's my current makefle:

Code: [Select]
Code:
all: stageviewstageview: stageview.o gcc $< -o $@ -L/usr/lib -lopengl32 -lglu32 -lglut32 -lstdc++stageview.o: stageview.cpp gcc $< -c -o $@ -I/usr/include -g

And here's my current stageview.cpp:

Code: [Select]
Code:
// System#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <cstdlib>#include <stdio.h>#include <stdlib.h>#include <windows.h>// STL#include <string>#include <cassert>// GLUT#include <glut/glut.h>// OpenGL#include <gl/gl.h>#include <gl/glu.h>#include <gl/glext.h>using 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 functionsu16 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;}int load_lzs(const string & name, void ** data ){ // read compressed data u8 *buf; int tsize = load( name, (void**)&buf ); 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;}// Background loading and storagestruct Vertex { s16 x, y, z; s16 u, v;};struct Element { u16 a, b, c, s; // s = shader};struct Mesh { int texture; int element_start; int element_count;};struct Shader { int texture; int palette;};struct Background { int vertex_count; Vertex *vertex; int element_count; Element *element; int *indexbuffer; int shader_count; Shader *shader; GLuint *textures; int mesh_count; Mesh *mesh;};intadd_vertex(Background *bg, s16 x, s16 y, s16 z, u8 u, u8 v){ for (int i=0; i<bg->vertex_count; i++) {  if (bg->vertex[i].x == x && bg->vertex[i].y == y && bg->vertex[i].z == z && bg->vertex[i].u == u && bg->vertex[i].v == v) {   return i;  } }  int idx = bg->vertex_count++; bg->vertex = (Vertex *)realloc(bg->vertex, bg->vertex_count * sizeof(Vertex)); bg->vertex[idx].x = x; bg->vertex[idx].y = y; bg->vertex[idx].z = z; bg->vertex[idx].u = u; bg->vertex[idx].v = v; return idx;}int add_triangle(Background *bg, u16 a, u16 b, u16 c, u16 s){ int idx = bg->element_count++; bg->element = (Element*)realloc(bg->element, bg->element_count * sizeof(Element)); bg->element[idx].a = a; bg->element[idx].b = b; bg->element[idx].c = c; bg->element[idx].s = s; return idx;}intadd_shader(Background *bg, int texture, int palette){ for (int i=0; i<bg->shader_count; i++) {  if (bg->shader[i].texture == texture && bg->shader[i].palette == palette) {   return i;  } }  int idx = bg->shader_count++; bg->shader = (Shader *)realloc(bg->shader, bg->shader_count * sizeof(Shader)); bg->shader[idx].texture = texture; bg->shader[idx].palette = palette;  return idx;}voidload_background(const string & filename, Background *bg){ bg->vertex_count = 0; bg->vertex = NULL; bg->element_count = 0; bg->element = NULL; bg->textures = NULL; bg->shader_count = 0; bg->shader = NULL; bg->mesh_count = 0; bg->mesh = NULL;  u8 * data; int size = load_lzs(filename, (void**)&data); int num_pointer = get_u32le(data);  // background texture int texdata = get_u32le(data + num_pointer * 4); int npal = get_u16le(data + texdata + 18); int paldata_size = get_u32le(data+texdata+8); int pal_ofs = texdata + 20; int picdata_size = get_u32le(data+texdata+8+paldata_size); int pic_ofs = texdata + 20 + npal*512 + 12;  int xsize = get_u16le(data+pic_ofs-4)*2; int ysize = get_u16le(data+pic_ofs-2);  // convert mesh data for (int i=1; i<num_pointer-1; i++) {  int base = get_u32le(data + 4 + i * 4);    // triangles  int triangle_offset = base + 4 + get_u32le(data + base);  int num_triangles = get_u16le(data + triangle_offset);  int mesh_tri_flags = get_u16le(data + triangle_offset + 2);    int texture_idx = ((mesh_tri_flags & 0x0E)-6) / 2;  for (int j=0; j<num_triangles; j++) {   int point[3];   int ofs = triangle_offset + 4 + j * 16;   for (int k=0; k<3; k++) {    int p = get_u16le(data + ofs + k * 2) + base + 4;    s16 x =  ((s16)get_u16le(data + p + 0*2));    s16 y = -((s16)get_u16le(data + p + 1*2));    s16 z =  ((s16)get_u16le(data + p + 2*2));    const int uv_offsets[3] = { 8, 12, 14 };    u8 u = data[ofs + uv_offsets[k] + 0];    u8 v = data[ofs + uv_offsets[k] + 1];    point[k] = add_vertex(bg, x,y,z,u,v);   }   u16 flags1 = get_u16le(data + ofs + 6);   u16 flags2 = get_u16le(data + ofs + 10);      int palette_idx = (flags2 >> 6) & 7;   int shader_idx = add_shader(bg, texture_idx, palette_idx);      add_triangle(bg, point[0], point[1], point[2], shader_idx);  }    // quads  int quad_offset = triangle_offset + 4 + num_triangles * 16;  int num_quads = get_u16le(data + quad_offset);  int mesh_quad_flags = get_u16le(data + quad_offset + 2);  for (int j=0; j<num_quads; j++) {   int point[4];   int ofs = quad_offset + 4 + j * 20;   for (int k=0; k<4; k++) {    int p = get_u16le(data + ofs + k * 2) + base + 4;    s16 x =  ((s16)get_u16le(data + p + 0 * 2));    s16 y = -((s16)get_u16le(data + p + 1 * 2));    s16 z =  ((s16)get_u16le(data + p + 2 * 2));        const int uv_offsets[4] = { 8, 12, 14, 16 };    u8 u = data[ofs + uv_offsets[k] + 0];    u8 v = data[ofs + uv_offsets[k] + 1];    point[k] = add_vertex(bg, x,y,z,u,v);   }   u16 flags1 = get_u16le(data + ofs + 18);   u16 flags2 = get_u16le(data + ofs + 10);   int palette_idx = (flags2 >> 6) & 7;   int shader_idx = add_shader(bg, texture_idx, palette_idx);      add_triangle(bg, point[0], point[1], point[2], shader_idx);   add_triangle(bg, point[3], point[2], point[1], shader_idx);  } }  // build meshes bg->indexbuffer = (int*)malloc(bg->element_count * 3 * sizeof(int)); int cur_mesh = 0; for (int i=0; i<bg->element_count; i++) {  bg->indexbuffer[i * 3 + 0] = bg->element[i].a;  bg->indexbuffer[i * 3 + 1] = bg->element[i].b;  bg->indexbuffer[i * 3 + 2] = bg->element[i].c;    if (bg->mesh_count > 0 && bg->mesh[cur_mesh].texture == bg->element[i].s) {   bg->mesh[cur_mesh].element_count++;  } else {   cur_mesh = bg->mesh_count++;   bg->mesh = (Mesh*)realloc(bg->mesh, bg->mesh_count * sizeof(Mesh));   bg->mesh[cur_mesh].texture = bg->element[i].s;   bg->mesh[cur_mesh].element_start = i*3;   bg->mesh[cur_mesh].element_count = 1;  } }  // build required textures struct RGBA {  u8 r, g, b, a; };  RGBA *clut = (RGBA*)malloc(sizeof(RGBA) * 256 * (npal)); for (int j = 0; j < npal; j++) {  for (int i=0; i<256; i++) {   u16 col = (data[i*2 + pal_ofs + j*512 + 1]<<8) | data[i*2 + pal_ofs + j * 512];   clut[i+j*256].r = (((col      ) & 31) * 255 + 15) / 31;   clut[i+j*256].g = (((col >>  5) & 31) * 255 + 15) / 31;   clut[i+j*256].b = (((col >> 10) & 31) * 255 + 15) / 31;   clut[i+j*256].a = ((col & 0x8000) || (col == 0)) ? 0 : 255;  } }  bg->textures = (GLuint*)malloc(sizeof(GLuint) * bg->shader_count); glGenTextures( bg->shader_count, bg->textures); RGBA *texture = (RGBA*)malloc(sizeof(RGBA) * 256 * 256); for (int i=0; i<bg->shader_count; i++) {  // build#if 1  if ( bg->shader[i].palette >= npal ) {   printf("%i %i\n", bg->shader[i].palette, npal);   bg->shader[i].palette = 0;  }#endif  for (int y=0; y<256; y++) {   for (int x=0; x<256; x++) {    texture[y*256+x] = clut[data[pic_ofs + y * xsize + x + bg->shader[i].texture * 256] + bg->shader[i].palette * 256];   }  }    // copy to GL  glBindTexture( GL_TEXTURE_2D, bg->textures[i]);#if 0  // blocky  glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture);  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );#else  // interpolated  gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGBA, 256, 256, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, texture);  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR );#endif } free(texture); free(clut); free(data);}// GLUT and OpenGL stuffBackground battle;int rot_y;int rot_x;void ReshapeWindowFunc(int width, int height){ const double kFOVy = 0.57735; const double kZNear = 0.1;  glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); GLdouble aspect = ((GLfloat)width / (GLfloat)height) * (kZNear * kFOVy); glFrustum(-aspect, aspect, -(kZNear * kFOVy), (kZNear * kFOVy), kZNear, 1000.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity();}void MainRenderLoop(void){ // render glClearColor(0, 0, 0, 1.00); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LEQUAL );    glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 1.0f/255.0f); glEnable( GL_TEXTURE_2D ); glEnable( GL_CULL_FACE ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );        glDisable( GL_LIGHTING ); glDisable( GL_BLEND ); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );  glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef( (float)rot_x * 360.0f / 256.0f, 1.0f, 0.0f, 0.0f ); glRotatef( (float)rot_y * 360.0f / 256.0f, 0.0f, 1.0f, 0.0f ); glTranslatef( 0, -16, 0); glScalef( 1.0f/256.0f, 1.0f/256.0f, 1.0f/256.0f );  glMatrixMode(GL_TEXTURE); glLoadIdentity(); glScalef(1.0f/256.0f, 1.0f/256.0f, 0); glTranslatef( 0.5f, 0.5f, 0);  glEnableClientState( GL_VERTEX_ARRAY ); glEnableClientState( GL_TEXTURE_COORD_ARRAY );  glVertexPointer( 3, GL_SHORT, sizeof(Vertex), &(battle.vertex[0].x) ); glTexCoordPointer( 2, GL_SHORT, sizeof(Vertex), &(battle.vertex[0].u) ); for (int i = 0; i < battle.mesh_count; i++) {  glBindTexture(GL_TEXTURE_2D, battle.textures[battle.mesh[i].texture]);  glDrawElements(GL_TRIANGLES, battle.mesh[i].element_count * 3, GL_UNSIGNED_INT, battle.indexbuffer + battle.mesh[i].element_start); }  glDisableClientState( GL_TEXTURE_COORD_ARRAY ); glDisableClientState( GL_VERTEX_ARRAY );  glFlush();}void SpecialHandler(int key, int x, int y){ 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();}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, "stageview <stage.lzs>\n"); } else {// get current directory  char cwd[1024];  getcwd(cwd, sizeof(cwd));              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) + "/";  }  // 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);      // load data  load_background(path + argv[1], &battle);    rot_y = rot_x = 0;    // main (this will never return)  glutMainLoop(); } return 0;}

gdb using STAGE04.LZS (since you mentioned that specific file, though the outcome is the same regardless of which file I use...even if the file doesn't exist or isn't the right format):

Code: [Select]
Code:
[USERNAME OMITTED]@[HOST OMITTED] ~$ gdb stageviewGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\stageview.exe...done.(gdb) r C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\STAGE04.LZSStarting program: C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USERNAME OMITTED]\STAGE04.LZS[New Thread 848.0xc08]Program received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb) where#0  0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45#1  0x00401557 in load_lzs (name=..., data=0x22fa30) at stageview.cpp:77#2  0x00401ad0 in load_background (filename=..., bg=0x40c020)    at stageview.cpp:228#3  0x00402e49 in main (argc=2, argv=0x3e26f8) at stageview.cpp:502(gdb)
So, it seems to dislike the array for get_u32le.
 
It looks like it failed to find/load the stage file. Maybe mingw munges the path somehow? Or there is a conflict in the code that tries to make the path absolute? Can you show the current value of filename in load_background? (I should really port that to python sometime, to make it more portable.)
 
Hmm...I don't exactly know how to do that with gdb. Let me know if this is the correct method, or if there's another feature that would be better suited:

Code: [Select]
Code:
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\STAGE04.LZSThe program being debugged has been started already.Start it from the beginning? (y or n) yStarting program: C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USER OMITTED]\STAGE04.LZS[New Thread 2904.0x6e4]Program received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb) p 'load_background'::filename$15 = (const std::string &) @0x22ff3c: {static npos = <optimized out>,  _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},    _M_p = 0x3e2b04 "C:\\MinGW\\msys\\1.0\\home\\[USER OMITTED]\\STAGE04.LZS"}}(gdb)
 
Hmm... that looks correct. At this point I'd step through load_lzs and see where it fails. Though I don't have mingw installed anywhere and it has been ages since I used gdb directly, I'm using xcode on MacOS and Visual Studio 2005 (because I'm poor) on Windows.
 
Code: [Select]
Code:
$ gdb stageviewGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe...done.(gdb) b load_lzsBreakpoint 1 at 0x401537: file stageview.cpp, line 76.(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzsStarting program: C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs[New Thread 2760.0xa88]Breakpoint 1, load_lzs (name=..., data=0x22fa30) at stageview.cpp:7676              int tsize = load( name, (void**)&buf );(gdb) n77              int isize = get_u32le(buf) + 4;(gdb) nProgram received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb)
So, same place.
 
In case it's of interest, I've also done so for load_background and main:

Code: [Select]
Code:
$ gdb stageviewGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe...done.(gdb) b load_backgroundBreakpoint 1 at 0x401a62: file stageview.cpp, line 217.(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzsStarting program: C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs[New Thread 1124.0xf7c]Breakpoint 1, load_background (filename=..., bg=0x40c020) at stageview.cpp:217217             bg->vertex_count = 0;(gdb) n218             bg->vertex = NULL;(gdb) n219             bg->element_count = 0;(gdb) n220             bg->element = NULL;(gdb) n221             bg->textures = NULL;(gdb) n222             bg->shader_count = 0;(gdb) n223             bg->shader = NULL;(gdb) n224             bg->mesh_count = 0;(gdb) n225             bg->mesh = NULL;(gdb) n228             int size = load_lzs(filename, (void**)&data);(gdb) nProgram received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb)

Code: [Select]
Code:
$ gdb stageviewGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe...done.(gdb) b mainBreakpoint 1 at 0x402c41: file stageview.cpp, line 477.(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzsStarting program: C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs[New Thread 3776.0x1ac]Breakpoint 1, main (argc=2, argv=0x3e26f8) at stageview.cpp:477477     {(gdb) n478             if (argc != 2) {(gdb) n483                     getcwd(cwd, sizeof(cwd));(gdb) n485                   string path;(gdb) n486                     if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] != 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') {(gdb) n491                     glutInit(&argc, (char **) argv);(gdb) n492                     glutInitWindowSize(640, 480);(gdb) n493                     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);(gdb) n494                     glutCreateWindow(argv[0]);(gdb) n495                     glutDisplayFunc(MainRenderLoop);(gdb) n496                     glutIdleFunc(MainRenderLoop);(gdb) n497                     glutReshapeFunc(ReshapeWindowFunc);(gdb) n498                     glutKeyboardFunc(KeyboardHandler);(gdb) n499                     glutSpecialFunc(SpecialHandler);(gdb) n502                     load_background(path + argv[1], &battle);(gdb) nProgram received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb)

...but as you can see, it's the same issue.
 
Wait, if you're using Visual Studio in Windows, couldn't you just compile a copy of the program?  :)  That's all I'm shooting for here (sure, playing with source is fun, but my goal is to get the app working).
 
Unfortunately since I installed a new HD a few weeks ago my netbook doesn't really have anything FF7 related on it. I'll have to try tomorrow if I can find some time to copy everything over again.
You are stepping over load_lzs. I assume it returns NULL in data, because it somehow fails to load the file. What is interesting is if it fails to open the file, or fails to decompress it. Though I have no experience with mingw, if it needs anything special.
 
Cool; hopefully you can figure something out. If so, I'll add it to the GameHacking.org Downloads section, for posterity.

Not sure what you mean by "stepping over load_lzs". In the first post after yours, I set a breakpoint on load_lzs, and stepped through it...did I miss something?
 
In case it's of interest, I've also done so for load_background and main:

Code: [Select]
Code:
$ gdb stageviewGNU gdb (GDB) 7.4Copyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.  Type "show copying"and "show warranty" for details.This GDB was configured as "i686-pc-mingw32".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe...done.(gdb) b mainBreakpoint 1 at 0x402c41: file stageview.cpp, line 477.(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzsStarting program: C:\MinGW\msys\1.0\home\[USER OMITTED]\stageview.exe C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs[New Thread 3776.0x1ac]Breakpoint 1, main (argc=2, argv=0x3e26f8) at stageview.cpp:477477     {(gdb) n478             if (argc != 2) {(gdb) n483                     getcwd(cwd, sizeof(cwd));(gdb) n485                   string path;(gdb) n486                     if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] != 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') {(gdb) n491                     glutInit(&argc, (char **) argv);(gdb) n492                     glutInitWindowSize(640, 480);(gdb) n493                     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);(gdb) n494                     glutCreateWindow(argv[0]);(gdb) n495                     glutDisplayFunc(MainRenderLoop);(gdb) n496                     glutIdleFunc(MainRenderLoop);(gdb) n497                     glutReshapeFunc(ReshapeWindowFunc);(gdb) n498                     glutKeyboardFunc(KeyboardHandler);(gdb) n499                     glutSpecialFunc(SpecialHandler);(gdb) n502                     load_background(path + argv[1], &battle);(gdb) nProgram received signal SIGSEGV, Segmentation fault.0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);(gdb)

...but as you can see, it's the same issue.
LB: If you look carefully the debugger indicated buf was a NULL pointer (see this line)
Code: [Select]
Code:
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:4545              return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)| (((u8*)buf)[3]<<24);
which means it can't dereference a reference to NULL in the function (by the way should it be checking for NULL pointers before using one?).
Erstwhile what Mickey was suggesting might be a bit difficult with straight gdb you could try debugging the application under Eclipse with MinGW. What I believe was being suggested was to inspect buf before it's used.

Cool; hopefully you can figure something out. If so, I'll add it to the GameHacking.org Downloads section, for posterity.

Not sure what you mean by "stepping over load_lzs". In the first post after yours, I set a breakpoint on load_lzs, and stepped through it...did I miss something?
It appears what is going wrong is before the get_u32le function is called because buf is being passed as a NULL pointer (0).

That is probably whats going wrong.
Code: [Select]
Code:
u16 get_u16le(void const * const buf){ u16 temp; temp = 0; if(buf) {  temp = ((u8*)buf)[0] | (((u8*)buf)[1]<<8); } return temp;}u32 get_u32le(void const * const buf){ u32 temp; temp = 0; if(buf) {  temp = ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16) | (((u8*)buf)[3]<<24); } return temp;}
would prevent the error from croping up, however if it's passing NULL pointers that Is the real problem line 78 in function
Code: [Select]
Code:
int load_lzs(const string & name, void ** data )
is where get_u32le is called
Code: [Select]
Code:
int load_lzs(const string & name, void ** data ){ // read compressed data u8 *buf; int tsize = load( name, (void**)&buf ); int isize = get_u32le(buf) + 4;
The prior function call is likely returning a NULL pointer in buff (hence the load function is likely too blame).
going to load
Code: [Select]
Code:
int load( const string & name, void ** data ){        size_t size = 0;        *data = NULL;        int fd = open( name.c_str(), O_RDONLY, 0 );
initializes data to NULL (or buf since this is a reference to buf in the prior function).
skipping a bit further down if it can't open the file or can't allocate the space it returns NULL for the buffer and 0 for the size.

Code: [Select]
Code:
        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;}
So it may make sense to do something like
Code: [Select]
Code:
int load_lzs(const string & name, void ** data ){ // read compressed data u8 *buf; int tsize, isize; // attempt to open file tsize = load( name, (void**)&buf ); // if we successfully opened the file if(tsize) { // get the internal file size and add the header value  isize = get_u32le(buf) + 4;  // if the file size and the internal file size + offset aren't equal  if (isize != tsize) {   free(buf);   *data = NULL;   return 0;  } } else { // clean up  *data = NULL;  return 0; }
I'm not sure where one would dump errors too (error.log?) granted this tool was Micky's quick hack, so yes their might be a few 'problems' with it if everything isn't perfect. Anyhow THAT is why Micky was saying it's probably having a problem with opening the file.

Cyb
 
Try this: http://bin.mypage.sk/FILES/release.zip
It works with the background I tried.
Cyberman is right, there is no error checking. I should probably put an assert into the get_le* functions, the NULL pointer should be really checked outside, in cases where a NULL can be returned.
 
Cyberman: Good tips; thanks very much. I'll keep those in mind in the future.

Micky: Awesome; it works :)  Mind sharing the current source as well?
 
I have started to port it to python, I'll post it here once it is done.
 
Status
Not open for further replies.
Back
Top