Important information: this site is currently scheduled to go offline indefinitely by end of the year.

Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post questions about game models here, or help out others!
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

Hello there! i try search models from this game in unpacked data with idtool, what i found in Model Researcher:
Image
I newbie on hex founding meshes and etc, but have some success but i don't understand where and how to find UV, if someone have a time help me out please, sample files will be below.

P.S. i think skeletal data in same file as mesh (i've research 00d.dat), i don't know now what file is .dbr maybe texture.
UPDATE: I don't understand how to find UV in hex table, right, or where i can start, i know for UV need use UV tab, if you possible found UV let me know how and where it start in hex or just do a sample screen from model researcher.


https://dropmefiles.com/1oa1x
Last edited by JakeMiles on Tue Feb 16, 2021 9:34 pm, edited 1 time in total.
Lazov
veteran
Posts: 84
Joined: Sat Oct 08, 2016 11:56 am
Has thanked: 17 times
Been thanked: 55 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Help find UV

Post by Lazov »

After finding the vertices, you can start looking for the normals, because they can be visualized. Texture coordinates can also be rendered in the Texture tab.
00d.dat_Sun_Feb_14_06-10-28_2021.png
You do not have the required permissions to view the files attached to this post.
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Help find UV

Post by JakeMiles »

Thanks Lazov i will use that information!
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Help find UV

Post by JakeMiles »

Here my result, ive rotate uv by blender to match with textures, try to find how to find bones, weights and anim if it possible.

Image
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

I'll remane topic for better name becouse it is not about UV only now.
And with new question, for who made exporters models, How i can better know when model info start?

I want do export script for noesis or console app (c#) for find mesh (vertex\normal\UV) then export it by OBJ or SMD, becouse look game files one by one is hard and kill lots of time.

And what ive try search match by hex like

Code: Select all

08 00 00 00 08 00 00 00 2D 2D 2D 2D 2D 2D 2D 2D
and next bytes are verteces but not all it is 2D 2D 2D 2D 2D 2D 2D 2D sometime its just start, and i want to know where i need start to know where vertex a begun, or get position of start or count of vertex\normal\UV and etc. or maybe have tools who hust find vertex of file and try to generate model or some code, becouse if i can't know start of model i think i've can't do batch export of model.

I've appreciate help with c# code, noesis or blender scripts, or just tip how to parse model then next or check by nothing meshes found.

Here a bunch of samples https://dropmefiles.com/soqWc

P.S. If some have tutorial for that link me, please maybe it help me.
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4288
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1149 times
Been thanked: 2243 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by shakotay2 »

Counts should not be a big deal if you're a coder:
.
counts.png
Search for 000001000200 to find start of face indices block(s).
End of block 2D2D [2D...?]
Counts to follow, see picture.

To get start of vertices (0x6f80 for "hand" here) do a backward search for 080000002D2D2D2D2D2D2D2D
(so backwards 2D2D2D2D2D2D2D2D00000008) starting from FI's start address (0x8f10 for "hand" in this sample).

That's how I'd do it.

Don't know whether this applies for all sub meshes/all samples - just found this on a quick glance!

And please: it spells "because", not "becouse". :eek:
You do not have the required permissions to view the files attached to this post.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

Very thanks shakotay2, excuse me for mistake in english, i try search how to convert hex faces into tri-stripes, when i read just short (2 byte int16) it looks like quads:

Code: Select all

f  0 1 2 2
f  3 3 3 4
f  5 6 7 8
f  9 10 11 12
f  13 14 15 16
f  16 10 10 8
f  17 17 18 18
but i need tri strips like that, how it looks in model researcher:

Code: Select all

f  0 1 2
f  3 4 5
f  6 5 4
f  5 6 7
f  8 7 6
f  7 8 9
f  10 9 8
f  9 10 11
f  12 11 10
f  11 12 13
f  14 13 12
f  13 14 15
f  16 15 14
f  10 8 17
f  20 19 18
for example, this is may noob question but i didn't understand and can't see simple tutorial how to convert quad to tri-stripts, but i see many peoples do that in exporters, if some one can teach me with sample or code i will be appreciate it.

P.S. This is what i want in the end:

Code: Select all

f  1/1/1 2/2/2 3/3/3
f  4/4/4 5/5/5 6/6/6
f  7/7/7 6/6/6 5/5/5
f  6/6/6 7/7/7 8/8/8
f  9/9/9 8/8/8 7/7/7
f  8/8/8 9/9/9 10/10/10
f  11/11/11 10/10/10 9/9/9
f  10/10/10 11/11/11 12/12/12
f  13/13/13 12/12/12 11/11/11
f  12/12/12 13/13/13 14/14/14
f  15/15/15 14/14/14 13/13/13
f  14/14/14 15/15/15 16/16/16
f  17/17/17 16/16/16 15/15/15
f  11/11/11 9/9/9 18/18/18
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4288
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1149 times
Been thanked: 2243 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by shakotay2 »

For the hand (no quads afaics) the tri strips look like so (using hex2obj):
f 1 2 3
f 4 6 5
f 5 6 7
f 6 8 7
f 7 8 2
f 8 9 2
f 2 9 3
f 9 10 3
...

and the algo used (usually?) is to be found here:
shakotay2 wrote: Sat Feb 27, 2016 12:12 am
But there's different ways/algos so may not apply to every mesh.

edit: the link I gave above was for auto creating triangle strips, so not correct here!
see remark here:
shakotay2 wrote: Fri Feb 19, 2021 10:08 am
Last edited by shakotay2 on Fri Feb 19, 2021 2:15 pm, edited 1 time in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

@shakotay2 i try find vertex and faces count by 2D 2D 2D 2D pattern and 6 of 8 will be successful, but sometime it without 2D 2D 2D 2D at the end, just store after faces end like on image, this is eyeball, one of it, second, first eye ball will have 2D 2D 2D 2D at the end.
You do not have the required permissions to view the files attached to this post.
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

I've try search pair (vert. face count) and found only two possitions, after face ind. and before vertex data of model i think.

Code: Select all

part         ofs.        vcount         fcount
1             6300       CA 00 00 00 55 02 00 00 
2             8EA0       CA 00 00 00 62 02 00 00
3             BA60       21 00 00 00 6E 00 00 00
4             C7D0       21 00 00 00 68 00 00 00
5             D530       46 03 00 00 F9 08 00 00
6             17190      23 02 00 00 A3 06 00 00
7             1D5D0      65 01 00 00 EB 02 00 00
8             214F0      28 00 00 00 40 00 00 00
try to search more maybe i found postions or better pattern to stop using 2D 2D 2D 2D.
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

@shakotay2 I've looking at your code and test it on c#, i im right it generate faces from vertex count?
Ive get this from build_tristrips:

Code: Select all

f  1 2 3
f  2 4 3
f  3 4 5
f  4 6 5
f  5 6 7
f  6 8 7
f  7 8 9
f  8 10 9
f  9 10 11
It looks like okay firts time, but in model research faces tab sometime faces looks like that:

Code: Select all

f  204 191 208
f  191 204 192
f  199 192 204
f  192 199 193
f  15 16 26
f  250 26 16
f  26 250 32
f  105 32 250
f  32 105 41
f  95 41 105
And i don't see simiral from my output, its gonna be like:

Code: Select all

f  248 250 249
f  249 250 251
f  250 252 251
f  251 252 253
f  252 254 253
f  253 254 255
f  254 256 255
f  255 256 257
f  256 258 257
...
f  475 476 477
f  476 478 477
f  477 478 479
f  478 480 479
...
and etc.

Picture below how it look in blender.
You do not have the required permissions to view the files attached to this post.
JakeMiles
advanced
Posts: 53
Joined: Wed Aug 12, 2015 11:59 pm
Has thanked: 27 times
Been thanked: 5 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by JakeMiles »

@shakotay2 Ive made it work! A big thanks for the code! :keke:
Ive just give f1 f2 f3 my faces and input facecount from faces list and hooray miracle it look fine!

P.S. i may post c# code if you want a look a it, i just little edit your C code sample.
You do not have the required permissions to view the files attached to this post.
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4288
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1149 times
Been thanked: 2243 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by shakotay2 »

JakeMiles wrote: Fri Feb 19, 2021 12:42 am @shakotay2 I've looking at your code and test it on c#, i im right it generate faces from vertex count?
Upps, well, sorry! My fault, what I linked was the code for auto generated triangle strips. But f1, f2 should not be preset for existing face indices. :cry: So f1= GetFaceIndex(...); f2= GetFaceIndex(...); (That's what you've changed probably.)
P.S. i may post c# code if you want a look a it, i just little edit your C code sample.
Feel free to post it here - might help others, too. :)
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
Bigchillghost
double-veteran
double-veteran
Posts: 1027
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 32 times
Been thanked: 1212 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by Bigchillghost »

JakeMiles wrote: Thu Feb 18, 2021 6:36 pm but sometime it without 2D 2D 2D 2D at the end, just store after faces end like on image
The byte 0x2D (the char '-') is merely a character for padding when the data block is not aligned to 0x10 bytes. The count fields of the vertices/indices are usually stored before corresponding data blocks, if there's no further info (size fields, offsets etc.) stored ahead that can help determining how to read the data correctly. There seems to always be a 0x130-byte header before the vertices block, with the fixed signature 70 01 95 00. So if you must do it by searching for a signature, this should be a good choice.
00d_hdrs.png
You do not have the required permissions to view the files attached to this post.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)
mariokart64n
ultra-veteran
ultra-veteran
Posts: 586
Joined: Sun Jun 05, 2005 12:00 pm
Location: Ontario, Canada
Has thanked: 36 times
Been thanked: 243 times

Re: Fahrenheit (Indigo Prophecy) 2005 EU PC - Research

Post by mariokart64n »

Image

Only thing i've been able to find are heads, I'm guessing there is a different block type that holds weighted geometry...

I usually would write a program to import directly into blender or 3dsmax, but I gave C# a go and wrote this exporter.

Code: Select all

/*
	C# Programs, dumps geometry from data file to obj from Fahrenheit (Indigo Prophecy) 2005
	Author:		mariokart64n
	Date:		February 19, 2021

	more info:
				https://forum.xentax.com/viewtopic.php?f=16&t=23441

	*/

using System;
using System.IO;
using System.Text;

namespace PackExtract {
	class Program {
		static Encoding enc8 = Encoding.UTF8;	// Required for ReadString Function
		static int readShort(ref Byte[] buffer, ref int ptr) {
			// Converts Unsigned 16bit Integer from the buffer
			int word = 0;
			word += buffer[ptr + 1] * 0x00000100;
			word += buffer[ptr + 0] * 0x00000001;
			ptr += 2;
			return word;
			}
		static int readLong(ref Byte[] buffer, ref int ptr) {
			// Converts Unsigned 32bit Integer from the buffer
			int dword = 0;
			dword += buffer[ptr + 3] * 0x01000000;
			dword += buffer[ptr + 2] * 0x00010000;
			dword += buffer[ptr + 1] * 0x00000100;
			dword += buffer[ptr + 0] * 0x00000001;
			ptr += 4;
			return dword;
			}
		static double readFloat(ref Byte[] buffer, ref int ptr) {
			int inputAsInt = readLong(ref buffer, ref ptr);
			double fraction = 0.0F;
			for (int i = 0; i < 23; i++) {
				fraction += (1 & (inputAsInt >> ((23 - i) - 1))) * (Math.Pow(2, -(i + 1)));
				}
			int sign = -1;
			if (((inputAsInt >> 31) & 0x00000001) == 0) {
				sign = 1;
				}
			return (sign * (1 + fraction) * (Math.Pow(2, (((inputAsInt & 0x7F800000) >> 23) - 127))));
			}
		static string ReadString(ref Byte[] buffer, ref int pos, int length) {
			// Reads a string from the buffer
			string output = String.Empty;
			Decoder decoder8 = enc8.GetDecoder();
			int nChars = decoder8.GetCharCount(buffer, pos, length);
			char[] chars = new char[nChars];
			nChars = decoder8.GetChars(buffer, pos, length, chars, 0);
			output += new String(chars, 0, nChars);
			pos += length;
			return output.Replace("\0", string.Empty);
			}
		static void Main(string[] args) {
			Console.WriteLine("===========================================================\n");
			Console.WriteLine("OBJ Dumper for Fahrenheit (Indigo Prophecy) 2005\n");
			Console.WriteLine("Written By:\tmariokart64n");
			Console.WriteLine("Released:\tFebruary 19, 2021\n");
			Console.WriteLine("    https://forum.xentax.com/viewtopic.php?f=16&t=23441\n");
			Console.WriteLine("===========================================================\n\n");
			
			// Check that an argument was supplied
			if (args.Length > 0) {
				
				// Set Filepath
				string file = args[0];
				Console.WriteLine("File:\t{0}\n", file);
				
				// Open File into a FileStream
				
				var fs = new FileStream(file, FileMode.Open);
				// Read File into byte[] Array
				var fsize = (int)fs.Length;
				var buffer = new byte[fsize];
				
				fs.Read(buffer, 0, fsize);
				fs.Close();
				
				// Read file id
				int ptr = 0;
				int i = 0;
				int fileID1 = 0;
				int fileID2 = 0;
				if (fsize > 8) {
					fileID1 = readLong(ref buffer, ref ptr);
					fileID2 = readLong(ref buffer, ref ptr);
					}
				if (fileID1 == 0x41544144 && fileID2 == 0x4B4E4142) {
					int unk01 = readLong(ref buffer, ref ptr);	// always 1?
					int filesize = readLong(ref buffer, ref ptr);
					int count = readShort(ref buffer, ref ptr);
					int unk03 = readLong(ref buffer, ref ptr);	// count?
					int unk04 = readLong(ref buffer, ref ptr);	// 0
					int unk05 = readLong(ref buffer, ref ptr);	// addr?
					int unk06 = readLong(ref buffer, ref ptr);	// count?
					int unk10 = 0;
					int unk11 = 0;
					int unk12 = 0;
					int addr = 0;
					int hash1 = 0;
					int hash2 = 0;
					int meshCount = 0;
					int vertCount = 0;
					int faceCount = 0;
					string objfile = "";
					bool faceCW = true;
					int f1 = 0;
					int f2 = 0;
					int f3 = 0;
					int faceOffset = 0;
					double x = 0.0F;
					double y = 0.0F;
					double z = 0.0F;
					double w = 0.0F;
					
					if (count > 0) {
						for (int b = 0; b < count; b++) {
							ptr = 0x20 + (b * 0x10);
							unk10 = readLong(ref buffer, ref ptr); // ?
							unk11 = readLong(ref buffer, ref ptr); // ?
							unk12 = readLong(ref buffer, ref ptr); // always 0
							addr = readLong(ref buffer, ref ptr);
							ptr = addr;
							hash1 = readLong(ref buffer, ref ptr);
							hash2 = readLong(ref buffer, ref ptr);
							if (hash1 == 0x00931B68 && hash2 == 0x00ADA1F8) {
								
								
								Console.WriteLine("MESHDATA{0}: [{1}{2}]\t@ {3}\n", b, hash1, hash2, addr);
								
								ptr += 0x14;
								meshCount = readLong(ref buffer, ref ptr);
								Console.WriteLine("MESHCOUNT\t{0}\n-------------------------------------\n", meshCount);
								
								ptr += 0x03E0;
								faceOffset = 1;
								for (int m = 0; m < meshCount; m++) {
									Console.WriteLine("  SUBMESH\t{0}\n", m);
									
									ptr += 0x60;
									vertCount = readLong(ref buffer, ref ptr);
									faceCount = readLong(ref buffer, ref ptr);
									Console.WriteLine("    VERTCOUNT\t{0}\n", vertCount);
									Console.WriteLine("    FACECOUNT\t{0}\n", faceCount);
									
									ptr += 0x0108;
									
									Console.WriteLine("    POSITIONS\t@ {0}\n", ptr);
									
									for (i = 0; i < vertCount; i++) {
										objfile += "v " + (readFloat(ref buffer, ref ptr)).ToString("0.000000");
										objfile += " " + (readFloat(ref buffer, ref ptr)).ToString("0.000000");
										objfile += " " + (readFloat(ref buffer, ref ptr)).ToString("0.000000") + "\n";
										ptr += 4;
										}
									objfile += "\n";
									
									Console.WriteLine("    NORMALS\t@ {0}\n", ptr);
									for (i = 0; i < vertCount; i++) {
										x = readFloat(ref buffer, ref ptr);
										y = readFloat(ref buffer, ref ptr);
										z = readFloat(ref buffer, ref ptr);
										w = readFloat(ref buffer, ref ptr);
										//x *= w; y *= w; z *= w;
										w = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2) + Math.Pow(z, 2));
										x /= w; y /= w; z /= w;
										objfile += "vn " + (x).ToString("0.000000");
										objfile += " " + (y).ToString("0.000000");
										objfile += " " + (z).ToString("0.000000") + "\n";
										}
									objfile += "\n";
									
									Console.WriteLine("    TEXCOORD\t@ {0}\n", ptr);
									
									for (i = 0; i < vertCount; i++) {
										objfile += "vt " + (readFloat(ref buffer, ref ptr)).ToString("0.000000");
										objfile += " " + (-readFloat(ref buffer, ref ptr)).ToString("0.000000") + " 0.000000\n";
										}
									ptr += (16-(ptr % 16)) % 16;
									objfile += "\n";
									
									Console.WriteLine("    PRIMITIVES\t@ {0}\n", ptr);
									objfile += "o mesh_" + m.ToString("0") + "\n";
									objfile += "g mesh_" + m.ToString("0") + "\n";
									i = 0;
									while (i < faceCount) {
										faceCW = true;
										f1 = readShort(ref buffer, ref ptr);
										f2 = readShort(ref buffer, ref ptr);
										i+=2;
										while (i < faceCount) {
											f3 = readShort(ref buffer, ref ptr);
											if (f3 == 0xFFFF || f3 == -1) {break;}
											if (f1 != f2 && f2 != f3 && f3 != f1) {
												if (faceCW) {
													objfile += "f " + (f1 + faceOffset).ToString("0");
													objfile += "/" + (f1 + faceOffset).ToString("0");
													objfile += "/" + (f1 + faceOffset).ToString("0");
													objfile += " " + (f2 + faceOffset).ToString("0");
													objfile += "/" + (f2 + faceOffset).ToString("0");
													objfile += "/" + (f2 + faceOffset).ToString("0");
													objfile += " " + (f3 + faceOffset).ToString("0");
													objfile += "/" + (f3 + faceOffset).ToString("0");
													objfile += "/" + (f3 + faceOffset).ToString("0") + "\n";
													}
												else {
													objfile += "f " + (f1 + faceOffset).ToString("0");
													objfile += "/" + (f1 + faceOffset).ToString("0");
													objfile += "/" + (f1 + faceOffset).ToString("0");
													objfile += " " + (f3 + faceOffset).ToString("0");
													objfile += "/" + (f3 + faceOffset).ToString("0");
													objfile += "/" + (f3 + faceOffset).ToString("0");
													objfile += " " + (f2 + faceOffset).ToString("0");
													objfile += "/" + (f2 + faceOffset).ToString("0");
													objfile += "/" + (f2 + faceOffset).ToString("0") + "\n";
													}
												}
											faceCW = !faceCW;
											f1 = f2; f2 = f3;
											i += 1;
											}
										
										}
									ptr += (16-(ptr % 16)) % 16;
									objfile += "\n";
									faceOffset += vertCount;
									Console.WriteLine("  END BLOCK\t@ {0}\n-------------------------------------\n", ptr);
									}
								}
							else {
								//Console.WriteLine("Unknown Block [{0}{1}]\t@ {2}\n", hash1, hash2, addr);
								}
							}
						}
					
					if (objfile != "") {
						using (StreamWriter outputFile = new StreamWriter(Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file) + ".obj"), false)) {
							outputFile.WriteLine(objfile);
							}
						
						
						}
					
					}
				else {
					// Warning User that File Is Invalid
					Console.WriteLine("Invalid File");
					}
				}
			else {Console.WriteLine("Usage:\n\tdat_obj_dumper.exe <dat_file>");}
			
			Console.WriteLine("\n\n\tPress Any Key to Continue....");
			Console.WriteLine("===========================================================");
			Console.Read();
			}
		}
	}
Maxscript and other finished work I've done can be found on my DeviantArt account
Post Reply