What's new

Melee Arcive Viewer (MAV) in development project.

OP
Tcll

Tcll

Complexity == Fun >:3
ok... so here's the tests that Jahra1n uses

testing for:
a string of 4 Characters at any given offset
an unsigned Long integer value from the specified offset
an Endian Swapped unsigned Long integer value from the specified offsetan unsigned short integer value from the specified offset
an endian swapped unsigned short integer value from the specified offset
an unsigned Byte value from the specified offset
a 16bit Fixed decimal signed integer and devides it by the scalar to get the floating point value (commonly used in GameCube Models)
a Single Point Precision Decimal number from the specified offset
an Endian Swapped Single Point Precision Decimal number from the specified offset
a string to a specified lenth from a specified offset
a string from the specified offset, the lenth is detemined by when the reading runs into a '00' byte

possible floating point digits
endian swapped possible floating point digits
________________________________________________

these tests need to be made into functions to be read by the main code, or other functions...

I'm so glad I can read VB... XDD
even though I've never taken 1 tutorial on it... o_O
 
Last edited:
OP
Tcll

Tcll

Complexity == Fun >:3
nope oO
i used PlFxGr.dat

should work fine..
can you tell me from which offset i start and from which i stop in PlFxGr ?

hmm... interesting... 0x20-0x41F7

o_O first encounter of it being in the middle of the data
most of the files I've used had a perfect 16 byte split
 

GameWatching

New member
i started from here and ended from here :
showc.png


it is correct ?
 
OP
Tcll

Tcll

Complexity == Fun >:3
no...

00000020 start here
...
000041F7 end here

the header is at the very top of the file...
and it's not all 0's like what was shown...

header
vert data
0 split
normal data
0 split
UV data
 
Last edited:
OP
Tcll

Tcll

Complexity == Fun >:3
sry...
I just falcon pawnched my computer...

here's what happened:
finished typing out long paragraph for thread...
click submit
"internet explorer cannot display the webpage."

WTF D:<
*looks down at network*
"The Wireless connection has limited or no connectivity"
(being 10 feet away from my computer)
WTF!!! DX<

where's my Minigun!!!... >_> <_<
screw it...
FALCON PAAAWWWNNNCH!!!
 
OP
Tcll

Tcll

Complexity == Fun >:3
here's what I typed out before:

o.o

if we are able to create an Obj and and edit and reinject it,
why it couldn't work ?

KK first off...
obj files suck...
they don't support bone data...
and everything else just plain out sucks

and 2nd of all...
there's nothing to convert it back to dat format...
you'd have to be a really good programmer/hexer to be able to pull it off
you don't appear to know enough of either to pull it off...
I'm not trying to be offencive or anything... and I hope you don't take offence to this...
I'm just simply stating the facts...
You will learn my good man... you certainly have the ambition to. :)

I'm only working on my importer right now...
but I do plan to work on an exporter...

here's the link to it if you'd like to download:
http://tcll5850.proboards.com/index.cgi?action=downloadattachmentpage&board=bpy&thread=36&post=90
Please notify me if you have any problembs. :)
 

Milun

New member
Well, I should have mentioned earlier, but I have a C++ program for faces too. This one's a bit dodgy, but I've converted a couple of .ty files flawlessly.This one works with you copying from the first header in the .ty file ('98 00 23' for example) until the end of the face data. In order to make it run, you have to type a whole heap (20+) of 'CC CC CC ' etc. at the end of the text to tell the program when the end is reached (I know, it's very inconvenient).

so at the end of the .txt file's text, if you had:

......34 AC 23

You'd make it:

......34 AC 23 CC CC CC CC CC CC CC CC CC etc.

Now, here's the code:

Code:
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <iterator>
#include <cstring>
using namespace std;

char *CHAR;

string Input;
string Output;

///We already know what this does.
string fn_DecToHex (unsigned int value) {
	char conHex[256];
	int rawDec = value; //this is variable
	sprintf(conHex,"%x",rawDec);
	return conHex;
}

int fn_HexToDec (char rawHex[]) {
	int conDec; 
	sscanf(rawHex, "%x", &conDec);
	return conDec;
}

string fn_IntToString(int intValue) {
  char *myBuff;
  string strRetVal;
  myBuff = new char[100];
  memset(myBuff,'\0',100);
  itoa(intValue,myBuff,10);
  strRetVal = myBuff;
  delete[] myBuff;
  return(strRetVal);
}

int fn_StringToInt(string strConvert) {
  int intReturn;
  intReturn = atoi(strConvert.c_str());
  return(intReturn);
}

void fn_StringToChar(string STR) {
     int TempNumOne=STR.size();
     for (int a=0;a<=TempNumOne;a++)
     {
         CHAR[a]=STR[a];
     }
}



int main() {

  ///Same as before.
  string line;///Makes a new variable called 'line', the 'line' in this case being the entire hex contained copy-pasted within the .txt, so it's large.
  cout << "Opening files." << endl;///This just shows text in command prompt, and makes a new line.
  
  cout << "Input file: ";
  cin >> Input;///This asks for the complete filename.
  cout << endl;///New line.
  
  ifstream myfile (Input.c_str());///Makes a filename out of 'Input'.
  
  cout << "Output file: ";
  cin >> Output;
  cout << endl;
  
  ofstream outfile (Output.c_str()); ///Makes a filename out of 'Output'.
  
  cout << "Writing vertice data to file." << endl;
  
  
  
  if (myfile.is_open() && outfile.is_open())
  {
    while (! myfile.eof() )
    {   
      ///Same variables.
      getline (myfile,line);
      CHAR  = new char[100];
      unsigned int Offset = 0;
      unsigned int MaxOffset = line.length();
      string HexA;
      string HexB;
      
      ///Ok, here we go.
      unsigned int Face1;///Stores the vertice number for first triangle point.
      unsigned int Face2;///Stores the vertice number for second triangle point.
      unsigned int Face3;///Stores the vertice number for third triangle point.
      unsigned int Face4;///Stores the vertice number in-case of a quadratic.
      unsigned int Duration;///Stores the Datablock size.
      
      //0xB8 // points
      //0xA8 // lines
      //0xB0 // line strip
      //0x90 // triangles
      //0x98 // triangle strip
      //0xA0 // triangle fan
      //0x80 // quads
      
      ///Just all the different faces.
      string LineNor = "A8 0";
      string LineStrip = "B0 0";
      
      string TriStrip = "98 0";
      string TriNor = "90 0";
      string TriFan = "A0 0";
      
      string Quad = "80 0";
      
      ///////////////////////
      string LengthA;
      int LengthB;
      
      ///This aids in the search through the string.
      size_t found;
      
      ///These values are mainly for debugging; they basically show where the nearest face value is on every step.
      int TriStripFound;
      int TriNorFound;
      int QuadFound;
      
      ///The offset for the line after all equations are performed.
      int FinalOffset = 0;
      
      string Type = "";
      
      ///Length is back///
      unsigned int Length;
      
      /////////////////////////////////
      unsigned int FileOffset;

      ///Loop.
      FindLength:
      
      ///These are for debugging. The '999' prevents the search from skipping over a particular header.
      Duration = 0;
      TriStripFound = 999;
      TriNorFound = 999;
      QuadFound = 999;
      
      ///Convert the first 9 characters ('98 00 23 ' for example) to characters.
      fn_StringToChar(line.substr(FinalOffset,9));
      
      ///Used for debugging. Basically, it prints the above string, so I can look for a flaw in my code if it isn't '98', '80' etc.
      cout << "Last Offset words: " << CHAR << endl;
      
      ///Get's rid of everything we were working on before we looped (later), leaving the start of the file to be '98 00 23 '.
      ///This prevents overly large offset numbers.
      line.erase(0,FinalOffset);
      
      ///Look for the first occurence of a Triangle Strip, over 36 characters (12 lots of hex).
      found = line.find(TriStrip,36);
      
      cout << "\n" << "TriStrip found at:                " << found << endl;///Debug; Show me where you found it. It worked if it is 36 (or 0, only at the start of the process).
      
      if (found!=string::npos)///If you actually found it at all...
      {
          if (int(found) == 36 || int(found) == 0)///If it's the right values.
          {
              TriStripFound = int(found);///Make this equal where you found it.
          }
          else
          {
              ///Now, when changing headers, theres usually an intermission of '00' before. So the Triangle Strip would not be at position 36 anymore.
              ///This solves that problem (although, not too well).
              found = line.find("00 00 00 00 00 " + TriStrip,0);
      
              if (found!=string::npos)
              {
                  TriStripFound = int(found)+15;///It adds 15, because of the '00's.
              }
          }
      }
      
      ///Now do the same for other face types.
      found = line.find(TriNor,36);
      cout << "TriNor found at:                  " << found << endl;
      if (found!=string::npos)
      {
          if (int(found) == 36 || int(found) == 0)
          {
              TriNorFound = int(found);
          }
          else
          {
              found = line.find("00 00 00 00 00 " + TriNor,0);
              if (found!=string::npos)
              {
                  TriNorFound = int(found)+15;
              }
          }
      }
      
      ///And again.
      found = line.find(Quad,36);
      cout << "Quad found at:                  " << found << endl;
      if (found!=string::npos)
      {
          if (int(found) == 36 || int(found) == 0)
          {
              QuadFound = int(found);
          }
          else
          {
              found = line.find("00 00 00 00 00 " + Quad,0);
      
              if (found!=string::npos)
              {
                  QuadFound = int(found)+15;
              }
          }
      }
      
      
      
      //////////////////
      /// DEBUG ZONE ///
      //////////////////
      
      cout << "TriFan found at:                  " << line.find(TriFan,0) << endl;
      cout << "LineNor found at:                 " << line.find(LineNor,0) << endl;
      cout << "LineStrip found at:               " << line.find(LineStrip,0) << endl;
      
      //////////////////////////////
      /// NOW LEAVING DEBUG ZONE ///
      //////////////////////////////
      
      ///If TriNor (Triangles; '90') is at the location 36 (remember, all others have been set to '999')
      if (TriNorFound < TriStripFound)
      {
          if (TriNorFound < QuadFound)
          {
              ///Go to its offset.
              FinalOffset = TriNorFound;
      
              ///Now we know what type to convert.
              Type = "Nor";
              
              ///Go to the convertion.
              goto NoConvert;
          }
      }
      
      ///Again.
      if (TriStripFound < TriNorFound)
      {
          cout << "TriStripFound:                               " << TriStripFound << endl;
          if (TriStripFound < QuadFound)
          {
              FinalOffset = TriStripFound;
              Type = "Strip";
              goto NoConvert;
          }
      }
      
      ///Again.
      if (QuadFound < TriNorFound)
      {
          cout << "QuadFound:                            " << QuadFound << endl;
          if (QuadFound < TriStripFound)
          {
              FinalOffset = QuadFound;
              Type = "Quad";
              goto NoConvert;
          }
      }
      
      ///Now we convert.
      NoConvert:
      
      ///Debug.          
      cout << "FinalOffset of type: " << FinalOffset << endl;
      cout << "Type:                " << Type << endl;
      
      ///This looks familiar. Remember, since 'FinalOffset' is still placed before '98 00 23 ', we need to add values.
      ///In this case, we're getting '00' as a value.
      fn_StringToChar(line.substr(FinalOffset+3,2));
      LengthA = CHAR;
      ///Now LengthA == '00'.
      
      ///Now we get '23'
      fn_StringToChar(line.substr(FinalOffset+6,2));
      
      ///And add to it, so we get '0023'///
      ///I do this because space (' ') won't get read.
      LengthA += CHAR;
      
      ///And finally, Length == decimal value of '0023'.
      fn_StringToChar(LengthA);
      Length = fn_HexToDec(CHAR);
      
      ///More debug.
      fn_StringToChar(line.substr(FinalOffset,9));
      cout << "Now converting from offset:       " << CHAR << endl;
      cout << "The length is:                    " << Length << endl << endl;
      
      ///Like Amy once said, 'just wait a minute'.
      ///YOU WOULD SERIOUSLY NEED TO CONCIDER REMOVING THIS, OR IT WILL PAUSE AFTER EVERY HEADER.
      ///The reason I even have it, is to pinpoint exactly where my program has mistakes (which it sometimes does.
      system ("pause");
      
      ///Add 9, so we go past '98 00 23 ', and reach the first value after. Let's say it's '03 15 '
      FinalOffset += 9;
      
      ///Now we convert for real.
      ConvertFace:
      
      ///Convert the '03'.
      fn_StringToChar(line.substr(FinalOffset,2));
      HexA = CHAR;
      
      ///Convert the '15'.
      fn_StringToChar(line.substr(FinalOffset+3,2));
      HexB = CHAR;
      
      ///Our powers combined, we are '0315'.
      HexA += HexB;
      
      fn_StringToChar(HexA);
      
      ///Now Face1 is the decimal value of that.
      Face1 = fn_HexToDec(CHAR);
      
      ///We add 1, because '00' counts, yes theres no such thing as the 0th vertice.
      Face1++;
      
      ///Add to the amount of times we've converted a face.
      Duration++;
      
      ///And again.
      fn_StringToChar(line.substr(FinalOffset+18,2));
      HexA = CHAR;
      fn_StringToChar(line.substr(FinalOffset+21,2));
      HexB = CHAR;
      HexA += HexB;
      fn_StringToChar(HexA);
      Face2 = fn_HexToDec(CHAR);
      Face2++;
      
      ///And again.
      fn_StringToChar(line.substr(FinalOffset+36,2));
      HexA = CHAR;
      fn_StringToChar(line.substr(FinalOffset+39,2));
      HexB = CHAR;
      HexA += HexB;
      fn_StringToChar(HexA);
      Face3 = fn_HexToDec(CHAR);
      Face3++;
      
      ///And once more, incase we have a Quad.
      fn_StringToChar(line.substr(FinalOffset+54,2));
      HexA = CHAR;
      fn_StringToChar(line.substr(FinalOffset+57,2));
      HexB = CHAR;
      HexA += HexB;
      fn_StringToChar(HexA);
      Face4 = fn_HexToDec(CHAR);
      Face4++;
      
      ///If we're not using a Quad.
      ///Also checks if we have double values anywhere.
      if (Type != "Quad"){
      if (Face1 == Face2 || Face1 == Face3 || Face2 == Face3){
      if (Face1 == Face2){Face2 = Face4;}
      if (Face1 == Face3){Face3 = Face4;}
      if (Face2 == Face3){Face3 = Face4;}}
      }
      
      ///Go forward 6 hex spaces ('XX XX XX XX XX XX ').
      FinalOffset += 18;
      
      ///Depending on what type, we need to add more than that.
      if (Type == "Nor"){
               FinalOffset += 36;
               Duration += 2;}
      
      if (Type == "Quad"){
               FinalOffset += 54;
               Duration += 3;}
      
      ///Check for duplicate values. It writes 'ERROR!!!' if we do... This rfeally shows how much faith I have in this code.
      if (Type != "Quad")
      {
          if (Face1 == Face2 || Face1 == Face3 || Face2 == Face3)
          {
              outfile << "f " << Face1 << " " << Face2 << " " << Face3 << " ERROR!!!" << endl;
              cout << "f " << Face1 << " " << Face2 << " " << Face3 << " ERROR!!!" << endl;
          }
          else
          {///And if we don't have duplicates, don't worry, be happy.
              outfile << "f " << Face1 << " " << Face2 << " " << Face3 << endl;
              cout << "f " << Face1 << " " << Face2 << " " << Face3 << endl;
          }
      }
      else
      {///Quads get special treatment, due to the extra point.
          outfile << "f " << Face1 << " " << Face2 << " " << Face3 << " " << Face4 << endl;
          cout << "f " << Face1 << " " << Face2 << " " << Face3 << " " << Face4 << endl;
      }
      
      ///NOW, THIS PART IS VERY IMPORTANT!
      
      ///See how it checks for that particular value?
      ///That is the way I check to see if we reached the end of the file.
      ///What I do is, at the end of the text in the .txt, I type a heap of 'CC CC CC CC CC CC CC CC '
      ///52429 happens to be what you'de get if you converted 'CC CC' to decimal and added 1.
      ///So it checks if we haven't reached the end of the file.
      if (Face1 != 52429)
      {
          if (Type != "Quad")///If we're not Quad's.
          {
              if (Length-3 >= Duration)///If we haven't reached the end of the length the header specified.
              {
                  goto ConvertFace;///Go back and convert again.
              }
              else
              {///But if we have.
                  if (Type == "Nor")
                  {
                      FinalOffset -= 36;///This fixes the offset, because '90' triangles are a bit weird for me.
                  }
                      
                  goto FindLength;///Look for another header.
              }      
          }
          else
          {///If we are using Quad's.
              if (Length-4 >= Duration)///Etc.
              {
                  goto ConvertFace;
              }
              else
              {
                  FinalOffset -= 36;
                  goto FindLength;
              }      
          }
      }
      else
      {
          ///If we are done, then tell me.
          cout << endl << "Done!" << endl << endl;
      }
    }
    myfile.close();
    outfile.close();
  }
  else cout << "Unable to open file";

	system ("pause");
	return 0;
}

Now, a few notes:

1. You'll need to separately convert the vertices, and paste the face data after them in the same .obj (use notepad).

2. You'll need to add this in between, here's an example:

v -1 46 1
v -1 45 2
usemtl (null)
s 1
f 790 791 720
f 791 720 721

There we go.

And here's the executable:

http://www.megaupload.com/?d=626U0TEW

Now, keep in mind, it's EXTREMELY prone to errors, also if you conciser the only faces it converts are Triangles, Triangle Strips, and Quads. But it still works, so... peace out:

 
OP
Tcll

Tcll

Complexity == Fun >:3
as is my Ty converter...
mine converts UV's normals and objects

UV's and normals don't work though... :(

but objects work perfectly for the files that do convert properly :D
 

Milun

New member
Hm... I'm sorry, I know you've probably mentioned this before, but could you mention how I should go about trying to decode UV. I'm pretty sure you linked to a UV guide, but I can't seem to find it.

Sorry about that.

EDIT: Well, it seems that my .obj exporter is near flawless, as all the crashing seems to happen when there are faces that aren't triangle, strip or quad. The whole point of my .obj exporter so far, is not to import (yet), but rather provide a means for people to rip their own models. But it does work:



Now I just hope to export the UV's.
 
Last edited:
OP
Tcll

Tcll

Complexity == Fun >:3
ah... those dreaded UV's that don't seem to work right for me...

just read them as you would verts...
but read 4 instead of 6
but I believe the values have to be byte-swaped
 

Milun

New member
Thanks, but I'm not even sure how to put UV's into .obj format, as in, I have no idea how they are written in .obj.

I'm gonna try making a sphere in Blender, UV texturing it, and seeing how it's formatted.
 
OP
Tcll

Tcll

Complexity == Fun >:3
UV:
vt float(U),float(V)

Normal:
vn float(X),float(Y),float(Z)
 

Milun

New member
...uh...

Well, I'm going to see what I can do. I seem to understand how it's formatted.

I think I should be able to manage, but I'm still unsure how they separate the different textures. I'll get back to you on that.

EDIT: Well, that didn't work. All I got in my UV's was a tangled mess that lagged my computer like crazy.

Ok, what I can tell so far (assuming that the UV data comes after the vertex data) is this (and please excuse me, I don't know the correct names).

The whole process of assigning UV numbers to face points (i.e. 134/23), seems to have no problem, as when I import it into blender, each face has a UV'd texture.

This leads me to believe, that the UV data itself is the problem, because I can never get anything but a tangle in the UV map window. My best assumption is that I'm not using the right equation on the UV when decoding it.
 
Last edited:

Milun

New member
Nope. Sorry, this ones a bit complicated. See, the face hex usually starts with '98 00', and follows a pattern afterward. For instance, in TyEievui.dat, the face hex starts at offset 0x000215E0, and ends around 0x00047BD0. Now, this is really something complex, because I've actually just been estimating where it ends. After you copy and paste it, you have to look for the last occurrence of '98 ?? ??' (in this case '98 00 07') and increase the number of the 3rd Hex to something like '17' (so now it's '98 00 17'). Then add the 'CC'. This makes my program go over the limit of the data, and reach the CC's, otherwise it crashes (yes I know, this is extremely complicated and unnecessary, I'm sorry). Anyway, after it reads everything, it will send out a .obj, which you have to look through (with notepad) to see if it printed 'ERROR!!!' anywhere. It will always print error at the end. Go to the very end of the file, and remove all the lines with 'ERROR!!!' in them, and any that have 2 large numbers (like '34, 35') and then end with '1'. These aren't real values either.

Now I'm going to go and actually make this program usable, as after typing this, I realize just how tedious all this is to do.
 

Top