Qhimm.com Forums
Miscellaneous Forums => Scripting and Reverse Engineering => Topic started by: Lazy Bastard on 2013-03-29 15:41:01
-
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: http://forums.qhimm.com/index.php?topic=3152.0 (http://forums.qhimm.com/index.php?topic=3152.0)
...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: http://forums.qhimm.com/index.php?topic=4292.0 (http://forums.qhimm.com/index.php?topic=4292.0)
...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 (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_scenes (http://wiki.qhimm.com/view/FF7/Battle/Battle_scenes)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.
-
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:
(http://gamehacking.org/lb/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.
-
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.
-
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.
-
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:
all: stageview
stageview: 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:
// 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 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);
}
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 storage
struct 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;
};
int
add_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;
}
int
add_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;
}
void
load_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 stuff
Background 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):
[USERNAME OMITTED]@[HOST OMITTED] ~
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (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.LZS
Starting 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:45
45 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:
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\STAGE04.LZS
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting 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:45
45 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.
-
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (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_lzs
Breakpoint 1 at 0x401537: file stageview.cpp, line 76.
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs
Starting 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:76
76 int tsize = load( name, (void**)&buf );
(gdb) n
77 int isize = get_u32le(buf) + 4;
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45 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:
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (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_background
Breakpoint 1 at 0x401a62: file stageview.cpp, line 217.
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs
Starting 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:217
217 bg->vertex_count = 0;
(gdb) n
218 bg->vertex = NULL;
(gdb) n
219 bg->element_count = 0;
(gdb) n
220 bg->element = NULL;
(gdb) n
221 bg->textures = NULL;
(gdb) n
222 bg->shader_count = 0;
(gdb) n
223 bg->shader = NULL;
(gdb) n
224 bg->mesh_count = 0;
(gdb) n
225 bg->mesh = NULL;
(gdb) n
228 int size = load_lzs(filename, (void**)&data);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45 return ((u8*)buf)[0] | (((u8*)buf)[1]<<8) | (((u8*)buf)[2]<<16)
| (((u8*)buf)[3]<<24);
(gdb)
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (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 main
Breakpoint 1 at 0x402c41: file stageview.cpp, line 477.
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs
Starting 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:477
477 {
(gdb) n
478 if (argc != 2) {
(gdb) n
483 getcwd(cwd, sizeof(cwd));
(gdb) n
485 string path;
(gdb) n
486 if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] !
= 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') {
(gdb) n
491 glutInit(&argc, (char **) argv);
(gdb) n
492 glutInitWindowSize(640, 480);
(gdb) n
493 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH
);
(gdb) n
494 glutCreateWindow(argv[0]);
(gdb) n
495 glutDisplayFunc(MainRenderLoop);
(gdb) n
496 glutIdleFunc(MainRenderLoop);
(gdb) n
497 glutReshapeFunc(ReshapeWindowFunc);
(gdb) n
498 glutKeyboardFunc(KeyboardHandler);
(gdb) n
499 glutSpecialFunc(SpecialHandler);
(gdb) n
502 load_background(path + argv[1], &battle);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45 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:
$ gdb stageview
GNU gdb (GDB) 7.4
Copyright (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 main
Breakpoint 1 at 0x402c41: file stageview.cpp, line 477.
(gdb) r C:\MinGW\msys\1.0\home\[USER OMITTED]\stage04.lzs
Starting 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:477
477 {
(gdb) n
478 if (argc != 2) {
(gdb) n
483 getcwd(cwd, sizeof(cwd));
(gdb) n
485 string path;
(gdb) n
486 if (argv[1][0] != 0 && argv[1][0] != '/' && argv[1][1] !
= 0 && argv[1][1] != ':' && argv[1][2] != 0 && argv[1][2] != '\\') {
(gdb) n
491 glutInit(&argc, (char **) argv);
(gdb) n
492 glutInitWindowSize(640, 480);
(gdb) n
493 glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH
);
(gdb) n
494 glutCreateWindow(argv[0]);
(gdb) n
495 glutDisplayFunc(MainRenderLoop);
(gdb) n
496 glutIdleFunc(MainRenderLoop);
(gdb) n
497 glutReshapeFunc(ReshapeWindowFunc);
(gdb) n
498 glutKeyboardFunc(KeyboardHandler);
(gdb) n
499 glutSpecialFunc(SpecialHandler);
(gdb) n
502 load_background(path + argv[1], &battle);
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45 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)
0x00401414 in get_u32le (buf=0x0) at stageview.cpp:45
45 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.
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
int load_lzs(const string & name, void ** data )
is where get_u32le is called
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
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.
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
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.
-
I have started to port it to python, I'll post it here once it is done.
Python is cool, that should work under linux without any fiddling around.
In the mean time I'll see if I can get the "old" one working under linux (with some error checking of course). I had complete forgot about this .. duh?
Cyb
-
I've hosted a mirror of StageView's Windows executable on GameHacking.org (with credit, of course), including a quick batch script I wrote to provide a primitive menu system for StageView, in case that's desired by the user: HERE (http://gamehacking.org/download#section15).
The script allows the user to either type the name of the stage file to load, or the word "all", which will load a separate instance of stageview.exe for each valid stage file within a directory (my system could handle loading all stage files simultaneously; who knows how that will act on slower systems). If the user types the name of a valid, existent stage file, but neglects to add the .lzs file extension, the script will append it to the provided file name and try that. If the user types the name of a file that doesn't exist, or that isn't a true stage file, the appropriate message will be displayed, and the user will be asked to try again. After successfully loading one or more stage files, if stageview.exe is closed, the batch script will remain open and allow the user to type another file name (or "all").
Hopefully that's slightly useful to someone.
In case anyone wants to see Micky's app in action:
(http://gamehacking.org/lb/Clipboard02.jpg)
-
Micky, I'm MiLO83 working with LazyBastard.
I am animating / rendering some FMVs for him, but before I became an animator I was a ROM hacker.
I partially translated Brave Story for PSP, put Zelda as the playabe char in Minish Cap GBA, and made Link a driver in Mario Kart Super Curcuit GBA, etc etc. Patching, Lz compression, pointer tables, blah blah.
Believe it or not I can code for squat.
I can however take something thats coded and adjust it lol.
Anyway, have you heard of Noesis? Its a python model viewer / converter with a .py plugin system.
You can write your own import export scripts and the GUI, model preview controls etc are already there.
I'm am potitioning for a move to this platform as it already has import / export scripts for the best 3d model formats / software.
If you are already re-writing the Battle Stage Viewer in .py, can you please write it as an import (/ export ?) script for NOESIS?
NOESIS HOME:
http://oasis.xentax.com/index.php?content=downloads
Here are some quick docs to get you started! :D
http://forum.xentax.com/viewtopic.php?f=29&t=8319&hilit=tutorial+exploring+file+formats
http://forum.xentax.com/viewtopic.php?f=29&t=7760
http://code.google.com/p/noesis-plugins-official/source/browse/trunk/chrrox/export/beta/fmt_noepyxml.py
"http://forum.xentax.com" is an amazing hang out for all this model format reversing stuff.
I have plenty more to ask of you, cause i typed my first python hello world yesterday (trying to convert your PSX Battle Model viewer python script from 2009 to a Noesis plugin myself.) but i'll give time to read about Noesis first. The main idea is you can import and export models to / from Noesis to so many different formats.
- MiLO83
-
I have plenty more to ask of you, cause i typed my first python hello world yesterday (trying to convert your PSX Battle Model viewer python script from 2009 to a Noesis plugin myself.) but i'll give time to read about Noesis first. The main idea is you can import and export models to / from Noesis to so many different formats.
FYI, Micky's model viewer script was for field models, not battle models - http://forums.qhimm.com/index.php?topic=8969.msg122920#msg122920 (http://forums.qhimm.com/index.php?topic=8969.msg122920#msg122920)
And yes, I agree - Noesis looks quite promising.
-
@LazyBastard LOL "Thanks Jimmy!"
-
Heh, guess I don't get the reference, so...you're welcome? ???