summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle K <kylek389@gmail.com>2015-04-21 02:19:05 -0500
committerKyle K <kylek389@gmail.com>2015-04-21 02:31:18 -0500
commitd216675c6b00f79d3ecf381c717286f48715a99c (patch)
treec89f6dd94b3111c56702e8ded81b2cbab8172aba
parentcad9c1bbc9226a3d15321696c49eac2d3536782c (diff)
downloadTXRExtractor-d216675c6b00f79d3ecf381c717286f48715a99c.tar.gz
TXRExtractor-d216675c6b00f79d3ecf381c717286f48715a99c.tar.bz2
TXRExtractor-d216675c6b00f79d3ecf381c717286f48715a99c.zip
provide initial 3ds Max model import script
it is still work in progress and meshes don't have materials assigned to them yet, the model format still needs more reversing
-rw-r--r--README.md8
-rw-r--r--maxscript/wmn/credits.txt6
-rw-r--r--maxscript/wmn/dds2gtf.exebin0 -> 147456 bytes
-rw-r--r--maxscript/wmn/gtf2dds.exebin0 -> 147456 bytes
-rw-r--r--maxscript/wmn/wmn.ms837
5 files changed, 847 insertions, 4 deletions
diff --git a/README.md b/README.md
index 4bb94cc..5f14646 100644
--- a/README.md
+++ b/README.md
@@ -2,10 +2,10 @@ Tokyo Xtreme Racer Extractor
============================
TXRExtractor is an archive unpacker for GENKI Tokyo Xtreme Racer series games.
-Currently supported archive extraction include WMN.DAT from Wangan Midnight PS3.
+Currently supported archive extraction include WMN.DAT and AUDIO_PS3.DAT from Wangan Midnight PS3.
-Wangan Midnight uses zlib deflate chunks that inflate up to 256KB. See relevant
-header files for reverse engineered headers and their description.
+Wangan Midnight uses zlib deflate chunks that inflate up to 256KB and files are
+composed of them. See relevant header files for reverse engineered headers and their description.
## NOTES
@@ -14,7 +14,7 @@ You need to have copy of a game or archives to attempt to extract them.
## Status
-* Wangan Midnight 2007 PS3......................: WMN.DAT [ok], AUDIO_PS3.DAT [wip]
+* Wangan Midnight 2007 PS3......................: WMN.DAT [ok], AUDIO_PS3.DAT [ok]
* Import Tuner Challenge 2006 Xbox 360...: [wip]
## Usage
diff --git a/maxscript/wmn/credits.txt b/maxscript/wmn/credits.txt
new file mode 100644
index 0000000..6d74ef1
--- /dev/null
+++ b/maxscript/wmn/credits.txt
@@ -0,0 +1,6 @@
+[dds2gtf.exe and gtf2dds.exe]
+- http://forum.xentax.com/viewtopic.php?p=54964#p54964
+- credits to ExeiL and JU57FL1P for coding up the GFT to DDS converter
+
+[maxscript]
+- thanks to mariokart64n for initial script http://forum.xentax.com/viewtopic.php?f=16&t=12775
diff --git a/maxscript/wmn/dds2gtf.exe b/maxscript/wmn/dds2gtf.exe
new file mode 100644
index 0000000..6277633
--- /dev/null
+++ b/maxscript/wmn/dds2gtf.exe
Binary files differ
diff --git a/maxscript/wmn/gtf2dds.exe b/maxscript/wmn/gtf2dds.exe
new file mode 100644
index 0000000..858d38a
--- /dev/null
+++ b/maxscript/wmn/gtf2dds.exe
Binary files differ
diff --git a/maxscript/wmn/wmn.ms b/maxscript/wmn/wmn.ms
new file mode 100644
index 0000000..7eef22d
--- /dev/null
+++ b/maxscript/wmn/wmn.ms
@@ -0,0 +1,837 @@
+/* ----------------------------------------------------------
+
+ Wangan Midnight 3ds Max Model Import Script
+
+
+
+ C H A N G E L O G
+
+ April 21, 2015
+ - script comments, cleanups, and some changes by nfm aka fatalhalt
+
+ April 20, 2015
+ - 5th revision by mariokart64n
+
+*/ ----------------------------------------------------------
+
+global f, g, PS3_WANGANM_IMPORTER, mscale = ((1.0/2.54)*100), tex = 1, texn = #()
+global impMsh = true, impSkl = false, dumpTex = true, DDSconv = true, guiEnabled = true, clearScene = false, debugMsg = false
+
+struct _geometry (
+ position = #(), -- vertices
+ uv_coordinate = #(),
+ matid = #(),
+ matcount = #(),
+ face = #()
+)
+
+struct _XTD_header (
+ fileid = "", -- 3 chars
+ vers = 0, -- 1 char
+ unk1 = "", -- 4 chars
+ offsets = #()
+)
+
+-- acts as container that usually stores 2 sub blocks; model data and texture
+struct _header (
+ fileid = "", -- 3 chars
+ filever = 0, -- 1 char
+ unk1 = "", -- 4 chars
+ unk2 = 0, -- long
+ count = 0, -- long, count of sub blocks in current file
+ offsets = #(), -- these offsets are relative to a sub block and not the whole file e.g. when XMD contains another XMD
+ sizes = #()
+)
+
+struct _subheader (
+ type = 0, -- short
+ string_index = 0, -- short
+ size = 0, -- long
+ unk2 = 0, -- long
+ unk3 = 0 -- long
+)
+
+-- this is a table that appears 1 long after "Bp"
+struct _filetable (
+ unk1 = 0, -- long
+ unk2 = 0, -- long, seems to store count, amount of sub blocks
+ unk3 = 0, -- long
+ offsets = #() -- addresses to sub blocks, which e.g. can store XTD or even nested XMD
+)
+
+fn RH2LH corrd = (
+ [corrd.x,-corrd.z,corrd.y]*mscale
+)
+
+fn readBEfloat fstream = (
+ bit.intAsFloat (bit.swapBytes (bit.swapBytes (readlong fstream #unsigned) 1 4) 2 3)
+)
+
+fn readBElong fstream = (
+ bit.swapBytes (bit.swapBytes (readlong fstream #unsigned) 1 4) 2 3
+)
+
+fn readBEshort fstream = (
+ bit.swapBytes (readshort fstream #unsigned) 1 2
+)
+
+fn getpadding num alignment = (
+ mod (alignment-(mod num alignment)) alignment
+)
+
+fn paddstring len instring = (
+ local i, str = ""
+ instring = instring as string
+ if instring.count <=len then (
+ for i = 1 to (len-instring.count) do (
+ str += "0"
+ )
+ str = (str+instring)
+ ) else (
+ for i = 1 to len do (
+ str+="0";str[i]=instring[i]
+ )
+ )
+ return str
+)
+
+fn readFixedString bstream fixedLen = (
+ local i, str = ""
+ for i = 1 to fixedLen do (
+ str += bit.intAsChar (ReadByte bstream #unsigned)
+ )
+ str
+)
+
+fn triangle_strip fstream count = (
+ global g
+ local face_add = 1, matid = 1, vertex_start = 0
+ local count, fa, fb, fc , x, y
+ local face_flip = true
+ local face_reset = true
+
+ x = 0; while x < count do (
+ x += 1
+ if face_reset == true then (
+ x += 2
+ face_reset = false
+ face_flip = false
+ append g.matid matid
+ fa = ((readBEshort fstream)-vertex_start) + face_add
+ fb = ((readBEshort fstream)-vertex_start) + face_add
+ fc = ((readBEshort fstream)-vertex_start) + face_add
+ if face_flip == true then (
+ append g.face [fa,fc,fb]; face_flip = false
+ ) else (
+ append g.face [fa,fb,fc]; face_flip = true
+ )
+ ) else (
+ fa = fb; fb = fc; fc = readBEshort fstream
+ if fc < 0xFFFF then (
+ fc -= vertex_start
+ fc += face_add
+ append g.matid matid
+ if face_flip == true then (
+ append g.face [fa,fc,fb]; face_flip = false
+ ) else (
+ append g.face [fa,fb,fc]; face_flip = true
+ )
+ ) else (
+ face_reset = true
+ )
+ )
+ )
+)
+
+fn buildObj objname = (
+ global g
+ local j, msh --,mats = copy g.matcount #nomap
+-- local faceValid = true
+-- j = 1; while j < g.face.count and faceValid == true do (
+-- if g.face[j][1] > g.position.count or g.face[j][1] < 0 do faceValid = false
+-- if g.face[j][2] > g.position.count or g.face[j][1] < 0 do faceValid = false
+-- if g.face[j][3] > g.position.count or g.face[j][1] < 0 do faceValid = false
+-- j += 1
+-- )
+-- if faceValid == false do (g.face = #(); print "Face Range Error")
+-- print g.position.count
+-- print g.face
+ if g.position.count > 0 do (
+ msh = mesh vertices:g.position tverts:g.uv_coordinate faces:g.face -- materialIDs:g.matid
+ msh.name = objname
+ msh.numTVerts = g.uv_coordinate.count
+ msh.displayByLayer = false
+ msh.backfacecull = on
+ buildTVFaces msh
+
+ for j = 1 to g.uv_coordinate.count do setTVert msh j g.uv_coordinate[j]
+ for j = 1 to g.face.count do setTVFace msh j g.face[j]
+ convertTo msh PolyMeshObject
+-- if g.matcount.count > 0 do (
+-- msh.material = multiMaterial numsubs:g.matcount.count
+-- sort mats
+-- for j = 1 to g.matcount.count do (
+-- msh.material.materialList[j].Diffuse = random (color 0 0 0) (color 255 255 255)
+-- msh.material.materialList[j].diffuseMap = Bitmaptexture fileName:("tex_"+(paddstring 3 (findItem mats g.matcount[j]))+".tga")
+-- )
+-- )
+ )
+ msh
+)
+
+fn writeDDSheader fstream texW texH texM texC = (
+ local texP = 0, i
+ writelong fstream 0x20534444 #unsigned -- File ID
+ writelong fstream 0x7C #unsigned -- Header Size
+ case texC of ( -- dwFlags
+ "DXT1": (
+ writelong fstream 0x00081007 #unsigned
+ texP = ((texW*texH)/0x02)
+ )
+ "DXT3": (
+ writelong fstream 0x00081007 #unsigned
+ texP = (texW*texH)
+ )
+ "DXT5": (
+ writelong fstream 0x00081007 #unsigned
+ texP = (texW*texH)
+ )
+ "ATI1": (
+ writelong fstream 0x000A1007 #unsigned
+ texP = ((texW*texH)/0x20)
+ )
+ "ATI2": (
+ writelong fstream 0x000A1007 #unsigned
+ texP = (texW*texH)
+ )
+ "P8": (
+ writelong fstream 0x000A1007 #unsigned
+ texP = ((texW*texH)/0x02)
+ )
+ "ARGB16": (
+ writelong fstream 0x00081007 #unsigned
+ texP = (((texW*texH)/0x8)*0x10)
+ )
+ "ARGB32": (
+ writelong fstream 0x00081007 #unsigned
+ texP = (((texW*texH)/0x4)*0x10)
+ )
+ )
+
+ writelong fstream texW #unsigned -- Texture Width
+ writelong fstream texH #unsigned -- Texture Height
+ writelong fstream texP #unsigned -- Pitch (#of bytes in a single row across the texture)
+ writelong fstream 0x00 #unsigned -- Image Depth? Not Used, for Image Volume
+ writelong fstream texM #unsigned -- Texture MIP Count
+ for i = 1 to 11 do (
+ writelong fstream 0x00 #unsigned
+ ) -- Reserved Space
+ writelong fstream 0x20 #unsigned -- Size of PIXEL_FORMAT info, always 32bytes;
+ case texC of (
+ "DXT1": (
+ writelong fstream 0x04;writelong fstream 0x31545844 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned
+ )
+ "DXT3": (
+ writelong fstream 0x04;writelong fstream 0x33545844 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned
+ )
+ "DXT5": (
+ writelong fstream 0x04;writelong fstream 0x35545844 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned
+ )
+ "ATI1": (
+ writelong fstream 0x04;writelong fstream 0x31495441 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned
+ )
+ "ATI2": (
+ writelong fstream 0x04;writelong fstream 0x32495441 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned
+ )
+ "P8": (
+ writelong fstream 0x20;writelong fstream 0x20203850 #unsigned
+ writelong fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00401008 #unsigned
+ )
+ "ARGB16": (
+ writelong fstream 0x41;writelong fstream 0x00000000 #unsigned
+ writelong fstream 0x10;writebyte fstream 0x00;writebyte fstream 0x0F;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0xF0;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x0F;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xF0;writebyte fstream 0x00
+ writebyte fstream 0x00;writelong fstream 0x00001000 #unsigned
+ )
+ "ARGB32": (
+ writelong fstream 0x41;writelong fstream 0x00000000 #unsigned
+ writelong fstream 0x20;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xFF
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0xFF;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0xFF;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00;writebyte fstream 0x00
+ writebyte fstream 0xFF;writelong fstream 0x00001000 #unsigned
+ )
+ )
+ for i = 1 to 4 do ( -- Reserved Space for CAPS
+ writelong fstream 0x00 #unsigned
+ )
+)
+
+fn getHeader = (
+ global f
+ local h = _header(), i = 0, p = ftell f
+ h.fileid = readFixedString f 3
+ h.filever = readbyte f #unsinged
+ h.unk1 = readFixedString f 4
+ h.unk2 = readBElong f
+ h.count = readBElong f
+ h.offsets = (
+ for i = 1 to h.count collect (
+ readBElong f + p
+ )
+ )
+ fseek f (getpadding (ftell f) 16) #seek_cur
+ h.sizes = (
+ for i = 1 to h.count collect (
+ readBElong f
+ )
+ )
+ fseek f (getpadding (ftell f) 16) #seek_cur
+ h
+)
+
+-- this function consumes 16 bytes from file's current position
+fn getSubHeader = (
+ global f
+ local s = _subheader()
+
+ if debugMsg == true do (format "parsing sub header at 0x%\n" (bit.intAsHex((ftell f) as integer)))
+ s.type = readBEshort f
+ s.string_index = readBEshort f
+ s.size = readBElong f
+ s.unk2 = readBElong f
+ s.unk3 = readBElong f
+ s
+)
+
+fn getTXD_header = (
+ global f
+ local t = _XTD_header(), p = ftell f
+ t.fileid = readFixedString f 3
+ t.vers = readbyte f #unsigned
+ t.unk1 = readFixedString f 4
+ t.offsets = (
+ for i = 1 to (readlong f #unsigned) collect (
+ readlong f #unsigned + p
+ )
+ )
+ t
+)
+
+fn dumpGFT spath = (
+ global f
+ local p = ftell f
+ local s, x
+ if dumpTex == true do (
+ if (readlong f #unsigned) == 0x00000501 and DDSconv == true then (
+ readBElong f
+ readBElong f
+ readBElong f
+ data_address = readBElong f + p
+ data_size = readBElong f
+ fmt = readbyte f #unsigned
+ fseek f 0x03 #seek_cur
+ readBElong f
+ w = readBEshort f
+ h = readBEshort f
+ fseek f data_address #seek_set
+ s = fopen spath "wb"
+ writeDDSheader s h w 0 (
+ case fmt of (
+ 0x85: ("ARGB32")
+ 0x86: ("DXT1")
+ 0x87: ("DXT3")
+ 0x88: ("DXT5")
+ 0xA7: ("DXT3")
+ default: (
+ format "New DDS Type: 0x%\n" (bit.intAsHex((fmt) as integer))
+ "DXT1"
+ )
+ )
+ )
+ for x = 1 to data_size do (
+ writebyte s (readbyte f #unsigned) #unsigned
+ )
+ fclose s
+ ) else (
+ fseek f -0x14 #seek_cur
+ data_size = readlong f #unsigned - 0x10
+ fseek f 0x0C #seek_cur
+ s = fopen (spath+".GFT") "wb"
+ for x = 1 to data_size do (
+ writebyte s (readbyte f #unsigned) #unsigned
+ )
+ fclose s
+ )
+ )
+)
+
+-- arg1 here is result of getTXD_header()
+fn getTXD hdr fpath = (
+ global f, tex
+ for i = 1 to hdr.offsets.count do (
+ fseek f hdr.offsets[i] #seek_set
+ size = readlong f #unsigned
+ type = readlong f #unsigned
+ unk1 = readBEshort f
+ unk2 = readBEshort f
+ unk3 = readBEshort f
+ unk4 = readBEshort f
+ if size > 0x10 do (
+ if debugMsg == true do print (fpath + "_tex_" + (paddstring 3 i) + ".dds")
+ if tex <= texn.count then (
+ dumpGFT((getFilenamePath fpath)+texn[tex] + ".dds")
+ ) else (
+ dumpGFT(fpath + "_tex_" + (paddstring 3 tex) + ".dds")
+ )
+ )
+ tex+=1
+ )
+)
+
+fn getType04 objname = (
+ global f
+ readBElong f
+ readBEshort f
+ readBEshort f
+ readBElong f
+ readBElong f
+
+ local pos = [(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ d = dummy()
+ d.position = (RH2LH(pos))
+ d.name = objname
+ d.showLinks = d.showLinksOnly = true
+ d
+)
+
+fn getType05 h = (
+ global f
+ local p = ftell f - 16
+ fseek f (p+h.size) #seek_set
+ for i = 1 to h.unk3 do (
+ p = ftell f
+ readBEshort f
+ readBEshort f
+ block_size = readBElong f
+ fseek f (p+block_size) #seek_set
+ )
+)
+
+fn getType07 strArray = ( -- materials data
+ global f
+ local p = ftell f
+ readBElong f
+ readBElong f
+ readBElong f
+ count = readBElong f
+
+ --if debugMsg == true do (format "Material Sub Block, read 1 long past count, now @ 0x%\n" (bit.intAsHex((ftell f) as integer)))
+
+ for i = 1 to count do (
+ p = ftell f
+ type = readBElong f
+ size = readBElong f
+ unk1 = readBElong f
+ unk2 = readBElong f
+ case type of (
+ 0x02: (
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ )
+ 0x03: (
+ readBElong f
+ readBElong f
+ readBElong f
+ readBElong f
+
+ --print strArray[idx]
+ )
+ 0x09: (
+ readBElong f
+ readBElong f
+ readBElong f
+ readBElong f
+ )
+ 0x0B: (
+ )
+ default : (
+ --if debugMsg == true do (format "Material Sub Block, Unknown Material Type @ 0x%\n" (bit.intAsHex((ftell f) as integer)))
+ )
+ )
+ fseek f (p + size) #seek_set
+ )
+)
+
+fn getType08 objname = ( -- geomety data
+ global f, g = _geometry()
+ local p = ftell f, getPos
+
+ unk01=readBElong f
+ unk02=readBElong f
+ unk03=readBElong f
+ unk04=readBElong f
+
+ bmin = [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+ bmax = [(readBEfloat f),(readBEfloat f),(readBEfloat f),(readBEfloat f)]
+
+ unk05=readBElong f
+ unk06=readBElong f
+ count1 = readBElong f
+ count2 = readBElong f
+
+ unk07=readBElong f
+ unk08=readBElong f
+ unk09=readBElong f
+ unk10=readBElong f
+
+-- if debugMsg == true do (
+-- format "Unknowns[%]:\t % % % % % % % % % %\n" \
+-- count1 unk01 unk02 unk03 unk04 unk05 \
+-- unk06 unk07 unk08 unk09 unk10
+-- )
+
+ for i = 1 to count2 do ( -- e.g. you would loop to grab faces then vertices and so on, see case statement
+ getPos = ftell f
+
+ readBElong f -- 0x000A0000
+ block_size = readBElong f
+ comp = readBElong f
+ datatype = readBElong f
+
+ readBElong f
+ count = readBElong f -- e.g. number of faces or vertices
+ readBElong f
+ readBElong f
+
+ case comp of (
+ 0x00: ( -- face
+ triangle_strip f count
+ )
+ 0x02: ( -- position
+ for i = 1 to count do (
+ append g.position (RH2LH([(readBEfloat f),(readBEfloat f),(readBEfloat f)]))
+ )
+ )
+ 0x03: ( -- colours
+ )
+ 0x04: ( -- normals
+ )
+ 0x05: ( -- UVs
+ for i = 1 to count do (
+ append g.uv_coordinate ([(readBEfloat f),1-(readBEfloat f),0])
+ )
+ )
+ 0x0B: ( -- Bone Indices
+-- for i = 1 to count do (
+-- b1 = readBEfloat f
+-- b2 = readBEfloat f
+-- b3 = readBEfloat f
+-- b4 = readBEfloat f
+-- )
+ )
+ 0x0C: ( -- Bone Weights
+-- for i = 1 to count do (
+-- b1 = readBEfloat f
+-- b2 = readBEfloat f
+-- b3 = readBEfloat f
+-- b4 = readBEfloat f
+-- )
+ )
+ default: (
+ format "Error Vertex Format Unsupported [%] @ 0x%\n" \
+ comp (bit.intAsHex((getPos) as integer))
+ )
+ )
+ fseek f (getPos + block_size) #seek_set
+ )
+
+ --print g.uv_coordinate.count
+ if g.uv_coordinate.count < g.position.count do (
+ for i = 1 to (g.position.count - g.uv_coordinate.count) do (
+ append g.uv_coordinate [0,0,0]
+ )
+ )
+
+ buildObj(objname)
+)
+
+fn getType21 = ( -- string data
+ global f
+ readstring f
+)
+
+-- called from getStuff()
+fn getStuffTable pos = (
+ global f
+ local t = _filetable()
+ t.unk1 = readBElong f
+ t.unk2 = readBElong f
+ t.unk3 = readBElong f
+ t.offsets = (
+ for i = 1 to t.unk2 collect (
+ readBElong f + pos
+ )
+ )
+ t
+)
+
+-- this function is called when 0x0 long magic is encounter in XMD file container
+-- arg1's position usually will be at "Bp" section here
+fn getStuff pos = (
+ global f
+ local p = ftell f, strArray = #(), boneArray = #(), subHeaderArray = #()
+ fseek f 0x80 #seek_cur -- FIX ME, NOTICE THAT IT SEEK EXTRA 80h FROM CURR POS
+
+ -- HEADER HERE DESCRIBES COUNTS FOR DATA BELOW
+ check = readlong f #unsigned
+ if check == 0x00007042 or check == 0x0000F041 or check == 0x0000C041 then ( -- check for "Bp" section
+ table = getStuffTable(pos)
+
+ -- seek to all sub blocks and parse their header solely to prefetch string array that will be used in next loop
+ for i = 1 to table.unk2 do (
+ fseek f table.offsets[i] #seek_set
+ sb = getSubHeader()
+ append subHeaderArray sb
+ if sb.type == 0x15 do (
+ append strArray (getType21())
+ )
+ )
+
+ for i = 1 to table.unk2 do (
+ fseek f (table.offsets[i] + 16) #seek_set
+ sb = subHeaderArray[i]
+ block_name = ""
+ if debugMsg == true do block_name += (i as string) + " "
+ if sb.string_index > 0 and sb.string_index <= strArray.count do (
+ block_name += strArray[(sb.string_index)] -- creates block names such as "1 Detail" or "3 mat_sitamichi00_sh"
+ )
+
+ case sb.type of (
+ 0x04: ( -- matrix?
+ if debugMsg == true do (format "Matrix? @ 0x%\n" (bit.intAsHex((table.offsets[i]) as integer)))
+ if impSkl == true do (
+ append boneArray (getType04(block_name))
+ if sb.unk2 > 0 and sb.unk2 <= boneArray.count do (
+ try (
+ boneArray[(boneArray.count)].parent = boneArray[(sb.unk2)]
+ )
+ catch (
+ if debugMsg == true do (
+ format "Illegal parent, possibly same node or ancestor node [Index:%(%) Parent:%]\n" \
+ boneArray.count sb.unk3 sb.unk2
+ )
+ )
+ )
+ )
+ )
+ 0x05: ( -- bounding box
+ if debugMsg == true do (format "Bounding Box? @ 0x%\n" (bit.intAsHex((table.offsets[i]) as integer)))
+ getType05(sb)
+ )
+ 0x07: ( -- materials
+ if debugMsg == true do (format "Material @ 0x%\n\tName: %\n" (bit.intAsHex((table.offsets[i]) as integer)) block_name)
+ getType07(strArray)
+ )
+ 0x08: ( -- geometry
+ if debugMsg == true do (format "Geometry @ 0x%\n" (bit.intAsHex((table.offsets[i]) as integer)))
+ if impMsh == true do (
+ getType08(block_name)
+ )
+ )
+ 0x0C: ( -- texture names?
+ if debugMsg == true do (format "Textures ? @ 0x%\n\tName: %\n" (bit.intAsHex((table.offsets[i]) as integer)) block_name)
+ append texn block_name
+ )
+ 0x11: ( -- IK Bone
+ if debugMsg == true do (format "IK Bone @ 0x%\n\tName: %\n" (bit.intAsHex((table.offsets[i]) as integer)) block_name)
+ )
+ 0x15: ( -- string data
+ )
+ default: (
+ format "SubBlock Not Supported [%] @ 0x%\n" \
+ sb.type (bit.intAsHex((table.offsets[i]) as integer))
+ )
+ )
+
+ ) -- end of sub block loop
+ ) else (
+ format "Error: Failed to seek to table\n"
+ )
+ if debugMsg == true do (
+ format "String Table\n"
+ for i = 1 to strArray.count do (
+ format "%:\t%\n" i strArray[i]
+ )
+ )
+)
+
+
+-- this fn reads first long of a file called magic and decides what to make of it
+-- GTF stores multiple headerless DDS image, some even are 8888:32bit
+fn readBinary filen = (
+ global f
+ local magic = readlong f #unsigned
+ fseek f -4 #seek_cur
+ case magic of (
+ 0x01444D58: ( -- XMD (Xtreme Model Data)
+ hdr = getHeader()
+ for d = 1 to hdr.count do (
+ -- seeks to an offset, grabs long and seeks back a long
+ fseek f hdr.offsets[d] #seek_set
+ filetype = readlong f #unsigned
+ fseek f hdr.offsets[d] #seek_set
+ case filetype of (
+ 0x00000000: ( -- usaully means we hit the 2 longs before X3D0037 section
+ getStuff(hdr.offsets[d])
+ )
+ 0x01444D58: ( -- nested XMD (Xtreme Model Data)
+ readBinary(filen)
+ )
+ 0x00445458: ( -- XTD (Xtreme Texture Data)
+ --getTXD( getTXD_header() )((getFilenamePath filen)+(getFilenameFile filen))
+ readBinary(filen)
+ )
+ default: (
+ format "Error: New Block Type [%] @ Address: 0x%\n" \
+ filetype (bit.intAsHex((hdr.offsets[d]) as integer))
+ )
+ )
+ )
+ )
+ 0x00445458: ( -- XTD (Xtreme Texture Data)
+ getTXD(getTXD_header())((getFilenamePath filen)+(getFilenameFile filen))
+ )
+ 0x00000501: ( -- GTF
+ dumpGFT((getFilenamePath filen)+(getFilenameFile filen)+"_tex_001.dds")
+ )
+ )
+)
+
+fn openFilen filen = (
+ global f
+ format "opening file %\n" filen
+ if filen != undefined and doesFileExist filen == true then (
+ try (fclose f) catch(gc())
+ f = fopen filen "rb"
+ if clearScene == true do (delete $*)
+
+ readBinary(filen)
+
+ if debugMsg == true do (format "last read @ 0x%\n" (bit.intAsHex((ftell f) as integer)))
+ fclose f
+ return true
+ ) else (
+ format "failed to open %\n" filen
+ return false
+ )
+)
+
+
+-- code execution starts here, first we clear listener window
+clearlistener()
+
+-- globals below are freely accessible
+if guiEnabled == false then (
+ local filen = ""
+
+ --filenames = stringstream ""
+ --format "D:\\MaxScript\\C1\\AREA_C1_ROAD_MDL_000.GRID\n" to:filenames
+ --for i = 1 to 2 do (
+ -- format "D:\\MaxScript\\C1\\AREA_C1_ROAD_MDL_%%\n" (formattedPrint i format:".3d" as string) ".GRID" to:filenames
+ --)
+ --seek filenames 0
+
+ --for i = 1 to 1 do (
+ -- filen = readLine filenames
+ -- openFilen(filen)
+ --)
+ openFilen("D:\\MaxScript\\C1\\AREA_11GO_BUIL_CUT_11GO_WAN_013.GRID")
+) else (
+ try (destroydialog PS3_WANGANM_IMPORTER) catch()
+ rollout PS3_WANGANM_IMPORTER "Wangan Midnight" (
+ group "Main" (
+ button btn1 "IMPORT" width:65 height:31 align:#center
+ label ls0 "" -- spacer
+ checkbox chk1 "Clear Scene " checked:true align:#center
+ checkbox chk3 "Import Mesh " checked:true align:#center
+ checkbox chk4 "Import Bones " checked:false align:#center
+ checkbox chk2 "Dump Textures" checked:false align:#center
+ checkbox chk5 "Convert to DDS" checked:false align:#center
+ )
+ group "About" (
+ hyperLink lb5 "Author: mariokart64n," address:"mailto:mario_kart64n@hotmail.com"
+ label lb8 " nfm aka fatalhalt" align:#left
+ label lb3 "Date: April 2015" align:#left
+ )
+ on chk1 changed theState do (
+ clearScene = theState
+ )
+ on chk2 changed theState do (
+ dumpTex = theState
+ )
+ on chk3 changed theState do (
+ impMsh = theState
+ )
+ on chk4 changed theState do (
+ impSkl = theState
+ )
+ on chk5 changed theState do (
+ DDSconv = theState
+ )
+ on PS3_WANGANM_IMPORTER open do (
+ chk1.checked = clearScene
+ chk2.checked = dumpTex
+ chk3.checked = impMsh
+ chk4.checked = impSkl
+ chk5.checked = DDSconv
+ )
+ on btn1 pressed do (
+ local filen_ = GetOpenFileName \
+ caption:"Select GRID File" \
+ types: "Wangan Midnight files (*.*)|*.*|"
+
+ if openFilen(filen_) == true do (
+ messagebox "Done!"
+ if debugMsg == true do (print texn)
+ )
+ )
+ )
+ createdialog PS3_WANGANM_IMPORTER
+)