From d216675c6b00f79d3ecf381c717286f48715a99c Mon Sep 17 00:00:00 2001 From: Kyle K Date: Tue, 21 Apr 2015 02:19:05 -0500 Subject: 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 --- README.md | 8 +- maxscript/wmn/credits.txt | 6 + maxscript/wmn/dds2gtf.exe | Bin 0 -> 147456 bytes maxscript/wmn/gtf2dds.exe | Bin 0 -> 147456 bytes maxscript/wmn/wmn.ms | 837 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 847 insertions(+), 4 deletions(-) create mode 100644 maxscript/wmn/credits.txt create mode 100644 maxscript/wmn/dds2gtf.exe create mode 100644 maxscript/wmn/gtf2dds.exe create mode 100644 maxscript/wmn/wmn.ms 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 Binary files /dev/null and b/maxscript/wmn/dds2gtf.exe differ diff --git a/maxscript/wmn/gtf2dds.exe b/maxscript/wmn/gtf2dds.exe new file mode 100644 index 0000000..858d38a Binary files /dev/null and b/maxscript/wmn/gtf2dds.exe 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 +) -- cgit v1.2.3