Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Topics - Micky

Pages: [1] 2
1
Well, kind of on-topic, even though an accessible implementation is still a bit off:
http://youtu.be/Oie1ZXWceqM
(Depending if they release the code or not.)
Still, together with the existing camera and walkmesh info this may be a quick way to get a starting layout to work off.

Here's the abstract: http://www.faculty.idc.ac.il/arik/site/3Sweep.asp

2
I'm playing around with Unity3d at the moment, and I like it a lot! As an experiment I implemented an importer for some of the Xenogears assets types. It is just some of my old C++/Python code converted to C# and munged together. It doesn't contain any of Akari's latest research from q-gears and I didn't make any attempt to clean up duplicate functionality, yet.
You can't actually play anything, but you can use the Unity editor as a viewer to explore some of the models and textures.
http://bin.mypage.sk/FILES/ImportXenogears.unitypackage

Usage:
- Make sure you don't need the computer for the next hour or so and have lots of free space on the HD.
- You need raw disc images of disc 1 and disc 2. (2352 byte sector format, file extension .img. The extension is only cosmetic because I didn't find a way to allow multiple extensions in Unity's file selector API.)
- You need Unity 3.5. The free version should do. I don't have Unity 4.0 at home, yet, so I can't tell if there are any problems. ( http://unity3d.com/unity/download/archive )
- Create a new project.
- Import the unity package. This should give you two scripts.
- The window menu should now have an "import xenogears" option
- Use "choose disc image" to select the disc images. The code takes a sniff at the file system and automatically detects disc1/disc2 of the US NTSC version.
- Select "Import". The importer unpacks the disc images into individual files and then imports field, battle stages, worldmap and a bunch of TIM files. This takes ages, and unfortunately I can't display a progress bar because much of the UI is blocked.

There will be unity scenes for the field and battle backgrounds and the terrains that can be opened, alternatively you can browse the models in the project view. I didn't create scenes for the imported images.

Let me know how it goes.
(I don't plan to make this playable, that time would be better invested into q-gears.)

Update:
- it's now a unity package
- tweaked the instancing code for field scenes
- added hierarchy for battle scenes
- added scene models (mostly gears and spaceships)

3
I was curious if any useful data about the structure of a field or how they were created could be extracted from the way tiles are grouped into strips. So I added a simple UI to my own extraction tool:

Unfortunately it's nothing useful. They seem to be mostly grouped by which palettes they share. Well, if anyone else is curious, this saves you the time! :)

4
Scripting and Reverse Engineering / [FF7] textbox gradient
« on: 2011-09-22 20:26:12 »
Well, this is something I spent a bit researching, though it is really of minor importance. The corner colours for a text box in FF7 can be changed in the settings, something like this:

The top left gradient should be familiar to people who played around with this. The hardware draws a quad internally as two triangles, and each triangle interpolates the colours at its corners. Because the same colour is used along the long edge you get a constant colour, and not a mix of all 4 colours as you would expect from a bilinear interpolation.
Nowadays you can solve this easily with a few lines in a pixel shader, except my ancient mac-mini has only a few texture combiners. So I looked a bit into how to solve this otherwise.
The top right gradient is a triangle fan, with the centre colour the average of all corners. It's slightly improved, but still off from a bilinear interpolation. The solution I am most happy with is the bottom left: It uses a tiny 2x2 pixel texture so that it can use the bilinear interpolation hardware used for textures. Unfortunately the precision for that is slightly less than for the vertex colour interpolation, but otherwise it is the best result.
Source:
Code: [Select]
import sys, array

from OpenGL.GL import *

import pygame
from pygame.locals import *

def main(*argv):
    pygame.init()
   
    screen = pygame.display.set_mode((640, 480), HWSURFACE|DOUBLEBUF|OPENGL)

    # set up view
    glViewport(0, 0, 640, 480)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, 640, 480, 0, -1, 1)

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    # scale and offset texture coordinates to that we sample from pixel centre to pixel centre
    glMatrixMode(GL_TEXTURE)
    glLoadIdentity()
    glScalef(1.0/2.0, 1.0/2.0,1)
    glTranslatef(0.5,0.5,0)

    glDisable(GL_DEPTH_TEST)
    glDisable(GL_CULL_FACE)
    glDisable(GL_LIGHTING)
    glDisable(GL_BLEND)
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
   
    # gradient colours
    colours = array.array("B", [255,0,0,255, 0,255,0,255, 0,255,0,255, 0,0,255,255])
    # colours = array.array("B", [255,0,0,255, 0,255,0,255, 0,0,255,255, 255,255,0,255])
    # colours = array.array("B", [255,0,0,255, 0,255,0,255, 255,0,0,255, 0,255,0,255])
    # colours = array.array("B", [255,255,255,255, 0,0,0,255, 0,0,0,255, 0,0,0,255])
    # colours = array.array("B", [255,0,0,255, 128,128,0,255, 128,128,0,255, 0,255,0,255])
   
    # create texture from gradient colours
    texture = glGenTextures(1)
    glBindTexture(GL_TEXTURE_2D, texture)
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, colours.tostring())
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    # simple replace mode: fragment colour is just texture colour
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

    glClearColor(0.5, 0.5, 0.5, 0)
    while True:
for event in pygame.event.get():
    if event.type == QUIT:
exit()
    elif event.type == KEYDOWN:
if event.key == pygame.K_ESCAPE:
    exit()
   
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

# plain vertex colours
glBegin(GL_QUADS)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(40,40)
glColor4ub(colours[4],colours[5],colours[6],colours[7])
glVertex2i(300,40)
glColor4ub(colours[12],colours[13],colours[14],colours[15])
glVertex2i(300,220)
glColor4ub(colours[8],colours[9],colours[10],colours[11])
glVertex2i(40,220)
glEnd()

# triangle fan with mixed colour in the centre
center = (
    (colours[0]+colours[4]+colours[12]+colours[8]) / 4,
    (colours[1]+colours[5]+colours[13]+colours[9]) / 4,
    (colours[2]+colours[6]+colours[14]+colours[10]) / 4,
    (colours[3]+colours[7]+colours[15]+colours[11]) / 4
)
glBegin(GL_TRIANGLE_FAN)
glColor4ub(center[0],center[1],center[2],center[3])
glVertex2i(470,130)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(340,40)
glColor4ub(colours[4],colours[5],colours[6],colours[7])
glVertex2i(600,40)
glColor4ub(colours[12],colours[13],colours[14],colours[15])
glVertex2i(600,220)
glColor4ub(colours[8],colours[9],colours[10],colours[11])
glVertex2i(340,220)
glColor4ub(colours[0],colours[1],colours[2],colours[3])
glVertex2i(340,40)
glEnd()

# texture
glEnable(GL_TEXTURE_2D)
glBegin(GL_QUADS)
glTexCoord2i(0,0)
glVertex2i(40,260)
glTexCoord2i(1,0)
glVertex2i(300,260)
glTexCoord2i(1,1)
glVertex2i(300,440)
glTexCoord2i(0,1)
glVertex2i(40,440)
glEnd()
glDisable(GL_TEXTURE_2D)

pygame.display.flip()

if __name__ == "__main__":
    main(*sys.argv[1:])
There are a few different gradients to play around with.

5
Just a small update to http://wiki.qhimm.com/FF7/Field_Module/DAT/Tile_Map
I think the first u16 in section 1 was always considered to be sorting depth for the tile. I thought I could do a cool visualisation based on that, so I wrote it out into a mesh file. Unfortunately it seems to be simply the Y coordinate of all tiles in that group. Sigh. (Unless of course there is a silly bug in my viewer.)

6
This is both kind-of on and off topic... I plan to investigate what kind of data I can extract from Panzer Dragoon Saga, and one of the few Sega-internal formats is PRS. I found a closed-source decompressor, and a few open-source (in cpp and c#) that seemed to be unnecessarily complicated. I implemented this routine in python so that other people have a better reference, and I can investigate Saga. I compared the output on NiGHTS with the closed-source decompressor, and the result is identical.
Unfortunately I don't have a model or texture viewer, yet.
(On-topic because the algorithm is based on LZS similar to Xenogears and FF7, so maybe useful if this extension was picked up by square.)
Code: (python) [Select]
# SEGA PRS Decompression (LZS variant)
# Credits:
# based on information/comparing output with
# Nemesis/http://www.romhacking.net/utils/671/
# puyotools/http://code.google.com/p/puyotools/
# fuzziqer software prs/http://www.fuzziqersoftware.com/projects.php

import array

class DecompressPrs:
    def __init__(self, data):
self.ibuf = array.array("B", data)
self.obuf = array.array("B")

self.iofs = 0
self.bit = 0
self.cmd = 0
   
    def getByte(self):
val = self.ibuf[self.iofs]
self.iofs += 1
return val
   
    def getBit(self):
if self.bit == 0:
    self.cmd = self.getByte()
    self.bit = 8
bit = self.cmd & 1
self.cmd >>= 1
self.bit -= 1
return bit

    def decompress(self):
while self.iofs < len(self.ibuf):
    cmd = self.getBit()
    if cmd:
self.obuf.append(self.ibuf[self.iofs])
self.iofs += 1
    else:
t = self.getBit()
if t:
    a = self.getByte()
    b = self.getByte()
   
    offset = ((b << 8) | a) >> 3
    amount = a & 7
    if self.iofs < len(self.ibuf):
if amount == 0:
    amount = self.getByte() + 1
else:
    amount += 2

    start = len(self.obuf) - 0x2000 + offset
else:
    amount = 0
    for j in xrange(2):
amount <<= 1
amount |= self.getBit()
    offset = self.getByte()
    amount += 2
   
    start = len(self.obuf) - 0x100 + offset
for j in xrange(amount):
    if start < 0:
self.obuf.append(0)
    elif start < len(self.obuf):
self.obuf.append(self.obuf[start])
    else:
self.obuf.append(0)
    start += 1

return self.obuf.tostring()
   
def main():
    import glob, os
   
    list = glob.glob("NiGHTS/*.PRS")
    for file in list:
   
f = open(file, "rb")
data = f.read()
f.close()

prs = DecompressPrs(data)
data = prs.decompress()

outfile = os.path.splitext(file)[0] + ".bin"
f = open(outfile, "wb")
f.write(data)
f.close()

if __name__ == "__main__":
    main()
No fancy user interface, you'll have to fix the path to your data in the main routine, or integrate it into your own framework.

7
Completely Unrelated / Showing off...
« on: 2010-12-18 10:49:18 »
Okay, while we're at it: y'all go buy a copy of DJ Hero 2. It's an awesome game.
http://www.djhero.com/
AFAIK most bundles, except the stand-alone disc, contain a copy of DJ Hero 1 as well.
(I worked on bits and pieces on the engine side.)

8
Scripting and Reverse Engineering / [Xenogears] Filesystem
« on: 2010-06-06 20:45:05 »
(In extension to this old thread)
I cross referenced the info from jpsxdec with the data from my extraction tool, and found a bug in my length calculation for movie scenes. But aside from that, it looks like my assumption that the negative number that shows the start of a directory is actually the number of files in the directory is correct. For the movie directory it matches the number of movies reported by jpsxdec, and interestingly the last two entries after the movies point to the executable and config file, at exactly the same sector positions as reported by the iso9660 filesystem.
Unfortunately this leaves quite a few files that don't get put into any directory, so there is maybe still something I'm missing.

Here is the current version of my extraction code:
Code: (Python) [Select]
import sys, os, struct, re, csv

re_name = re.compile(r"(.*);([0-9]+)")
block_size = 2352

def readSectorForm1(f, lba, count):
    f.seek(lba * block_size)
    data = ""
    for i in xrange(count):
block = f.read(block_size)
data += block[24:2048+24]
del block

    return data

def readDir( f, path, dir_pos, dir_size, parent):
    dir = readSectorForm1(f, dir_pos, (dir_size + 2047) / 2048)
    list = []
    pos = 0
    while pos < len(dir):
(entry_size, file_pos, file_len, attr, name_len) = struct.unpack_from("<BxIxxxxIxxxxxxxxxxxBxxxxxxB", dir, pos)
if entry_size > 0:
    hidden = (attr & 1) != 0
    subdir = (attr & 2) != 0

    if file_pos != dir_pos and file_pos != parent:
name = dir[pos+33:pos+33+name_len]
if not subdir:
    pat = re_name.match(name)
    if pat:
name = pat.group(1)

file_path = os.path.join(path, name)
if subdir:
    list.extend( readDir(f, file_path, file_pos, file_len, dir_pos) )
else:
    list.append( (file_path, file_pos, file_len) )
   
    pos += entry_size
else:
    pos = (pos + 2047) & ~2047

    del dir
    return list

def readFileTable(f):
    fileTable = readSectorForm1( f, 24, 16 )
    index = 0
    fileCount = 0
    dirCount = 0
    dirIndex = 0
    movies = False
    list = []
    while True:
startSector = struct.unpack_from("<I", fileTable, index * 7 + 0)[0] & 0xFFFFFF
if startSector == 0xFFFFFF:
    break
fileSize = struct.unpack_from("<i", fileTable, index * 7 + 3)[0]
if fileSize < 0:
    fileCount = 0
    dirIndex = dirCount
    movies = dirCount == 0
    dirCount += 1
elif fileSize > 0:
    file_path = os.path.join("dir%i" % dirIndex, "file%i.bin" % fileCount)
    list.append( (file_path, startSector, fileSize, movies) )
    fileCount += 1
index += 1
    return list

def main(*argv):
    for arg in argv:
f = open(arg, "rb")

# identify the disk
volume_descriptor = readSectorForm1( f, 16, 1 )
(system_identifier, volume_identifier) = struct.unpack_from("<32s32s", volume_descriptor, 8)
system_identifier = system_identifier.strip()
if system_identifier != "PLAYSTATION":
    print "Not a playstation image: \"%s\"" % system_identifier
    f.close()
    return
volume_identifier = volume_identifier.strip()
if volume_identifier != "XENOGEARS":
    print "Not a Xenogears image: \"%s\"" % volume_identifier
    f.close()
    return

# read the filesystem
(root_pos,) = struct.unpack_from("<I", volume_descriptor, 156 + 2)
(root_len,) = struct.unpack_from("<I", volume_descriptor, 156 + 10)
list = readDir( f, "", root_pos, root_len, root_pos)

# find if we're disk 1 or disk 2
disk = None
for file in list:
    if file[0] == 'SLUS_006.64':
disk = 1
break
    elif file[0] == 'SLUS_006.69':
disk = 2
break
if disk is None:
    print "Failed to find executable"
    print "Please post this to the tech-related forum on http://forums.qhimm.com/"
    print list
    f.close()
    return
   
# export normal files
if True:
    for (name, startSector, fileSize)  in list:
blocks = (fileSize + 2047) / 2048
data = readSectorForm1(f, startSector, blocks)

path = os.path.join("disk%i" % disk, name)
dirname = os.path.dirname(path)
if not os.path.exists(dirname):
    os.makedirs(dirname)

d = open(path, "wb")
d.write(data[:fileSize])
d.close()
del data

# export directory table
if False:
    c = open("xenogears_iso%i.csv" % disk, "wt")
    w = csv.writer(c)
    w.writerows(list)
    c.close()

# get hidden file table
list = readFileTable(f)

# export hidden files
if True:
    for (name, startSector, fileSize, movieFlag) in list:
if movieFlag:
    blocks = (fileSize + 2335) / 2336
    f.seek(startSector * block_size)
    data = f.read(blocks * block_size)
else:
    blocks = (fileSize + 2047) / 2048
    data = readSectorForm1(f, startSector, blocks)

path = os.path.join("disk%i" % disk, name)
dirname = os.path.dirname(path)
if not os.path.exists(dirname):
    os.makedirs(dirname)

d = open(path, "wb")
d.write(data[:fileSize])
d.close()
del data

# export file table
if False:
    c = open("xenogears_table%i.csv" % disk, "wt")
    w = csv.writer(c)
    w.writerows(list)
    c.close()
   
f.close()

if __name__ == "__main__":
    main(*sys.argv[1:])

It can give you CSV tables for the ISO filesystem and the file table used for game data. Note that both the config file and the boot file are referenced from both tables.
You need a raw disc image for it to work from.

9
Scripting and Reverse Engineering / Blending on PSX
« on: 2010-06-01 07:27:31 »
I already have Halkun's PSX doc and did some Google search, but there are two bits still unclear:
- There is a special case for colour 0x0000. If it is marked as transparent, does it take part as "black" in the blend operation, or is it like an alpha-kill that doesn't write the pixel into the frame buffer at all?
- What are the rules for untextured polys? Do they just get blended as a whole if alpha blend is enabled?

10
Q-Gears / Invalid filename in subversion
« on: 2010-05-05 19:31:56 »
when I try to update:
Code: [Select]
svn: Can't convert string from 'UTF-8' to native encoding:
svn: output/data/system/?\208?\154?\208?\190?\208?\191?\208?\184?\209?\143 courier_new_9_75.tga
That's on OS/X.
I assume the characters are some kind of non-latin encoding. Is it possible to rename it?

11
Not very exciting... but the diskinfo.cnf contain Shift-JIS encoded text, different on each disk.

Google-translate translates it to:
Code: [Select]
DISK0001
-------------------------------------------------- ----------
This CD is FinalFantasy7 Disk1.
Please take care not to break cover.

When they came out and symptoms are often skipped frames of the movie
CD symptoms may disappear and try to clean the lens.

DISK0002
-------------------------------------------------- ----------
This CD is FinalFantasy7 Disk2.
Please take care not to break cover.

DISK0003
-------------------------------------------------- ----------
This CD is FinalFantasy7 Disk3.
Please take care not to break cover.

12
I was wondering, is there any definite list about the different versions of FF7 that were released? And has anyone compared which files are different in each?

So far I know about:
- NTSC Japanese original
- NTSC Japanese international
- NTSC Japanese international [PSONE BOOKS]
- NTSC US/Canada
- PAL Spanish
- PAL English
- PAL German
- PAL French

Are the platinum editions in any way different to the original releases or the Playstation store versions? Is there a single PAL version for Europe and Australia? Is the Japanese FF7 International in Japanese, English, or selectable English/Japanese?
Official Translations seem to be English, Spanish, French and German. Is there a list of all the existing fan translations?

Sorry, this should really be a FAQ somewhere, but so far my Google-fu has failed me. Most of the stuff I found was related to Advent Children or Crisis Core.

Update: PAL is a separate version for each supported language.
Update: Found about PAL-French and Japanese PSOne release. Are those all?

13
I'm trying to get BCX/BSX files displayed in my own viewer. I found my original code to read the mesh, but it looks like I didn't get animations to work. Searching here I found several people's decoding attempts, but most of the links are dead now. Does anyone still have his notes, or can update the Wiki with the information?
By the way, where in q-gears is the code to extract the information from the original disks? The SVN version I have seems to load the extracted data directly.

14
I dug out my old Xenogears field viewer again:

As you can see, some background parts and the walkmesh are rotated relative to each other. Has anyone seen a transform set, animations or a skeleton in the files? Or is that set from the script?

15
Just in case anyone wants to display Xenogears text without the font:
Quote
wchar_t textCypher[256] = {
   /*00*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*10*/   ' ', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   /*20*/   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
   /*30*/   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', ']', '=', 'a', 'b', 'c',
   /*40*/   'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
   /*50*/   't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '"', '#', '%', '&', '\'', '(', ')', ':',
   /*60*/   '?',    0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, 0xff18, 0xff19, 0xff05, 0xff06, 0x2606, 0x25cb, 0x25a1,
   /*70*/   0x25b3, 0x203b, 0x2192, 0x2190, 0x2191, 0x2193, 0xff0e, 0xff1a, 0xfe63, 0xff0f, 0x2025, 0x201c, 0x300d, 0xff0b, 0xff0d, 0x2573,
   /*80*/   0xff1c, 0xff1e, 0xff05, 0xff06, 0x300e, 0x300f, 0xff03, 0x3001, 0x3002, 0x00b7, 0xff1f, 0xff01, 0xff3f, 0x301c, 0x2026, 0x201d,   
   /*90*/   0xff08, 0xff09, 0x300c,  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*a0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*b0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*c0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*d0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*e0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   
   /*f0*/   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
};
I picked unicode codepoints for the codes from 0x61 on, to get double-wide chars that match what is in the font and to get appropriate symbols. The font contains hiragana and katakana, but I haven't matched those.


16
I tried to update my stage viewer to display field models, but there seems to be a header between the beginning of the model segment and the beginning of the actual model data. The xeno-gears document says it should be the same format as stage models, so I'm not sure if my decoder is just broken. Has anyone else tried to write a viewer?

(BTW, since Akari's original server seems to have disappeared, I uploaded the copy of xeno-gears.htm I had laying around to here. I tried a HTML-Wiki converter, but all the tables seem to confuse it. Still, it would probably a good start to add it to http://wiki.qhimm.com)


17
This is something I've been playing around with since the weekend:
Screenshot
It is a projection of the worldmap from Xenogears onto a spherical mesh. I've been thinking for ages how it would be to have an actual round world, instead of a flat world that wraps around from the north pole to the south pole.
I originally thought I'd have to use some magic preprocessing to avoid distorting the map beyond recognition, but this is a simple spherical projection and it looks OK I think. The only thing that looks a bit messy is one of the islands near the pole. Maybe I'll add a special case for that. A cylindrical projection didn't look as good, though.
The next thing to look into is remeshing of the map to use less triangles in flat areas, and some LOD stuff so you can zoom in and walk around in a 3rd person view. And there are of course loads of graphical effects to add. :)
But this is actually faster than the old flat rendering code, because I resampled the textures for the new mesh. This safes state changes and improves triangulation.

(Mods note: Feel free to move this into the last Xenogears Worldmap thread. I wanted to avoid necromancy.)

18
Just a tiny bit about worldmaps in Xenogears: The map is stored in the last two files in each directory, once row-by-row and and once column by column, probably to optimise the disk-access when updating edges.
The map is stored in 16x16 tiles of 2k, each tile starts with four 9x9 sub-tiles of 4 byte per entry followed by a 16x16 subtile of 2 byte per entry.
The elevation is in the first byte of the 4 initial subtiles.
I've got some code to display it, but it is a bit boring without textures... Does anyone have an idea what compression is used? It doesn't seem to be LZS, because the data doesn't make sense.
(I got my own code to display the battle stages as well, but it is terribly unoptimised - but the stages really look cool, don't they? Maybe I'll port it to GameCube at some point. Where are the filed maps stored?)

19
Scripting and Reverse Engineering / FF7 field info (PS)
« on: 2005-12-31 12:16:43 »
The programmer of the field graphics format wins the price for most complicated format! Definitely management material!
- when decoding the MIM files it is worth copying them into the positions in VRAM that are set in the MIM file, because the texture pages sometime start at different positions.
- the second section of the dat file contains the tiles. It starts with 4 32-bit offsets, then follows some kind of display list. The first offset points to tile descriptions with 8 byte per entry (X/Y/U/V/attributes), the third offset points to tile descriptions with 12 byte per entry. The second entry seems to start with the texture page and hicolour entries required (like the PS texture page register)
- Now it gets complicated, and I haven't decoded everything, yet: there seem to be three kinds of codes:
[16-bit depth?, 16-bit start tile, 16-bit tile count]
[0x7FFE, 16-bit index (into the table of texture page/hicolour entries), 16-bit 0]
[0x7FFF]
The texture page info covers the MIM file correctly, but I'm not sure how the entries are selected correctly. Very strange.
I'll post the code once I've got it working, but I just thought others are interested as well. Is anyone updating Gears, now that Halkun is busy?

20
Scripting and Reverse Engineering / FF7 kernel.bin info
« on: 2005-12-31 12:02:32 »
Just a few words about the text sections in kernel.bin:
- The sections are    
Code: [Select]
"Attack descriptions",
"Spell descriptions",
"Item descriptions",
"Weapon descriptions?",
"Accessory (arm) descriptions",
"Accessory (hand) descriptions",
"Materia descriptions",
"Special Item descriptions",
"Attacks (Menu items)",
"Spells",
"Items",
"Weapons",
"Accessories (arm)",
"Accessories (hand)",
"Materia",
"Special Items",
"Generic Messages",
"Summons?"

- each section starts with a table of offsets to each string
- the strings have a extra compression: after the escape code 0xF9 is an offset:
Code: [Select]
int dist = ((*ptr) & 0x3F)+2;
int count = ((*ptr) >> 6)*2+4;
into the previous string.
- there is another escape code 0xF8, but I'm not sure what it is used for.

21
Scripting and Reverse Engineering / FF7 window.bin info
« on: 2005-12-31 11:57:19 »
Just a few words to expand on window.bin:
- the 6 byte header of in front of each block are compressed size, uncompressed size and some kind of ID.
- first section is a TIM file with general sprites. The "unknown" short in front of the palette size is the number of palettes. I'd say that is just copied as a block into vram
- second section is the font, with 8 palettes, one for each text colour
- last section is the width the pen has to be advanced after drawing each character

22
While looking for CD-XA documentation I found this library to read raw sectors from a CD in Linux:
http://www.gnu.org/software/libcdio/
I don't have a working Linux box at the moment so I can't test this, but this should be useful for anyone who wants to extract movies from FF7, FF8 and Xenogears for PSX.

23
Lost levels has an article about the Final Fantasy 6 3D demo:
http://www.lostlevels.org/200510/
I found it quite interesting, and I hadn't seen the movies before.

24
General Discussion / Final Fantasy 3 (JP) for DS
« on: 2005-10-21 21:01:19 »
Sorry to post another link to insertcredit:
http://www.insertcredit.com/archives/000692.html
Pictures of the DS remake of Final Fantasy 3 (JP).
Droooooool.

MOD EDIT: I think I'm actually going to move this from CU to the General forum.

25
I don't know if anyone here cares, but I used my FF7 PSX battle stage code as a basis to display them on GameCube.
http://www.dextrose.com/_forum/showthread.php?s=&threadid=10578
It's not much different from the GLUT viewer I posted some time ago, except that they are converted offline into GameCube display lists. They are converted into wavefront object files before building the display list, so if you want to you could load them into a modelling application.
All the compiler and libraries for homebrew GameCube development are freely available as they are not related to the official SDK.

Pages: [1] 2