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 - Omzy

Pages: [1]
1
Tools / [REL] PuPu - FF8 Field Importer/Exporter
« on: 2012-08-17 03:43:13 »
PuPu
FF8 Field Importer/Exporter



This tool allows you to:
I) View the individual layers of each field file that the game reads to synthesize a background
II) Export these layers to PNGs so they can be manipulated in image-editing programs (batch enabled)
III) Import resized versions of these layers back into a format that can be played in game (batch enabled)

(Note: The current OpenGL driver does not support this import feature, but with some hope, it will in the future)

Instructions:
1. Use Qhimm's Garden to extract the contents of FF8
2. Unzip PuPu.zip
3. Place PuPu.exe in the same directory as the extracted 'field' folder
4. Run the program and it will automatically load all field files contained in the 'field/mapdata' folder
5. Select one or multiple field files in the left box (CTRL + click  for multiple or SHIFT + END to select all)
6. Select the layer you want to view in the right box
7. Use the 'Export' button to save the selected files as PNGs
8. Use the 'Import' button to convert the selected files back to the game format

Download: PuPu_v1.zip

*Known issues:
Import feature not yet supported by OpenGL driver
Not memory-perfect (terminates in the middle of batch process) - Restart where it left off if this happens


2
Updated 8/20/12, Posted new download including all recent fixes, no longer providing links for old downloads = PROJECT COMPLETE
*This is the thread for the Field Pack release, not for the FacePalmer script. See FacePalmer v3.0 for that.

Omzy's FFVII Field Pack
A 100% complete collection of 4x-resized background textures for FFVII.
These are the result of my field resizing batch script FacePalmer. In addition, dozens of special cases were finished by hand.





Download
Download the 3GB field pack. Then, if there are other files that have been fixed, you can download those and apply them individually.

*It is recommended not to use the 'remove glitched textures' option in Bootleg or you may irreversibly lose a lot of playable content.

*If any of these links go dead, send me a PM (it emails me instantly).

Omzy's FFVII Field Pack (~3GB)

Install
After downloading the field pack, you may download individual fixes and 'patch' the folders inside the big pack with the fix (copy&replace). Once finished, you should have a field folder that is ~3.05gb. Your directory structure should resemble this:
C:\Program Files\Final Fantasy VII\mods\FacePalmer\field\(lots of folders)

In the ff7_opengl.cfg file, find the line with the mod_path and change it to:
mod_path = FacePalmer/

To suppress "GLITCH: missed palette write to external texture" messages, add the following lines to the end of your ff7_opengl.cfg file:
# Disable Error Notifications
disable_popup = on


Feedback
If you have trouble installing or getting files downloaded, post in this forum so that others can respond with help.

Don't hesitate to PM me if you find any issues with in-game bugs or quality. I haven't had a chance to playtest everything myself, so there may yet be a few things that aren't completely right.

Potentially Erroneous Fields
delmin2    (Costa del Sol Inn)
zz3      (chocobo sage's house)
icedun_1   (frost cave)
Gold Saucer Entrance

3
Updated 7/16/12, fixed lighting textures issue, Thanks to Aali on getting missing files imported = PROJECT COMPLETE
*This is the thread for the Photoshop script, not for the mod pack release. I've updated that with the new downloadable backgrounds. See Omzy's FFVII Field Pack for that.

FacePalmer v3.0
A Final Fantasy VII Texture Resizing Batch Script for Photoshop CS5.1

Examples of what this script can do (click pictures to enlarge):




Bowl on Don's desk:


Requirements
Requires Aali's Palmer 0.7b for input and conversion
Rheikon's Frontend helps a lot with Palmer's batch functions
Requires Adobe Photoshop CS5.1 (untested on other versions)
Recommended ExtendScript Toolkit for script editing
Requires Perfect Resize 7.0 Professional Edition (PS Plug-in)
Requires Perfectum Filter v1.4 (PS Plug-in)
Requires Aali's OpenGL Driver to play in-game
Tested under Windows 7 32-bit

Script Instructions
1) Extract flevel.lgp using UnLGP
2) Copy and paste the script into a text editor and save as a .jsx
3) This script must be placed into %Photoshop%\Presets\Scripts
4) Batch export layers to PNGs in Palmer
5) Place all of these folders inside %Photoshop%\ff7TexturesIN\
6) Open Photoshop, run File->Scripts->FacePalmer
7) Open Palmer again and batch import the folders in %Photoshop%\ff7TexturesOUT\
8 ) Place all new folders in Palmer's output folder into %FFVII%\mods\%modpath%\field\
9) Play the game!

Special Cases
The following files still need to be hand-finished after running the script:
blin69_1, chorace, chorace2, hyou5_2, itown1a, itown2, itown12, junair, junonl2, junonr2, las1_1, las4_2 (missing block bug in original game), las4_3 (missing block bug in original game), losin1, onna_5, sango2, ship_2, sininb41, trnad_1, trnad_3, uttmpin4, whitein, zcoal_1, zcoal_3

Script
FacePalmer_v3.0.jsx

4
Tools / [REL] Omzy's .MAP -> .OBJ Converter
« on: 2010-09-03 04:35:01 »
ff7MapToObj

Note: This program uses info from Ficedula's World Map Viewer (Reeve): http://forums.qhimm.com/index.php?topic=6057.0

I wrote this little program so that I could render a heightmap of the ff7 world map.

Seeing as how this is my first c++ release ever, don't expect it to be fast or efficient. In fact, since it makes external calls to LZSCDec.exe (because I didn't write my own decompressor), expect it to run slow. Also, I don't guarantee that it works on all OS's due to variability of int sizes, but it probably does.

Instructions (sorry if its not as easy as plug and play, but it is not legal to bundle the textures):
1) Extract the .rar from: http://www.mediafire.com/?c76sb586q66ee0q into your data/wm directory:
2) Use Biturn: http://mirex.mypage.sk/FILES/bi087b4.rar to extract the textures from data/wm/world_us.lgp. You MUST extract ALL textures as .TGA files AND place them in a new folder: data/wm/textures. You can select multiple textures at once and extract all at once. No need to do it one by one.

The program will read wm0.map, wm2.map, and wm3.map and output wm0.obj, wm2.obj, and wm3.obj. It uses NFITC1's LZS decompressor.

Notes: The textures for wm0 are 90% accurate, but should be exactly the same as Reeve's due to some unknown data (read thread). The textures for wm2 and wm3 are mapped differently, so are totally incorrect. There is one small hole in the wm2.map (underwater) mesh that I am pretty sure was part of the original game and not caused by me. The .obj files are rather large (wm0.obj is 20mb) so expect it to act up unless you've got a good 3d program and adequate system memory.

Downloads:
ff7MapToObj: http://www.mediafire.com/?c76sb586q66ee0q
Biturn (required): http://mirex.mypage.sk/FILES/bi087b4.rar
NFITC1's LZS decompressor (required, bundled with permission): http://www.mediafire.com/?hwyyk2zjjjj

See my Fallout 3 WIPs at the MDMD forums: http://z9.invisionfree.com/industrialpolygons/index.php?showtopic=562

Screenshots (click to enlarge):
World Map (wm0) textured mesh

World Map (wm0) mesh

Underwater Map (wm2) mesh -- Note that if you superimpose it in the central ocean of wm0, it drops in nicely.
There is a deep chasm that follows the path from Junon to Costa del Sol
and there is a channel that goes through the western continent to Lucrecia's cave.

Snow Map (wm3) mesh


Source (Visual C++ 2010):
Code: [Select]
/*
ff7MapToObj
by Omzy ([email protected]) 09/05/2010
        [REL] thread at: http://forums.qhimm.com/index.php?topic=10717.0
See my WIP at the MDMD forums: http://z9.invisionfree.com/industrialpolygons/index.php?showtopic=562

Description: Converts a final fantasy 7 .map file to an .obj file that can be opened in various 3d rendering programs.

Requires: lzscdec.exe (by NFITC1) and .map files (wm0, wm2, wm3 from data/wm) must be in same directory.
Download lzscdec.exe from http://www.mediafire.com/?hwyyk2zjjjj
        Requires: textures directory with .tga's from world_us.lgp in data/wm.

For documentation on .map format, see http://wiki.qhimm.com/FF7/WorldMap_Module
For documentation on .lsz compression, see http://wiki.qhimm.com/FF7/LZS_format
*/

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
using namespace std;

string getMtl (short mtlIndex) //mtlIndex is 9 bit value that represents texture id
{
//mtlcodes.txt and mtlnames.txt are in separate files to make texture swapping easier
char * mtlCode = new char[2]; //mtlcode is 2 alpha characters
ifstream mtlcodefile ("mtlcodes.txt", ios::in); //Codes match material names in mtlnames.txt
if (mtlcodefile.is_open())
{
int count(0); //This loop gets the code at line mtlIndex
mtlcodefile.seekg(0, ios::beg);
while (!mtlcodefile.eof() && mtlcodefile.good() && count < mtlIndex)
{
mtlcodefile.get(mtlCode, 3);
mtlcodefile.ignore(100, '\n');
count++;
}
}
else cout << "Unable to open" << "mtlcodes.txt" << endl;
mtlcodefile.close();

char * curCode = new char[2]; //Current code in file
string mtlName = "";
ifstream mtlnamefile ("mtlnames.txt", ios::in); //Names match material codes in mtlcodes.txt
if (mtlnamefile.is_open())
{
mtlnamefile.seekg(0, ios::beg); //This loop gets the name at the line starting with mtlCode
while (!mtlnamefile.eof() && mtlnamefile.good())
{
mtlnamefile.get(curCode, 3);
if (mtlCode[0] == curCode[0] && mtlCode[1] == curCode[1])
{
mtlnamefile.seekg(0x0001, ios::cur); //Skip '=' in file
char * temp = new char[1];
while (*temp != '\0')
{
mtlnamefile.get(temp, 2);
mtlName.append(temp);
}
break;
}
else
{
mtlnamefile.ignore(100, '\n');
}
}
}
else cout << "Unable to open" << "mtlnames.txt" << endl;
mtlnamefile.close();

//cout << mtlIndex << " " << mtlCode << " " << mtlName << endl;

return mtlName;
}

char * getTexDims (string mtlName)
{
char * texDim = new char[4];
//Open .tga file to check dimensions given mtlName

ifstream mtltexfile ("textures\\" + mtlName + ".tga", ios::in);
if (mtltexfile.is_open())
{
mtltexfile.seekg(0x000C, ios::beg);
mtltexfile.read(texDim, 0x0004);
}
else
{
cout << "Unable to open " << mtlName << ".tga" << endl;
}
mtltexfile.close();

return texDim;
}

void mapToObj (string filename, int numblocks, int dimension)
{
ifstream mapfile (filename + ".map", ios::in|ios::binary); //Input file
ofstream objfile (filename + ".obj", ios::out); //Output file

int totalVertices = 0;
int totalVTs = 0;

if (mapfile.is_open() && objfile.is_open())
{
objfile << "mtllib tgalib.mtl" << endl;

int * meshloc = new int;
int * lzssize = new int;

for (int i = 0; i < numblocks; i++) //There are 69 Blocks in wm0.map, ignores last 6 blocks (see below)
{
//Calculate north-south block (nsblock) and east-west (ewblock) offsets of block (7x9 grid of blocks = 63)
//Block size is 8192*4 = 32768x32768 coordinate units
//Note that blocks 63, 64, 65, 66, 67 and 68 replace blocks 50, 41, 42, 60, 47 and 48 (respectively), according to the story of the game.
int ewblock = i % dimension;  //take mod to get 0-8
int nsblock = floor ((float)(i / dimension)); //take floor to get 0-6

//cout << i << " " << ewblock << " " << nsblock << endl;

for (int j = 0; j < 16; j++) //There are 16 meshes in each block
{
//Calculate north-south (ns) and east-west (ew) offsets of mesh (4x4 grid of meshes = 16)
//Mesh size is 8192x8192 coordinate units
int ew = j % 4;  //take mod to get 0-3
int ns = floor ((float)(j / 4)); //take floor to get 0-3

int pos = i * 0xB800 + j * 0x0004;

mapfile.seekg (pos, ios::beg); //Block i, Mesh j
mapfile.read ((char *) meshloc, 0x0004); //Read location of mesh (pointer is 4 bytes)

pos = i * 0xB800 + *meshloc;
mapfile.seekg (pos, ios::beg); //Mesh LZS starts here
mapfile.read ((char *) lzssize, 0x0004); //Size is 1st 4 bytes
mapfile.seekg (-0x0004, ios::cur); //Go back 4 bytes because .lzs file includes size
char * memblock = new char [*lzssize + 0x0004];
mapfile.read (memblock, *lzssize + 0x0004); //Read the compressed mesh to memory (don't forget to read the size header)

ofstream lzsfile ("mesh.lzs", ios::out|ios::binary); //Write compressed mesh to mesh.lzs file
if (lzsfile.is_open())
{
lzsfile.write (memblock, *lzssize + 0x0004);
}
lzsfile.close();

//system("lzs.exe -d -q mesh.lzs"); //Decompress mesh with Ficedula's LZS decompressor
system("lzscdec.exe mesh.lzs D mesh.dec"); //Decompress mesh with NFITC1's LZS decompressor
remove ("mesh.lzs");

fstream::pos_type meshsize; //Copy data from mesh.dec to memory
ifstream meshfile ("mesh.dec", ios::in|ios::binary|ios::ate);
if (meshfile.is_open())
{
meshsize = meshfile.tellg();
delete[] memblock;
memblock = new char [meshsize];
meshfile.seekg (0, ios::beg);
meshfile.read (memblock, meshsize); //Read size header? Just need #triangles  & #vertices
}
meshfile.close();
remove ("mesh.dec");

//Here we add the mesh in memblock to the .obj file
//May need to add offsets for block # because map is 9x7 grid of 63 blocks.
unsigned char * mem_ptr;
unsigned short numTriangles, numVertices;
mem_ptr = (unsigned char *)(memblock);
numTriangles = *mem_ptr;
numTriangles += *(mem_ptr + 0x0001) << 8;
mem_ptr = (unsigned char *)(memblock + 0x0002);
numVertices = *mem_ptr;
numVertices += *(mem_ptr + 0x0001) << 8;

//cout << numTriangles << " " << numVertices << endl;

for (int f = 0; f < numTriangles; f++) //Triangle (face) data. Each triangle consists of 12 bytes. The first 3 are vertex indices.
{
pos = (int) (memblock + 0x0004 + 0x000C * f);
mem_ptr = (unsigned char *)(pos);
unsigned char v0 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char v1 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char v2 = *mem_ptr;
mem_ptr += 0x0002;
unsigned char u0 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char vt0 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char u1 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char vt1 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char u2 = *mem_ptr;
mem_ptr += 0x0001;
unsigned char vt2 = *mem_ptr;
mem_ptr += 0x0001;
unsigned short mtlIndex = *mem_ptr; //Texture is 2 bytes read lower then upper, but only lower 9 bits
mtlIndex += *(mem_ptr + 0x0001) << 8; //For that reason we throw out the top 7 bits

//Debug
//char upper7 = mtlIndex >> 9; //Upper 7 bits (unknown)
//Debug

mtlIndex = mtlIndex << 7;
mtlIndex = mtlIndex >> 7;
mtlIndex++;

//cout << getMtl (mtlIndex) << endl; //Material name
string mtlName = getMtl(mtlIndex);
objfile << "usemtl " << mtlName << endl; //Use texture from tgalib.mtl
objfile << "f " << (int) v0 + totalVertices + 1 << "/" << totalVTs + 1 << "/" << (int) v0 + totalVertices + 1 << " "; //face line format:
objfile << (int) v1 + totalVertices + 1 << "/" << totalVTs + 2 << "/" << (int) v1 + totalVertices + 1 << " "; //f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3
objfile << (int) v2 + totalVertices + 1 << "/" << totalVTs + 3 << "/" << (int) v2 + totalVertices + 1 << endl; //Vertex and Vertex/Normal values are same

//Easier to write the UVs here since they are considered part of a triangle (face) in the .map file. Obj file doesn't care where they are, just their order
//Get texture dimensions given mtlName
char * texDim = new char[4];
texDim = getTexDims (mtlName);
short texWidth = (texDim[1] << 8) + texDim[0];
if (texWidth < 0) texWidth *= -1;
short texHeight = (texDim[3] << 8) + texDim[2];
if (texHeight < 0) texHeight *= -1;
//cout << texWidth << " " << texHeight << endl;

objfile << "vt " << (float)((float) u0 / texWidth) << " " << (float)((float) vt0 * -1 / texHeight) << endl; //Note that V's are flipped
objfile << "vt " << (float)((float) u1 / texWidth) << " " << (float)((float) vt1 * -1 / texHeight) << endl; //All UVs must be divided by texheight/width for normalization
objfile << "vt " << (float)((float) u2 / texWidth) << " " << (float)((float) vt2 * -1 / texHeight) << endl;

totalVTs += 3;
}

for (int v = 0; v < numVertices; v++) //Vertex data. Each vertex consists of 8 bytes. The first 6 are coordinates (2 each).
{
pos = (int) (memblock + 0x0004 + 0x000C * numTriangles + 0x0008 * v);
mem_ptr = (unsigned char *)(pos);
short x = *mem_ptr;
x += *(mem_ptr + 0x0001) << 8;
mem_ptr += 0x0002;
short y = *mem_ptr;
y += *(mem_ptr + 0x0001) << 8;
mem_ptr += 0x0002;
short z = *mem_ptr;
z += *(mem_ptr + 0x0001) << 8;
objfile << "v " << (int) x  + ewblock * 32768 + ew * 8192 << " " << (int) y << " " << (int) z + nsblock * 32768 + ns * 8192 << endl;
}

for (int vn = 0; vn < numVertices; vn++) //Vertex/Normal data. Each vertex/normal consists of 8 bytes. The first 6 are coordinates (2 each).
{
pos = (int) (memblock + 0x0004 + 0x000C * numTriangles + 0x0008 * numVertices + 0x0008 * vn);
mem_ptr = (unsigned char *)(pos);
short x = *mem_ptr;
x += *(mem_ptr + 0x0001) << 8;
mem_ptr += 0x0002;
short y = *mem_ptr;
y += *(mem_ptr + 0x0001) << 8;
mem_ptr += 0x0002;
short z = *mem_ptr;
z += *(mem_ptr + 0x0001) << 8;
objfile << "vn " << (int) x  + ewblock * 32768 + ew * 8192 << " " << (int) y << " " << (int) z + nsblock * 32768 + ns * 8192 << endl;
}

totalVertices += numVertices;

//Mesh added to .obj file.
delete[] memblock;

//Report progress
system("cls");
cout << "ff7MapToObj by Omzy" << endl << endl;
cout << "Converting " << filename << ".map..." << endl;
cout << "Progress: Block: " << i + 1 << "/" << numblocks << " Mesh: " << j + 1 << "/16" << endl;
}
}
delete[] meshloc;
delete[] lzssize;
}
else cout << "Unable to open" << filename << ".map" << endl;

mapfile.close();
objfile.close();

return;
}

int main () {

mapToObj ("wm0", 63, 9);
mapToObj ("wm2", 12, 3);
mapToObj ("wm3", 4, 2);

system("Pause");
return 0;
}

5
Hello all, my first post here.

I am working on a total conversion ff7 remake for Fallout 3 with some others at the MDMD Forums:http://z9.invisionfree.com/industrialpolygons/index.php?act=idx. So far I've managed to get a working battle menu UI into the game and I was about to start working on developing the battle system. A friend of mine wants to help by starting work on the environments. However, I realized that I needed a complete world to drop cities and towns into before he can build them (for technical reasons). I made a heightmap using a flat screenshot of the ff7 world map and then hand-drew the mountainous regions and applied some photoshop filters to give them slopes. The problem is, its just not as accurate as I would like it to be.

What I really want is to get the original 3d map from the game and render it into a 4096x4096 heightmap. Then it will be absolutely true to the original. I'm kind of like you guys in my craziness to get things done properly, so that's why I came here to ask for help.

This dead thread: http://forums.qhimm.com/index.php?topic=5825.0;nowap
+
This wiki article: http://wiki.qhimm.com/FF7/WorldMap_Module

are the basis for my interest here.

Tonberry actually rendered the full map and posted this image:


As I said, I need it 4096x4096, so I'll need to render it on my machine. What I'm asking is for help taking the wm0.map and wm2.map files from data/wm, parsing them for their mesh data, and rendering this somehow. I am educated enough to follow instructions and I know a bit of java/c++, but I have never used anything like OpenGL or done any hex editing for that matter.

Basically, I don't want to spend a week doing this when someone else with skills can accomplish it in a few hours. It is the only low-level part of my project (I work with functions like Player.Cast FireBall Enemy  ;D)

Thanks in advance for any replies,

Omzy

Disclaimer: I own multiple copies of ff7. I'm not attempting to rip any game assets for direct use. My profit-less distribution is intended to meet all legal requirements upon eventual release.

Pages: [1]