------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------
--                                                                                                                                      --
--                                                   Abjab's W3D Tools                                                                  --
--                                                                                                                                      --
--                                               By Eric Morin (AKA: Abjab)                                                             --
--                                                                                                                                      --
------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------


------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- GLOBALS
------------------------------------------------------------------------------------------------------- 


CurrentScreenWidth = systemTools.GetScreenWidth()
CurrentScreenHeight = systemTools.GetScreenHeight()
newInitText = ""

struct W3DInfo
(
	w3dName,
	fName,
	fStart,
	fSize
)


------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- IMPORT MACRO BUTTONS
------------------------------------------------------------------------------------------------------- 

fileIn ((getDir #maxroot) + "scripts\Abjab's-W3D-Tools.ms")

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- SET RENX/3DSMAX WINDOW TITLE
------------------------------------------------------------------------------------------------------- 

fn setW3DAppTitle=
(
	local fname = if maxFileName == "" then "Untitled" else maxFileName
	local str
	if (maxVersion())[1] == 4200 then (str = fname + " - RenX - Abjab's W3D Tools") else (str = fname + " - 3ds max - Abjab's W3D Tools")
	cui.setAppTitle str
)

setW3DAppTitle()

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- INIT HELPER DIALOG (FOR RENX ONLY)
------------------------------------------------------------------------------------------------------- 

rollout TmpInitUpdateDlg "Temporary Dialog For W3D-Importer.ini Update" width:600 height:500 silentErrors:false
(
	groupBox NoteGroup "Note:" width:592 height:110 pos:[4,4]
	label Str1 "  Gmax script does not allow file writing, so I can't update the ini file.  Changes made in the" pos:[40,25]
	label Str2 "preferences will remains effective untill Gmax is closed. That is unless you replace the" pos:[40,41]
	label Str3 "content of W3D-Importer.ini by the text bellow, simply copy and paste this text over the text in the ini file." pos:[40,57]
	label Str4 "  Also make sure you select everything since Gmax does not have scroll bars for text boxes :(" pos:[40,89]
	edittext newInitFile text:newInitText width:596 height:380 pos:[0,120]

	fn Open=
	(
		createDialog TmpInitUpdateDlg style:#(#style_titlebar, #style_sysmenu) \
			pos:[(CurrentScreenWidth / 2) - 300, (CurrentScreenHeight / 2) - 250] modal:true
	)
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- INIT STRUCTURE
------------------------------------------------------------------------------------------------------- 

struct W3D_Importer_Init
(
	ImporterInitFile = getdir #maxroot + "\Plugcfg\W3D-Importer.ini",
	Initialized = false,
	InitStream,
	FoldersList = #(),
	W3DFolders = #(),
	TexturesFolders = #(),
	BoneShape,
	BoneSize,
	BoneColor,
	ProxyShape,
	ProxySize,
	ProxyColor,
	AggregateShape,
	AggregateSize,
	AggregateColor,
	DazzleShape,
	DazzleSize,
	DazzleColor,
	CreateMeshesBones,
	DefaultFolders,
	
	fn open=
	(
		if doesFileExist ImporterInitFile then
		(
			InitStream = openFile ImporterInitFile
			return true;
		)
		else return false;
	),

	fn close=
	(
		fclose InitStream
	),
	
	fn restoreDefaults=
	(
		BoneShape = 1
		BoneSize = 0.4
		BoneColor = (color 0 0 255)
		ProxyShape = 2
		ProxySize = 1.0
		ProxyColor = (color 255 255 0)
		AggregateShape = 3
		AggregateSize = 1.0
		AggregateColor = (color 255 155 247)
		DazzleShape = 4
		DazzleSize = 1.0
		DazzleColor = (color 255 0 0)
		CreateMeshesBones = false
	),

	fn ColorToString val=
	(
		val = val as color
		local r = (val.r as integer) as string
		local g = (val.g as integer) as string
		local b = (val.b as integer) as string
		local str = r + "," + g + "," + b

		str
	),

	fn valToShape val=
	(
		case val of
		(
			1: return "box";
			2: return "pyramid";
			3: return "cone";
			4: return "sphere";
		)
	),

	fn NewLine=
	(
		newInitText = newInitText + (bit.intAsChar 13) + (bit.intAsChar 10)
	),

	fn AddLine str=
	(
		newInitText = newInitText + str
		NewLine()
	),

	fn UpdateInitFile=
	(
		AddLine "[W3D_Importer]"
		AddLine ("BoneShape=" + ValToShape BoneShape)
		AddLine ("BoneSize=" + BoneSize as string)
		AddLine ("BoneColor=" + ColorToString BoneColor)
		AddLine ("ProxyShape=" + ValToShape ProxyShape)
		AddLine ("ProxySize=" + ProxySize as string)
		AddLine ("ProxyColor=" + ColorToString ProxyColor)
		AddLine ("AggregateShape=" + ValToShape AggregateShape)
		AddLine ("AggregateSize=" + AggregateSize as string)
		AddLine ("AggregateColor=" + ColorToString AggregateColor)
		AddLine ("DazzleShape=" + ValToShape DazzleShape)
		AddLine ("DazzleSize=" + DazzleSize as string)
		AddLine ("DazzleColor=" + ColorToString DazzleColor)
		AddLine ("CreateMeshesBones=" + ( if CreateMeshesBones then "1" else "0"))
		AddLine ("DefaultFolders=" + FoldersList[DefaultFolders])
		NewLine()

		for i = 1 to FoldersList.count do
		(
			if i == 7 do
			(
				AddLine "[Custom Folders List]"
				for j = 7 to FoldersList.count do AddLine ((j-6) as string + "=" + FoldersList[j])
				NewLine()
			)

			AddLine ("[" + FoldersList[i] + "]")
			AddLine ("W3DPath=" + W3DFolders[i])
			AddLine ("TexturesPath=" + TexturesFolders[i])
			NewLine()
		)

		TmpInitUpdateDlg.open()
		edit ImporterInitFile
		newInitText = ""
	),

	fn init=
	(
		if Initialized then return false;

		local Shapes = #("box", "pyramid", "cone", "sphere")
		local val
		local tmpRGB

		FoldersList = #("C&C Renegade Game Folder", "Earth & Beyond Game Folder", "C&C Generals Game Folder", \
						"C&C Generals ZERO:HOUR Game Folder", "Battle For Middle Earth Game Folder", \
						"Battle For Middle Earth II Game Folder")

		local i = 7
		while val != "" do
		(
			val = getINISetting ImporterInitFile "Custom Folders List" ((i-6) as string)
			if val != "" do FoldersList[i] = val
			i += 1
		)

		if FoldersList[7] == undefined do
		(
			FoldersList[7] = "Default Folder"
			W3DFolders[7] = "K:\\gmax\\w3d"
			TexturesFolders[7] = "K:\\gmax\\textures"
		)

		for i = 1 to FoldersList.count do
		(
			W3DFolders[i]= getINISetting ImporterInitFile FoldersList[i] "W3DPath"
			TexturesFolders[i]= getINISetting ImporterInitFile FoldersList[i] "TexturesPath"
		)
			
		val = getINISetting ImporterInitFile "W3D_Importer" "DefaultFolders"
		if (i = findItem FoldersList val) > 0 then DefaultFolders = i else DefaultFolders = 7

		val = getINISetting ImporterInitFile "W3D_Importer" "BoneShape"
		if val != undefined then BoneShape = findItem Shapes val else BoneSape = 2
		val = getINISetting ImporterInitFile "W3D_Importer" "BoneSize"
		if val != undefined then BoneSize = val as float else BoneSize = 0.4
		val = getINISetting ImporterInitFile "W3D_Importer" "BoneColor"
		if val != undefined then
		(
			tmpRGB = filterString val ","
			BoneColor = color (tmpRGB[1] as float) (tmpRGB[2] as float) (tmpRGB[3] as float)
		)
		else BoneColor = (color 0 0 255)

		val = getINISetting ImporterInitFile "W3D_Importer" "ProxyShape"
		if val != undefined then ProxyShape = findItem Shapes val else ProxyShape = 1
		val = getINISetting ImporterInitFile "W3D_Importer" "ProxySize"
		if val != undefined then ProxySize = val as float else ProxySize = 1.0
		val = getINISetting ImporterInitFile "W3D_Importer" "ProxyColor"
		if val != undefined then
		(
			tmpRGB = filterString val ","
			ProxyColor = color (tmpRGB[1] as float) (tmpRGB[2] as float) (tmpRGB[3] as float)
		)
		else ProxyColor = (color 255 255 0)

		val = getINISetting ImporterInitFile "W3D_Importer" "AggregateShape"
		if val != undefined then AggregateShape = findItem Shapes val else AggregateShape = 3
		val = getINISetting ImporterInitFile "W3D_Importer" "AggregateSize"
		if val != undefined then AggregateSize = val as float else AggregateSize = 1.0
		val = getINISetting ImporterInitFile "W3D_Importer" "AggregateColor"
		if val != undefined then
		(
			tmpRGB = filterString val ","
			AggregateColor = color (tmpRGB[1] as float) (tmpRGB[2] as float) (tmpRGB[3] as float)
		)
		else AggregateColor = (color 255 155 247)

		val= getINISetting ImporterInitFile "W3D_Importer" "DazzleShape"
		if val != undefined then DazzleShape = findItem Shapes val else DazzleShape = 4
		val = getINISetting ImporterInitFile "W3D_Importer" "DazzleSize"
		if val != undefined then DazzleSize = val as float else DazzleSize = 1.0
		val = getINISetting ImporterInitFile "W3D_Importer" "DazzleColor"
		if val != undefined then
		(
			tmpRGB = filterString val ","
			DazzleColor = color (tmpRGB[1] as float) (tmpRGB[2] as float) (tmpRGB[3] as float)
		)
		else DazzleColor = (color 255 0 0)

		val = getINISetting ImporterInitFile "W3D_Importer" "CreateMeshesBones"
		if val != undefined then CreateMeshesBones = ((val as integer) == 1) else CreateMeshesBones = false

		Initialized = true
	)
)

W3DImporterInit = W3D_Importer_Init()

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- FLAGS HELPER DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DFlagsHelper "W3D Flags Helper Tool" width:248 height:438 silentErrors:false
(
	local DazzleTypes = #("   ---  Dazzle Type  ---")
	local WWSkinNames = #("  -- Select WWSkin --")
	local SkinMeshNames = #("    --- Select Mesh ---")
	local SkinBoneNames = #("    --- Select Bone ---")
	local WWSkinsArray = #(), SkinMeshesArray = #(), SkinBonesArray = #()
	local CurrentWWSkin, CurrentSkinMesh, CurrentSkinBone
	local Initialized = false, Opened = True

	groupBox ExportOptions "Select By Object Export Options:" pos:[4,9] width:237 height:77
	button beBone "Export Transform (Bone)" pos:[48,29] width:150
	button beGeometry "Export Geometry" pos:[48,54] width:150

	groupBox GeometryOptions "Select By Geometry Options:" pos:[4,96] width:237 height:227
	button bgNormal "Normal" pos:[13,116] width:100
	button bgCamAl "Cam-Parallel" pos:[13,141] width:100
	button bgCamOr "Cam-Orient" pos:[13,166] width:100
	button bgAABox "AABox" pos:[13,191] width:100
	button bgOBBox "OBBox" pos:[13,216] width:100
	button bgNull "Null (LOD)" pos:[13,241] width:100
	button bgAgg "Aggregate" pos:[13,266] width:100
	button bgDazzle "Dazzle" pos:[13,291] width:79
	button bgSide "2Side" pos:[132,116] width:100
	button bgHide "Hide" pos:[132,141] width:100
	button bgZNm "ZNm" pos:[132,166] width:100
	button bgAlpha "VAlpha" pos:[132,191] width:100
	button bgShadow "Shadow" pos:[132,216] width:100
	button bgShatter "Shatter" pos:[132,241] width:100
	button bgNPatch "NPatch" pos:[132,266] width:100
	dropdownlist lgDazType pos:[100,291] width:133 items:DazzleTypes

	groupBox CollisionOptions "Select By Collision Options:" pos:[4,333] width:237 height:102
	button bcPhys "Physical" pos:[13,353] width:100
	button bcProj "Projectile" pos:[13,378] width:100
	button bcVhcl "Vehicle" pos:[13,403] width:100
	button bcVIS "VIS" pos:[132,353] width:100
	button bcCam "Camera" pos:[132,378] width:100

	groupBox WWSkinsSetup "WWSkins Setup" pos:[249,9] width:272 height:200 enabled:false
	label lblWWSkins "WWSkins:" pos:[257,31] align:#left enabled:false
	dropdownlist dlWWSkins pos:[380,29] width:132 items:WWSkinNames enabled:false
	button bSetSkinBones "Set WWSkin Bones List" pos:[294,60] width:180 enabled:false
	label lblSkinMeshes "Meshes:" pos:[257,94] align:#left enabled:false
	dropdownlist dlSkinMeshes pos:[380,92] width:132 items:SkinMeshNames enabled:false
	label lblVertices "Select Vertices for bone:" pos:[257,120] align:#left enabled:false
	dropdownlist dlVertBones pos:[380,118] width:132 items:SkinBoneNames enabled:false

	fn WWSkinInit=
	(
		WWSkinsSetup.enabled = true
		lblWWSkins.enabled = true
		dlWWSkins.enabled = true
		bSetSkinBones.enabled = true
		lblSkinMeshes.enabled = true
		lblVertices.enabled = true

		for i = 1 to WWSkinsArray.count by 3 do
		(
			local skinIndex = (i + 2) / 3
			append WWSkinNames WWSkinsArray[i].name
			for j = 1 to SkinMeshesArray.count by 2 do if SkinMeshesArray[j] == skinIndex do append WWSkinsArray[i+2] SkinMeshesArray[j+1]
		)
		dlWWSkins.items = WWSkinNames
	)

	fn init=
	(
		if Initialized do return false

		if objects.count == 0 do
		(
			for c in W3DFlagsHelper.controls do c.enabled = false
			return false
		)

		local foundWWSkin = false

		for o in objects do
		(
			local dazType = getAppData o 0x00100000
--			local SkinID = getUserProp o "WWSkin"
--			local BoneID = getAppData o 0x00200000
--			local BoneLOD = getAppData o 0x00300000

			if dazType != undefined do
				if findItem DazzleTypes dazType == 0 do append DazzleTypes dazType

--			if SkinID != undefined do join SkinMeshesArray #(SkinID, o) 
--			if BoneLOD != undefined do join SkinBonesArray #(BoneID, BoneLOD, o)

/*
			if classOf o == WWSkinSpaceWarp do
			(
				local SkinBones = execute (getUserProp o "Bones")
				join WWSkinsArray #(o, SkinBones, #())
				foundWWSkin = true
			)
*/
		)

		lgDazType.items = DazzleTypes
		-- if foundWWSkin do WWSkinInit()
		Initialized = true
		Opened = true
	)

	fn Open=
	(
		createDialog W3DFlagsHelper style:#(#style_titlebar, #style_minimizebox, #style_sysmenu) \
			pos:[(CurrentScreenWidth / 2) - 300, (CurrentScreenHeight / 2) - 200]

		init()
		setFocus W3DFlagsHelper
	)

	fn getDazzlesByType type=
	(
		disableSceneRedraw()
		clearSelection()
		for o in objects where getAppData o 0x00100000 == type do selectmore o
		enableSceneRedraw()
	)

	fn getNodesByType W3DType=
	(
		disableSceneRedraw()
		clearSelection()
		for o in objects where (getAppData o 0x01000000) != Undefined do
		(
			local type = bit.charAsInt (getAppData o 0x01000000)
			if bit.and W3DType type == W3DType do selectmore o
		)
		enableSceneRedraw()
	)

	fn getNodesByFlag flag:0x00000000 mask:0xffffffff=
	(
		disableSceneRedraw()
		clearSelection()
		for o in objects where (getAppData o 0x02000000) != Undefined do
		(
			local maskedFlag = bit.and ((getAppData o 0x02000000) as integer) mask
			if bit.and maskedFlag flag == flag do selectmore o
		)
		enableSceneRedraw()
	)

	fn getWWskin type val=
	(
		max modify mode

		case type of
		(
			"WWSkin":
			(
				if val == 1 then
				(
					clearSelection()
					bSetSkinBones.enabled = false
					dlSkinMeshes.selection = 1
					dlSkinMeshes.enabled = false
					dlVertBones.selection = 1
					dlVertBones.enabled = false

					CurrentSkinMesh = 1
					CurrentSkinBone = 1
				)
				else
				(
					local skinIndex = (3 * (val-1)) - 2
					select WWSkinsArray[skinIndex]

					if val == CurrentWWSkin do return false

					SkinMeshNames = #("    --- Select Mesh ---")
					for m in WWSkinsArray[skinIndex+2] do append SkinMeshNames m.name

					bSetSkinBones.enabled = true
					dlSkinMeshes.items = SkinMeshNames
					dlSkinMeshes.selection = 1
					dlSkinMeshes.enabled = true
					dlVertBones.selection = 1
					dlVertBones.enabled = false

					CurrentWWSkin = val
				)
			)
			"Mesh":
			(
				if val == 1 then
				(
					clearSelection()
					dlVertBones.selection = 1
					dlVertBones.enabled = false

					CurrentSkinBone = 1
				)
				else
				(
					local meshArrayIndex = (3 * (CurrentWWSkin-1))
					local meshArray = WWSkinsArray[meshArrayIndex]
					local skinMesh = meshArray[val-1]
					local vertBones = execute (getUserProp skinMesh "SkinBones")
					modPanel.setCurrentObject skinMesh.modifiers[1]
					update skinMesh
					
					if val == CurrentSkinMesh do return false

					SkinBoneNames = #("    --- Select Bone ---")
					for i = 1 to SkinBonesArray.count by 3 do
					(
						if findItem vertBones SkinBonesArray[i] > 0 and SkinBonesArray[i+1] == CurrentWWSkin-2 do
							append SkinBoneNames SkinBonesArray[i+2].name
					)

					dlVertBones.items = SkinBoneNames
					dlVertBones.selection = 1
					dlVertBones.enabled = true

					CurrentSkinMesh = val
				)
			)
			"Verts":
			(
				subobjectLevel = 1
				if val == 1 then clearSelection()
				else
				(
					local meshArrayIndex = (3 * (CurrentWWSkin-1))
					local meshArray = WWSkinsArray[meshArrayIndex]
					local skinMesh = meshArray[CurrentSkinMesh-1]
					local MeshFile = getUserProp skinMesh "SkinFile"
					local vertsOffset = (getUserProp skinMesh "SkinOffset") as integer
					local boneID, vertSelection = #()

					format "Skinmesh = %\n" skinMesh.name
					if val == CurrentSkinBone do return false
					
					for i = 1 to SkinBonesArray.count by 3 do
					(
						if SkinBonesArray[i+2].name == dlVertBones.selected do
						(
							boneID = SkinBonesArray[i]
							exit;
						)
					)

					for i = 1 to MeshFile.count do if (bit.CharAsInt MeshFile[i]) == 1 do MeshFile[i] = " "

					vertStream = fopen MeshFile "rb"
					fseek vertStream vertsOffset #seek_set

					for i = 1 to skinMesh.numverts do
					(
						local b = ReadShort vertStream #unsigned 
						if b == boneID do append vertSelection i
						for i = 1 to 6 do ReadByte W3Dstream #unsigned
					)

					fclose vertStream
					CurrentSkinBone = val
				)
			)
		)
	)

	on	bgAABox	pressed 	do	getNodesByFlag	flag:0x00000001 mask:0x0000000f
	on	bgOBBox	pressed 	do	getNodesByFlag	flag:0x00000002 mask:0x0000000f
	on	bcPhys	pressed 	do	getNodesByFlag	flag:0x00000010 mask:0x00000ff0
	on	bcProj	pressed 	do	getNodesByFlag	flag:0x00000020 mask:0x00000ff0
	on	bcVIS		pressed 	do	getNodesByFlag	flag:0x00000040 mask:0x00000ff0
	on	bcCam		pressed 	do	getNodesByFlag	flag:0x00000080 mask:0x00000ff0
	on	bcVhcl	pressed 	do	getNodesByFlag	flag:0x00000100 mask:0x00000ff0
	on	bgHide	pressed 	do	getNodesByFlag	flag:0x00001000 mask:0x0000f000
	on	bgSide	pressed 	do	getNodesByFlag	flag:0x00002000 mask:0x0000f000
	on	bgShadow	pressed 	do	getNodesByFlag	flag:0x00008000 mask:0x0000f000
	on	bgNormal	pressed 	do	getNodesByFlag	flag:0x00000000 mask:0x00ff0000
	on	bgCamAl	pressed 	do	getNodesByFlag	flag:0x00010000 mask:0x00ff0000
	on	bgCamOr	pressed 	do	getNodesByFlag	flag:0x00060000 mask:0x00ff0000
	on	bgShatter	pressed 	do	getNodesByFlag	flag:0x10000000 mask:0xf0000000
	on	bgNPatch	pressed 	do	getNodesByFlag	flag:0x20000000 mask:0xf0000000
	on	beBone	pressed 	do	getNodesByType 	1
	on	beGeometry	pressed 	do	getNodesByType 	2
	on	bgDazzle	pressed 	do	getNodesByType 	4
	on	bgAgg		pressed 	do	getNodesByType 	8

	on	bgNull	pressed 	do	clearSelection()	-- No flags for Null
	on	bgZNm		pressed 	do	clearSelection()	-- No flags for ZNm
	on	bgAlpha	pressed 	do	clearSelection()	-- No flags for VAlpha

	on lgDazType selected val do if val > 1 then getDazzlesByType lgDazType.selected else clearSelection()

--	on dlWWSkins selected val do getWWSkin "WWSkin" val
--	on dlSkinMeshes selected val do getWWSkin "Mesh" val
--	on dlVertBones selected val do getWWSkin "Verts" val
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- PROGRESS BAR DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DImportProgressDlg "Working..." width:400 height:90 silentErrors:false
(
	label Stage "" pos:[13,20] width:250 align:#left
	progressBar Progress pos:[14,40] height:20 width:372 align:#left
	label Percent "0 %" pos:[195,67] width:50 align:#left

	local oldPercentDone

	fn resetProgress=
	(
		oldPercentDone = 0
		Progress.value = 0
		Percent.text = "0 %"
	)

	fn updateProgress val maxVal=
	(
		if (local percentDone = (val * 100) / maxVal) != oldPercentDone do
		(
			oldPercentDone = percentDone
			Progress.value = percentDone
			Percent.text = (percentDone as string + " %")
		)
	)

	fn Open=
	(
		createDialog W3DImportProgressDlg style:#(#style_titlebar) \
			pos:[(CurrentScreenWidth / 2) - 200, (CurrentScreenHeight / 2) - 100]

		resetProgress()
		setFocus W3DImportProgressDlg
	)

	fn Close=
	(
		destroyDialog W3DImportProgressDlg
	)
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- ABOUT DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DImportAboutDlg "About W3D Importer" width:230 height:60 silentErrors:false
(
	label appLabel "Abjab's W3D Tools v1.0"
	label byLabel "by"
	label authorLabel "Eric Morin"

	fn Open XYPos=
	(
		createDialog W3DImportAboutDlg style:#(#style_titlebar, #style_toolwindow, #style_sysmenu) \
			pos:[(XyPos[1] as integer) + 50, (XYPos[2] as integer) + 150] modal:true
	)
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- MERGE/NEW PROMPT DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DMergePrompt "Keep Current Scene ?" width:165 height:90 silentErrors:false
(
	button OKButton "OK" pos:[45,65] width:75
	radioButtons actionRadio labels:#( "Import as new scene", "Add to current scene") default:1 columns:1 pos:[23,20]

	fn Open=
	(
		createDialog W3DMergePrompt style:#(#style_titlebar) pos:[(CurrentScreenWidth / 2) - 150, (CurrentScreenHeight / 2) - 60] modal:true
	)

	on OKButton pressed do
	(
		if actionRadio.state == 1 then
		(
			destroyDialog W3DMergePrompt
			if getSaveRequired() do checkForSave()
			resetMaxFile #noPrompt
		)

		else destroyDialog W3DMergePrompt

	)
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- NEW FOLDER DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DNewFolder "New Folder" width:323 height:85 silentErrors:false
(
	local NewName

	edittext FolderName "Folder Name : " pos:[27,20] fieldWidth:195 text:"Custom Folder" align:#left
	button OKButton "OK" pos:[159,60] width:75
	button CancelButton "Cancel" pos:[240,60] width:75

	fn Open XYPos=
	(
		createDialog W3DNewFolder style:#(#style_titlebar, #style_sysmenu) \
			pos:[(XyPos[1] as integer) + 25, (XYPos[2] as integer) + 25] modal:true
	)

	on OKButton pressed do
	(
		if FolderName.text.count > 0 do
		(
			if findItem W3DImporterInit.FoldersList FolderName.text > 0 then
			(
				messagebox "Folder name already exist, please choose another name."
				FolderName.text = ""
			)
			else
			(
				NewName = FolderName.text
				destroyDialog W3DNewFolder
			)
		)
	)

	on CancelButton pressed do destroyDialog W3DNewFolder
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- SET PATHS DIALOG
------------------------------------------------------------------------------------------------------- 

rollout SetW3DPathsDlg "Set W3D Folders" width:482  height:210 silentErrors:false
(
	groupBox FoldersGroup "W3D Folders:" width:474 height:154 pos:[4,9]

	label FoldersNamesLbl "Folder Name: " pos:[14,33] align:#left
	dropdownlist FoldersNamesCombo pos:[90,30] width:300 align:#left
	button NewButton "New" pos:[400,29] width:70
	button DeleteButton "Delete" pos:[400,56] width:71

	label W3DFoldersLbl "W3D Path: " pos:[14,101] align:#left
	edittext W3DFoldersTxt pos:[86, 100] width:356
	button BrowseW3DButton "..." pos:[450,98] width:20
	label TexturesFoldersLbl "Textures Path: " pos:[14,131] align:#left
	edittext TexturesFoldersTxt pos:[86, 130] width:356
	button BrowseTexturesButton "..." pos:[450,128] width:20

	button OkButton "Ok" pos:[233,180] width:75
	button ApplyButton "Apply" pos:[314,180] width:75
	button CancelButton "Cancel" pos:[395,180] width:75

	fn init=
	(
		FoldersNamesCombo.items = W3DImporterInit.FoldersList
		FoldersNamesCombo.selection = 1
		W3DFoldersTxt.text = W3DImporterInit.W3DFolders[1]
		TexturesFoldersTxt.text = W3DImporterInit.TexturesFolders[1]
		ApplyButton.enabled = false
		DeleteButton.enabled = false
	)

	fn UpdateFolderPaths val=
	(
		W3DFoldersTxt.text = W3DImporterInit.W3DFolders[val]
		TexturesFoldersTxt.text = W3DImporterInit.TexturesFolders[val]
		ApplyButton.enabled = false
		if val > 5 then DeleteButton.enabled = true else DeleteButton.enabled = false
	)

	fn changePaths folder val=
	(
		ApplyButton.enabled = true
		case folder of
		(
			"W3D": W3DImporterInit.W3DFolders[val] = W3DFoldersTxt.text
			"Textures": W3DImporterInit.TexturesFolders[val] = TexturesFoldersTxt.text
		)
	)

	fn GetFolder folder=
	(
		local tmpPath = getSavePath caption:"Choose W3D Folder"

		if tmpPath != undefined do
		(
			case folder of
			(
				"W3D": W3DFoldersTxt.text = getFileNamePath tmpPath
				"Textures": TexturesFoldersTxt.text = getFileNamePath tmpPath
			)
			ApplyButton.enabled = true
		)	
	)

	fn ApplyChanges=
	(
		W3DImporterInit.UpdateInitFile()
		ApplyButton.enabled = false
	)

	fn deleteFolder=
	(
		local val = FoldersNamesCombo.selection
		if val > 5 do
		(
			deleteItem W3DImporterInit.FoldersList val
			deleteItem W3DImporterInit.W3DFolders val
			deleteItem W3DImporterInit.TexturesFolders val
			FoldersNamesCombo.items = W3DImporterInit.FoldersList
			FoldersNamesCombo.selection = 1
			ApplyButton.enabled = true
			DeleteButton.enabled = false
		) 
	)
	
	fn newFolder=
	(
		W3DNewFolder.open (getDialogPos SetW3DPathsDlg)
		local newName = W3DNewFolder.NewName

		if newName != undefined then
		(
			local tmpArray = FoldersNamesCombo.items
			append tmpArray newName
			FoldersNamesCombo.items = tmpArray
			FoldersNamesCombo.selection = tmpArray.count
			append W3DImporterInit.W3DFolders "K:\\gmax\\w3d"
			append W3DImporterInit.TexturesFolders "K:\\gmax\\textures"
			W3DFoldersTxt.text = W3DImporterInit.W3DFolders[tmpArray.count]
			TexturesFoldersTxt.text = W3DImporterInit.TexturesFolders[tmpArray.count]
			ApplyButton.enabled = true
			DeleteButton.enabled = true
		)
	)

	fn Open=
	(
		createDialog SetW3DPathsDlg style:#(#style_titlebar, #style_minimizebox, #style_sysmenu) \
			pos:[(CurrentScreenWidth / 2) - 300, (CurrentScreenHeight / 2) - 200]

		init()
		setFocus SetW3DPathsDlg 
	)

	on NewButton pressed do newFolder()
	on DeleteButton pressed do deleteFolder()

	on FoldersNamesCombo selected val do UpdateFolderPaths val

	on W3DFoldersTxt changed val do changePaths "W3D" FoldersNamesCombo.selection
	on TexturesFoldersTxt changed val do changePaths "Textures" FoldersNamesCombo.selection

	on BrowseW3DButton pressed do GetFolder "W3D"
	on BrowseTexturesButton pressed do GetFolder "Textures"

	on OkButton pressed do
	(
		if ApplyButton.enabled do ApplyChanges()
		destroyDialog SetW3DPathsDlg
	)

	on CancelButton pressed do destroyDialog SetW3DPathsDlg
	on ApplyButton pressed do ApplyChanges()
	
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- PREFERENCES DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DPreferences "W3D Importer Preferences" width:418 height:400 silentErrors:false
(
	local ProfilesSettings = #()

	groupBox Settings "Settings:" width:410 height:267 pos:[4,9]

	label bShapeLabel "Bones Shape :" pos:[18,30] align:#left
	dropdownlist bShapeCombo pos:[95,27] width:81 height:6 align:#left
	edittext bSizeEdit "Bones Size : " pos:[29,60] fieldWidth:80 align:#left
	colorpicker bColorPick "Bones Color : " pos:[25,87] fieldWidth:80 title:"Bones Color" align:#left

	label pShapeLabel "Proxies Shape :" pos:[14,129] align:#left
	dropdownlist pShapeCombo pos:[95,126] width:81 height:6 align:#left
	edittext pSizeEdit "Proxies Size : " pos:[25,159] fieldWidth:80 align:#left
	colorpicker pColorPick "Proxies Color : " pos:[21,186] fieldWidth:80 title:"Proxies Color" align:#left

	label aShapeLabel "Aggregates Shape : " pos:[223,30] align:#left
	dropdownlist aShapeCombo pos:[324,27] width:81 height:6 align:#left
	edittext aSizeEdit "Aggregates Size : " pos:[234,60] fieldWidth:80 align:#left
	colorpicker aColorPick "Aggregates Color : " pos:[230,87] fieldWidth:80 title:"Aggregates Color" align:#left

	label dShapeLabel "Dazzles Shape : " pos:[240,129] align:#left
	dropdownlist dShapeCombo pos:[324,126] width:81 height:6 align:#left
	edittext dSizeEdit "Dazzles Size : " pos:[251,159] fieldWidth:80 align:#left
	colorpicker dColorPick "Dazzles Color : " pos:[247,186] fieldWidth:80 title:"Dazzles Color" align:#left

	checkbox MeshBonesCheck "Create Bones For Meshes Exported With Bone Transform" pos:[14,224]
	button RestoreButton "Restore" pos:[329,240] width:75

	groupBox W3DPathGroup "Default W3D Folder:" width:410 height:57 pos:[4,285]

	dropdownlist DefaultFoldersCombo pos:[14,306] width:310 align:#left
	button SetPathsButton "Set Paths..." pos:[329,306] width:75

	button OkButton "OK" pos:[173,360] width:75
	button ApplyButton "Apply" pos:[254,360] width:75
	button CancelButton "Cancel" pos:[335,360] width:75

	fn UpdateFromIni restore:false=
	(
		if restore do W3DImporterInit.restoreDefaults
		
		bShapeCombo.selection = W3DImporterInit.BoneShape
		bSizeEdit.text = W3DImporterInit.BoneSize as string
		bColorPick.color = W3DImporterInit.BoneColor
		pShapeCombo.selection = W3DImporterInit.ProxyShape
		pSizeEdit.text = W3DImporterInit.ProxySize as string
		pColorPick.color = W3DImporterInit.ProxyColor
		aShapeCombo.selection = W3DImporterInit.AggregateShape
		aSizeEdit.text = W3DImporterInit.AggregateSize as string
		aColorPick.color = W3DImporterInit.AggregateColor
		dShapeCombo.selection = W3DImporterInit.DazzleShape
		dSizeEdit.text = W3DImporterInit.DazzleSize as string
		dColorPick.color = W3DImporterInit.DazzleColor
		MeshBonesCheck.checked = W3DImporterInit.CreateMeshesBones

		ApplyButton.enabled = restore
	)

	fn UpdateFoldersFromIni=
	(
		DefaultFoldersCombo.items = W3DImporterInit.FoldersList
		DefaultFoldersCombo.selection = W3DImporterInit.DefaultFolders
	)

	fn UpdateSettings controlChanged val=
	(
		case controlChanged of
		(
			"BoneShape": W3DImporterInit.BoneShape = val
			"BoneSize": W3DImporterInit.BoneSize = val as float
			"BoneColor": W3DImporterInit.BoneColor = val
			"ProxyShape": W3DImporterInit.ProxyShape = val
			"ProxySize": W3DImporterInit.ProxySize = val as float
			"ProxyColor": W3DImporterInit.ProxyColor = val
			"AggregateShape": W3DImporterInit.AggregateShape = val
			"AggregateSize": W3DImporterInit.AggregateSize = val as float
			"AggregateColor": W3DImporterInit.AggregateColor = val
			"DazzleShape": W3DImporterInit.DazzleShape = val
			"DazzleSize": W3DImporterInit.DazzleSize = val as float
			"DazzleColor": W3DImporterInit.DazzleColor = val
			"MeshesBones": W3DImporterInit.CreateMeshesBones = val
			"DefaultFolders": W3DImporterInit.DefaultFolders = val
		)

		ApplyButton.enabled = true
	)

	fn ApplyChanges=
	(
		W3DImporterInit.UpdateInitFile()
		ApplyButton.enabled = false
	)

	fn init=
	(
		local Shapes = #("Box", "Pyramid", "Cone", "Sphere")

		bShapeCombo.items = Shapes
		pShapeCombo.items = Shapes
		aShapeCombo.items = Shapes
		dShapeCombo.items = Shapes

		UpdateFromIni()
		UpdateFoldersFromIni()
	)

	fn Open XYPos=
	(
		createDialog W3DPreferences style:#(#style_titlebar, #style_sysmenu) \
			pos:[(XyPos[1] as integer) + 25, (XYPos[2] as integer) + 25]
		init()
		setFocus W3DPreferences
	)

	on bShapeCombo selected val do UpdateSettings "BoneShape" val
	on bSizeEdit changed val do UpdateSettings "BoneSize" val
	on bColorPick changed val do UpdateSettings "BoneColor" val

	on pShapeCombo selected val do UpdateSettings "ProxyShape" val
	on pSizeEdit changed val do UpdateSettings "ProxySize" val
	on pColorPick changed val do UpdateSettings "ProxyColor" val

	on aShapeCombo selected val do UpdateSettings "AggregateShape" val
	on aSizeEdit changed val do UpdateSettings "AggregateSize" val
	on aColorPick changed val do UpdateSettings "AggregateColor" val

	on dShapeCombo selected val do UpdateSettings "DazzleShape" val
	on dSizeEdit changed val do UpdateSettings "DazzleSize" val
	on dColorPick changed val do UpdateSettings "DazzleColor" val

	on MeshBonesCheck changed val do UpdateSettings "MeshesBones" val

	on RestoreButton pressed do UpdateFromIni restore:true

	on DefaultFoldersCombo selected val do UpdateSettings "DefaultFolders" val

	on SetPathsButton pressed do SetW3DPathsDlg.open()

	on OkButton pressed do
	(
		if ApplyButton.enabled do ApplyChanges()
		destroyDialog W3DPreferences
	)

	on CancelButton pressed do destroyDialog W3DPreferences
	on ApplyButton pressed do ApplyChanges()
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- MAIN W3D IMPORTER DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DImportDlg "W3D Importer V2.0" width:604 height:450 silentErrors:false
(
	local CurrentW3DPath
	local w3dFiles
	local dependencies

	label lblW3DFolder "Look in:" pos:[15,13] align:#left enabled:true
	dropdownlist W3DFolder pos:[65,10] width:410 items:W3DImporterInit.FoldersList enabled:true
	button SetPathsButton "Set Paths..." pos:[490,9] width:100
	
	groupBox W3DFilesGroup "W3D Files:" width:246 height:322 pos:[13,45]
	listBox W3DFilesList pos:[22,63] width:228 height:22 items:#()

	groupBox W3DProperties "Properties:" width:316 height:126 pos:[274,45]
	label NameProplbl "Name :" pos:[284,65]
	label NameProptxt "N/A" width:260 pos:[327,65] align:#left
	label TypeProplbl "Type :" pos:[284,85]
	label TypeProptxt "N/A" width:260 pos:[327,85] align:#left
	label SizeProplbl "Size :" pos:[284,105]
	label SizeProptxt "N/A" width:260 pos:[327,105] align:#left
	label FramesProplbl "Frames :" pos:[284,125]
	label FramesProptxt "N/A" width:260 pos:[327,125] align:#left
	button dumpListenerButton "Dump to Listener" pos:[362,143] width:140
--	button dumpListenerButton "Dump to Listener" pos:[461,147] width:120

	groupBox DependenciesGroup "Dependencies:" width:316 height:189 pos:[274,178]
	listBox DependenciesList pos:[283,196] width:298 height:10
	button checkDependenciesButton "Search Required Files Now..." pos:[287,339] width:290

	groupBox W3DFileLoc "" width:577 height:30 pos:[13,374]
	label PathProptxt "" pos:[21,385] width:565

	button ImportButton "Import" pos:[365,418] width:100
	button CancelButton "Cancel" pos:[480,418] width:100

	fn getChunkName chunkID=
	(
		local chunksEnum = #(#(0x00000000, "W3D_CHUNK_MESH"),
							 #(0x00000002, "W3D_CHUNK_VERTICES"),
							 #(0x00000003, "W3D_CHUNK_VERTEX_NORMALS"),
							 #(0x0000000C, "W3D_CHUNK_MESH_USER_TEXT"),
							 #(0x0000000E, "W3D_CHUNK_VERTEX_INFLUENCES"),
							 #(0x0000001F, "W3D_CHUNK_MESH_HEADER3"),
							 #(0x00000020, "W3D_CHUNK_TRIANGLES"),
							 #(0x00000022, "W3D_CHUNK_VERTEX_SHADE_INDICES"),
							 #(0x00000023, "W3D_CHUNK_PRELIT_UNLIT"),
							 #(0x00000024, "W3D_CHUNK_PRELIT_VERTEX"),
							 #(0x00000025, "W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS"),
							 #(0x00000026, "W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE"),
							 #(0x00000028, "W3D_CHUNK_MATERIAL_INFO"),
							 #(0x00000029, "W3D_CHUNK_SHADERS"),
							 #(0x0000002a, "W3D_CHUNK_VERTEX_MATERIALS"),
							 #(0x0000002b, "W3D_CHUNK_VERTEX_MATERIAL"),
							 #(0x0000002c, "W3D_CHUNK_VERTEX_MATERIAL_NAME"),
							 #(0x0000002d, "W3D_CHUNK_VERTEX_MATERIAL_INFO"),
							 #(0x0000002e, "W3D_CHUNK_VERTEX_MAPPER_ARGS0"),
							 #(0x0000002f, "W3D_CHUNK_VERTEX_MAPPER_ARGS1"),
							 #(0x00000030, "W3D_CHUNK_TEXTURES"),
							 #(0x00000031, "W3D_CHUNK_TEXTURE"),
							 #(0x00000032, "W3D_CHUNK_TEXTURE_NAME"),
							 #(0x00000033, "W3D_CHUNK_TEXTURE_INFO"),
							 #(0x00000038, "W3D_CHUNK_MATERIAL_PASS"),
							 #(0x00000039, "W3D_CHUNK_VERTEX_MATERIAL_IDS"),
							 #(0x0000003a, "W3D_CHUNK_SHADER_IDS"),
							 #(0x0000003b, "W3D_CHUNK_DCG"),
							 #(0x0000003c, "W3D_CHUNK_DIG"),
							 #(0x0000003e, "W3D_CHUNK_SCG"),
							 #(0x00000048, "W3D_CHUNK_TEXTURE_STAGE"),
							 #(0x00000049, "W3D_CHUNK_TEXTURE_IDS"),
							 #(0x0000004a, "W3D_CHUNK_STAGE_TEXCOORDS"),
							 #(0x0000004b, "W3D_CHUNK_PER_FACE_TEXCOORD_IDS"),
							 #(0x00000058, "W3D_CHUNK_DEFORM"),
							 #(0x00000059, "W3D_CHUNK_DEFORM_SET"),
							 #(0x0000005a, "W3D_CHUNK_DEFORM_KEYFRAME"),
							 #(0x0000005b, "W3D_CHUNK_DEFORM_DATA"),
							 #(0x00000080, "W3D_CHUNK_PS2_SHADERS"),
							 #(0x00000090, "W3D_CHUNK_AABTREE"),
							 #(0x00000091, "W3D_CHUNK_AABTREE_HEADER"),
							 #(0x00000092, "W3D_CHUNK_AABTREE_POLYINDICES"),
							 #(0x00000093, "W3D_CHUNK_AABTREE_NODES"),

							 #(0x00000100, "W3D_CHUNK_HIERARCHY"),
							 #(0x00000101, "W3D_CHUNK_HIERARCHY_HEADER"),
							 #(0x00000102, "W3D_CHUNK_PIVOTS"),
							 #(0x00000103, "W3D_CHUNK_PIVOT_FIXUPS"),

							 #(0x00000200, "W3D_CHUNK_ANIMATION"),
							 #(0x00000201, "W3D_CHUNK_ANIMATION_HEADER"),
							 #(0x00000202, "W3D_CHUNK_ANIMATION_CHANNEL"),
							 #(0x00000203, "W3D_CHUNK_BIT_CHANNEL"),

							 #(0x00000280, "W3D_CHUNK_COMPRESSED_ANIMATION"),
							 #(0x00000281, "W3D_CHUNK_COMPRESSED_ANIMATION_HEADER"),
							 #(0x00000282, "W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL"),
							 #(0x00000283, "W3D_CHUNK_COMPRESSED_BIT_CHANNEL"),

							 #(0x000002c0, "W3D_CHUNK_MORPH_ANIMATION"),
							 #(0x000002c1, "W3D_CHUNK_MORPHANIM_HEADER"),
							 #(0x000002c2, "W3D_CHUNK_MORPHANIM_CHANNEL"),
							 #(0x000002c3, "W3D_CHUNK_MORPHANIM_POSENAME"),
							 #(0x000002c4, "W3D_CHUNK_MORPHANIM_KEYDATA"),
							 #(0x000002c5, "W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA"),

							 #(0x00000300, "W3D_CHUNK_HMODEL"),
							 #(0x00000301, "W3D_CHUNK_HMODEL_HEADER"),
							 #(0x00000302, "W3D_CHUNK_NODE"),
							 #(0x00000303, "W3D_CHUNK_COLLISION_NODE"),
							 #(0x00000304, "W3D_CHUNK_SKIN_NODE"),
							 #(0x00000305, "W3D_CHUNK_HMODEL_AUX_DATA"),
							 #(0x00000306, "W3D_CHUNK_SHADOW_NODE"),

							 #(0x00000400, "W3D_CHUNK_LODMODEL"),
							 #(0x00000401, "W3D_CHUNK_LODMODEL_HEADER"),
							 #(0x00000402, "W3D_CHUNK_LOD"),

							 #(0x00000420, "W3D_CHUNK_COLLECTION"),
							 #(0x00000421, "W3D_CHUNK_COLLECTION_HEADER"),
							 #(0x00000422, "W3D_CHUNK_COLLECTION_OBJ_NAME"),
							 #(0x00000423, "W3D_CHUNK_PLACEHOLDER"),
							 #(0x00000424, "W3D_CHUNK_TRANSFORM_NODE"),

							 #(0x00000440, "W3D_CHUNK_POINTS"),

							 #(0x00000460, "W3D_CHUNK_LIGHT"),
							 #(0x00000461, "W3D_CHUNK_LIGHT_INFO"),
							 #(0x00000462, "W3D_CHUNK_SPOT_LIGHT_INFO"),
							 #(0x00000463, "W3D_CHUNK_NEAR_ATTENUATION"),
							 #(0x00000464, "W3D_CHUNK_FAR_ATTENUATION"),

							 #(0x00000500, "W3D_CHUNK_EMITTER"),
							 #(0x00000501, "W3D_CHUNK_EMITTER_HEADER"),
							 #(0x00000502, "W3D_CHUNK_EMITTER_USER_DATA"),
							 #(0x00000503, "W3D_CHUNK_EMITTER_INFO"),
							 #(0x00000504, "W3D_CHUNK_EMITTER_INFOV2"),
							 #(0x00000505, "W3D_CHUNK_EMITTER_PROPS"),
							 #(0x00000506, "OBSOLETE_W3D_CHUNK_EMITTER_COLOR_KEYFRAME"),
							 #(0x00000507, "OBSOLETE_W3D_CHUNK_EMITTER_OPACITY_KEYFRAME"),
							 #(0x00000508, "OBSOLETE_W3D_CHUNK_EMITTER_SIZE_KEYFRAME"),
							 #(0x00000509, "W3D_CHUNK_EMITTER_LINE_PROPERTIES"),
							 #(0x0000050a, "W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES"),
							 #(0x0000050b, "W3D_CHUNK_EMITTER_FRAME_KEYFRAMES"),
							 #(0x0000050c, "W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES"),

							 #(0x00000600, "W3D_CHUNK_AGGREGATE"),
							 #(0x00000601, "W3D_CHUNK_AGGREGATE_HEADER"),
							 #(0x00000602, "W3D_CHUNK_AGGREGATE_INFO"),
							 #(0x00000603, "W3D_CHUNK_TEXTURE_REPLACER_INFO"),
							 #(0x00000604, "W3D_CHUNK_AGGREGATE_CLASS_INFO"),

							 #(0x00000700, "W3D_CHUNK_HLOD"),
							 #(0x00000701, "W3D_CHUNK_HLOD_HEADER"),
							 #(0x00000702, "W3D_CHUNK_HLOD_LOD_ARRAY"),
							 #(0x00000703, "W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER"),
							 #(0x00000704, "W3D_CHUNK_HLOD_SUB_OBJECT"),
							 #(0x00000705, "W3D_CHUNK_HLOD_AGGREGATE_ARRAY"),
							 #(0x00000706, "W3D_CHUNK_HLOD_PROXY_ARRAY"),

							 #(0x00000740, "W3D_CHUNK_BOX"),

							 #(0x00000741, "W3D_CHUNK_SPHERE"),
							 #(0x00000742, "W3D_CHUNK_RING"),

							 #(0x00000750, "W3D_CHUNK_NULL_OBJECT"),

							 #(0x00000800, "W3D_CHUNK_LIGHTSCAPE"),
							 #(0x00000801, "W3D_CHUNK_LIGHTSCAPE_LIGHT"),
							 #(0x00000802, "W3D_CHUNK_LIGHT_TRANSFORM"),

							 #(0x00000900, "W3D_CHUNK_DAZZLE"),
							 #(0x00000901, "W3D_CHUNK_DAZZLE_NAME"),
							 #(0x00000902, "W3D_CHUNK_DAZZLE_TYPENAME"),

							 #(0x00000a00, "W3D_CHUNK_SOUNDROBJ"),
							 #(0x00000a01, "W3D_CHUNK_SOUNDROBJ_HEADER"),
							 #(0x00000a02, "W3D_CHUNK_SOUNDROBJ_DEFINITION"))

		for a in chunksEnum where a[1] == chunkID do return a[2];
		return "W3D_CHUNK_UNKNOWN";
	)

	fn getAnimChannelType val=
	(
		local animChannelType = #(#(0x00, "X Translation"),
								  #(0x01, "Y Translation"),
								  #(0x02, "Z Translation"),
								  #(0x03, "X Rotation"),
								  #(0x04, "Y Rotation"),
								  #(0x05, "Z Rotation"),
								  #(0x06, "Quaternation"),
								  #(0x07, "X Translation (Time Coded)"),
								  #(0x08, "Y Translation (Time Coded)"),
								  #(0x09, "Z Translation (Time Coded)"),
								  #(0x0a, "Quaternation (Time Coded)"),
								  #(0x0b, "X Translation (Adaptive Delta)"),
								  #(0x0c, "Y Translation (Adaptive Delta)"),
								  #(0x0d, "Z Translation (Adaptive Delta)"),
								  #(0x0e, "Quaternation (Adaptive Delta)"))

		for a in animChannelType where a[1] == val do return a[2];
		return "Unknown Animation Channel";
	)

	fn getBitChannelType val=
	(
		local bitChannelType = #(#(0x00, "Visibility"),
								 #(0x01, "Visibility (Time Coded)"))

		for a in bitChannelType where a[1] == val do return a[2];
		return "Unknown Bit Channel";
	)

	fn compareArrays a1 a2 valID:1=
	(
		if a1[valID] == a2[valID] then return 0;
		else return if findItem (sort #(a1[valID], a2[valID])) a1[valID] == 1 then -1 else 1;
	)

	fn compareW3DInfo n1 n2=
	(
		if n1.w3dName == n2.w3dName then return 0;
		else return if findItem (sort #(n1.w3dName, n2.w3dName)) n1.w3dName == 1 then -1 else 1;
	)

	fn toLower ch=
	(
		local upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		local lower = "abcdefghijklmnopqrstuvwxyz"
		local pos = findString upper ch

		if pos != undefined do ch = lower[pos]
		ch
	)
		
	fn getFileSizeString fSize=
	(
		if fSize < 1024 then return ((fSize as string) + " Bytes")
		else if fSize >= (1024*1024) then return (((fSize / (1024*1024)) as string) + " MB")
		else if fSize >= 1024 then return (((fSize / 1024) as string) + " KB")
	)


	fn ReadW3DNameLen W3Dstream ContainerName:false doubleLen:false=
	(
		local str = ""
		local containerStr = ""
		local len = if ContainerName or doubleLen then 32 else 16

		for i = 1 to len do
		(
			local ch = ReadByte W3Dstream #unsigned

			if ContainerName and (bit.intAsChar ch) == "." then
			(
				containerStr = str
				str = ""
			)
			else str += (bit.intAsChar ch)


			if ch == 0 then
			(
				fseek W3Dstream (len - i) #seek_cur
				exit
			)
		)

		if ContainerName then return #(str, containerStr)
		else return str
	)

	fn ReadNullTerminatedString W3Dstream=
	(
		local str = ""
		local ch = 1
		while ch != 0 do
		(
			ch = ReadByte W3Dstream #unsigned
			str += (bit.intAsChar ch)
		)

		str
	)

	fn ReadLongReversed W3Dstream=					-- convert (little indian / big indian) byte order
	(
			local long = ReadLong W3DStream #unsigned
			local a = bit.and long 0x000000ff
			local b = (bit.and long 0x0000ff00) /2^8
			local c = (bit.and long 0x00ff0000) /2^16
			local d = bit.and (long / 2^8) 0x00ffffff
			a = bit.shift a 24
			b = bit.shift b 16
			c = bit.shift c 8
			d = (bit.and d 0x00ff0000) /2^16

			return a+b+c+d
	)

	fn ReadVersion W3Dstream=
	(
		local Min = ReadShort W3Dstream #unsigned
		local Maj = ReadShort W3Dstream #unsigned
		return (Maj as string + "." + Min as string)
	)

	fn ReadPoint3 W3Dstream=
	(
		Local X = ReadFloat W3Dstream
		Local Y = ReadFloat W3Dstream
		Local Z = ReadFloat W3Dstream
		return [X, Y, Z]
	)

	fn ReadColor W3Dstream Alpha:false=
	(
		local R = ReadByte W3Dstream #unsigned
		local G = ReadByte W3Dstream #unsigned
		local B = ReadByte W3Dstream #unsigned
		local A = ReadByte W3Dstream #unsigned

		if Alpha then return (color R G B A) else return (color R G B)
	)

	fn ReadFloatRGBA W3Dstream=
	(
		local R = ReadFloat W3Dstream
		local G = ReadFloat W3Dstream
		local B = ReadFloat W3Dstream
		local A = ReadFloat W3Dstream
		return (color R G B A)
	)

	fn ReadEuler W3Dstream=
	(
		local X = ReadFloat W3Dstream
		local Y = ReadFloat W3Dstream
		local Z = ReadFloat W3Dstream
		return (eulerangles X Y Z)
	)

	fn ReadQuat W3Dstream=
	(
		local X = ReadFloat W3Dstream
		local Y = ReadFloat W3Dstream
		local Z = ReadFloat W3Dstream
		local W = ReadFloat W3Dstream
		return (quat X Y Z W)
	)

	fn ReadMatrix3 W3Dstream=
	(
		local x = ReadFloat W3DStream
		local y = ReadFloat W3DStream
		local z = ReadFloat W3DStream
		local Row0 = [x,y,z]
		x = ReadFloat W3DStream
		y = ReadFloat W3DStream
		z = ReadFloat W3DStream
		local Row1 = [x,y,z]
		x = ReadFloat W3DStream
		y = ReadFloat W3DStream
		z = ReadFloat W3DStream
		local Row2 = [x,y,z]
		x = ReadFloat W3DStream
		y = ReadFloat W3DStream
		z = ReadFloat W3DStream
		local Row3 = [x,y,z]
		return (matrix3 Row0 Row1 Row2 Row3)
	)

	fn CreateBone Type Name CenterPos=
	(
		local Bone, Shape, Size, Color
		local Settings = #()
		local index = (13 * CurrentProfile) - 12

		case Type of
		(
			"Bone":
			(
				Shape = W3DImporterInit.BoneShape
				Size = W3DImporterInit.BoneSize
				Color = W3DImporterInit.BoneColor
			)

			"Proxy":
			(
				Shape = W3DImporterInit.ProxyShape
				Size = W3DImporterInit.ProxySize
				Color = W3DImporterInit.ProxyColor
			)

			"Aggregate":
			(
				Shape = W3DImporterInit.AggregateShape
				Size = W3DImporterInit.AggregateSize
				Color = W3DImporterInit.AggregateColor
			)

			"Dazzle":
			(
				Shape = W3DImporterInit.DazzleShape
				Size = W3DImporterInit.DazzleSize
				Color = W3DImporterInit.DazzleColor
			)

			"Origin":
			(
				Shape = 1
				Size = 0.4
				CenterPos = [0.0,0.0,0.0]
				Color = [0,255,0]
			)
		)

		case Shape of
		(
			1: Bone = Box name:Name width:Size height:Size length:Size pos:(CenterPos - [0.0,0.0,(Size/2)]) pivot:CenterPos 
			2: Bone = Pyramid name:Name width:Size depth:Size height:Size pos:(CenterPos - [0.0,0.0,(Size/2)]) pivot:CenterPos
			3: Bone = Cone name:Name radius1:(Size/2) height:Size pos:(CenterPos - [0.0,0.0,(Size/2)]) pivot:CenterPos 
			4: Bone = Sphere name:Name radius:(Size/2) pos:CenterPos pivot:CenterPos 
		)

		Bone.wireColor = Color
		Bone.mapCoords = true

		Bone
	)

	fn getW3DBoneParent parentID lodID=
	(
		local parentW3DBone = 0

		for j = 1 to W3DBones.count by 6 do
		(
			if W3DBones[j+1] != parentID do continue

			if not CreateLODBones then
			(
				if W3DBones[j+3] != "Mesh" and W3DBones[j+4] == 0 then parentW3DBone = j
				else if W3DBones[j+3] == "Mesh" and W3DBones[j+4] == lodID then parentW3DBone = j
			)

			else if W3DBones[j+4] == lodID do parentW3DBone = j
		)

		parentW3DBone
	)

	fn ReadAnimVector W3Dstream isQuat:false=
	(
		if isQuat then return (ReadQuat W3Dstream)
		else return (ReadFloat W3Dstream)
	)

	fn getChunks w3dStream fStart fSize fOffset:0xffffffff ofID:0xffffffff=
	(
		local chunks = # ()
		if fOffset == 0xffffffff do fOffset = fStart
			
		while fOffset < (fStart + fSize) do
		(
			fseek w3dStream fOffset #seek_set
			local chunkID = ReadLong w3dStream #unsigned
			local size = (bit.and (ReadLong w3dStream #unsigned) 0x7fffffff)
			if ofID != 0xffffffff then if ofID == chunkID do return fOffset;
			else append chunks #((chunkID), fOffset)

			fOffset = (ftell w3dStream) + size
		)

		if ofID != 0xffffffff do return 0;
		return chunks
	)


------------------------------------------- W3D Chunks Structures Definition ---------------------------------------


	struct W3D_CHUNK
	(
		ID,
		Size,
		Start,
		FlagPresent,

		fn readHeader w3dStream=
		(
			ID = ReadLong w3dStream #unsigned
			Size = ReadLong w3dStream #unsigned
			if (bit.and Size 0x80000000) != 0 do FlagPresent = true
			Size = bit.and Size 0x7fffffff
			Start = ftell w3dStream
			return ID;
		)
	)

	struct W3D_CHUNK_MESH_HEADER																	-- 0x00000001
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MESH_HEADER]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTICES																		-- 0x00000002
	(
		chunk,								-- W3D_CHUNK()
		Position,

		fn readChunk w3dStream numVertices= ( Position = for i = 1 to numVertices collect(ReadPoint3 w3dStream) ),
		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_VERTICES]\n" to:dumpStream
			for i = 1 to Position.count do format "1:Vertex[%]:%\n" i Position[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_NORMALS																	-- 0x00000003
	(
		chunk,								-- W3D_CHUNK()
		Normal,

		fn readChunk w3dStream numVertices= ( Normal = for i = 1 to numVertices collect(ReadPoint3 w3dStream) ),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_VERTEX_NORMALS]\n" to:dumpStream
			for i = 1 to Normal.count do format "1:Normal[%]:%\n" i Normal[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_SURRENDER_NORMALS																-- 0x00000004
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SURRENDER_NORMALS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_TEXCOORDS																		-- 0x00000005
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TEXCOORDS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_SURRENDER_TRIANGLES															-- 0x00000009
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SURRENDER_TRIANGLES]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MESH_USER_TEXT																	-- 0x0000000c
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MESH_USER_TEXT]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_INFLUENCES																-- 0x0000000e
	(
		chunk,								-- W3D_CHUNK()
		BoneIndex,
		Pad = #(),

		fn readChunk w3dStream=
		(
			BoneIndex = ReadShort w3dStream #unsigned
			Pad = for i = 1 to 6 collect(ReadByte w3dStream #unsigned)
		),

		fn dumpChunk dumpStream= ( format "1:[W3D_CHUNK_VERTEX_INFLUENCES]\n1:BoneIndex:%\n" BoneIndex to:dumpStream )
	)

	struct W3D_CHUNK_MATERIALS2																		-- 0x00000014
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MATERIALS2]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MATERIALS3																		-- 0x00000015
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MATERIALS3]\n" to:dumpStream
		)
	)

	Struct W3D_CHUNK_MESH_HEADER3																	-- 0x0000001f
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Flags,
		Name,
		Container,
		NumTris,
		NumVert,
		NumMat,
		NumDam,
		SortLevel,
		PrelitVer,
		FutureCnt,
		VertexChan,
		FaceChan,
		MMin,
		MMax,
		SphCenter,
		SphRadius,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Flags = ReadLong w3dStream #unsigned
			Name = ReadW3DNameLen w3dStream
			Container = ReadW3DNameLen w3dStream
			NumTris = ReadLong w3dStream #unsigned
			NumVert = ReadLong w3dStream #unsigned
			NumMat = ReadLong w3dStream #unsigned
			NumDam = ReadLong w3dStream #unsigned
			SortLevel = ReadLong w3dStream #unsigned
			PrelitVer = ReadLong w3dStream #unsigned
			FutureCnt = ReadLong w3dStream #unsigned
			VertexChan = ReadLong w3dStream #unsigned
			FaceChan = ReadLong w3dStream #unsigned
			MMin = ReadPoint3 w3dStream
			MMax = ReadPoint3 w3dStream
			SphCenter = ReadPoint3 w3dStream
			SphRadius = ReadFloat w3dStream
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MESH_HEADER3]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:HierarchyName:%\n" Container to:dumpStream
			format "1:NumTris:%\n" NumTris to:dumpStream
			format "1:NumVert:%\n" NumVert to:dumpStream
			format "1:NumMat:%\n" NumMat to:dumpStream
			format "1:NumDam:%\n" NumDam to:dumpStream
			format "1:SortLevel:%\n" SortLevel to:dumpStream
			format "1:PrelitVer:%\n" PrelitVer to:dumpStream
			format "1:FutureCnt:%\n" FutureCnt to:dumpStream
			format "1:VertexChan:%\n" VertexChan to:dumpStream
			format "1:FaceChan:%\n" FaceChan to:dumpStream
			format "1:MMin:%\n" MMin to:dumpStream
			format "1:MMax:%\n" MMax to:dumpStream
			format "1:SphCenter:%\n" SphCenter to:dumpStream
			format "1:SphRadius:%\n" SphRadius to:dumpStream
		)
	)

	struct W3D_CHUNK_TRIANGLES																		-- 0x00000020
	(
		chunk,								-- W3D_CHUNK()
		TriIndices = #(),
		Flags = #(),
		Normal = #(),
		Dist = #(),

		fn readChunk w3dStream numTriangles=
		(
			for i = 1 to numTriangles do
			(
				Local v1 = ReadLong w3dStream #unsigned
				Local v2 = ReadLong w3dStream #unsigned
				Local v3 = ReadLong w3dStream #unsigned
				TriIndices[i] = [v1, v2, v3]
				Flags[i] = ReadLong w3dStream #unsigned
				Normal[i] = ReadPoint3 w3dStream
				Dist[i] = ReadFloat w3dStream
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TRIANGLES]\n" to:dumpStream
			for i = 1 to TriIndices.count do
			(
				format "1:Triangle[%].VertexIndices:%\n" i TriIndices[i] to:dumpStream
				format "1:Triangle[%].Attributes:%\n" i Flags[i] to:dumpStream
				format "1:Triangle[%].Normal:%\n" i Normal[i] to:dumpStream
				format "1:Triangle[%].Dist:%\n" i Dist[i] to:dumpStream
			)
		)
	)

	struct W3D_CHUNK_PER_TRI_MATERIALS																-- 0x00000021
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PER_TRI_MATERIALS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_SHADES_INDICES															-- 0x00000022
	(
		chunk,								-- W3D_CHUNK()
		Index,

		fn readChunk w3dStream numVertices= ( Index = for i = 1 to numVertices collect(ReadLong w3dStream #unsigned) ),
		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_VERTEX_SHADES_INDICES]\n" to:dumpStream
			for i = 1 to Index.count do format "1:Index[%]:%\n" i Index[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_PRELIT_UNLIT																	-- 0x00000023
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PRELIT_UNLIT]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_PRELIT_VERTEX																	-- 0x00000024
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PRELIT_VERTEX]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS														-- 0x00000025
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE													-- 0x00000026
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MATERIAL_INFO																	-- 0x00000028
	(
		chunk,								-- W3D_CHUNK()
		PassCount,
		VMaterialCount,
		ShaderCount,
		TextureCount,

		fn readChunk w3dStream=
		(
			PassCount = ReadLong w3dStream #unsigned
			VMaterialCount = ReadLong w3dStream #unsigned
			ShaderCount = ReadLong w3dStream #unsigned
			TextureCount = ReadLong w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MATERIAL_INFO]\n" to:dumpStream
			format "1:PassCount:%\n" PassCount to:dumpStream
			format "1:VMaterialCount:%\n" VMaterialCount to:dumpStream
			format "1:ShaderCount:%\n" ShaderCount to:dumpStream
			format "1:TextureCount:%\n" TextureCount to:dumpStream
		)
	)

	struct W3D_CHUNK_SHADERS																		-- 0x00000029
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SHADERS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MATERIAL_NAME															-- 0x0000002c
	(
		chunk,								-- W3D_CHUNK()
		Name,

		fn readChunk w3dStream= ( Name = ReadNullTerminatedString w3dStream ),
		fn dumpChunk dumpStream= ( format "3:[W3D_CHUNK_VERTEX_MATERIAL_NAME]\n3:Name:%\n" Name to:dumpStream )
	)

	struct W3D_CHUNK_VERTEX_MATERIAL_INFO															-- 0c0000002d
	(
		chunk,								-- W3D_CHUNK()
		Flags,
		Ambient,
		Diffuse,
		Specular,
		Emissive,
		Shininess,
		Opacity,
		Translucency,

		fn readChunk w3dStream=
		(
			Flags = ReadLong w3dStream #unsigned
			Ambient = ReadColor w3dStream
			Diffuse = ReadColor w3dStream
			Specular = ReadColor w3dStream
			Emissive = ReadColor w3dStream
			Shininess = ReadFloat w3dStream * 100
			Opacity = ReadFloat w3dStream * 100
			Translucency = ReadFloat w3dStream * 100
		),

		fn dumpChunk dumpStream=
		(
			format "3:[W3D_CHUNK_VERTEX_MATERIAL_INFO]\n" to:dumpStream
			format "3:Flags:%\n" Flags to:dumpStream
			format "3:Ambient:%\n" Ambient to:dumpStream
			format "3:Diffuse:%\n" Diffuse to:dumpStream
			format "3:Specular:%\n" Specular to:dumpStream
			format "3:Emissive:%\n" Emissive to:dumpStream
			format "3:Shininess:%\n" Shininess to:dumpStream
			format "3:Opacity:%\n" Opacity to:dumpStream
			format "3:Translucency:%\n" Translucency to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MAPPER_ARGS0															-- 0x0000002e
	(
		chunk,								-- W3D_CHUNK()
		Stage0MapperArgs,

		fn readChunk w3dStream= ( Stage0MapperArgs = ReadNullTerminatedString w3dStream ),
		fn dumpChunk dumpStream=
		(
			format "3:[W3D_CHUNK_VERTEX_MAPPER_ARGS0]\n" to:dumpStream
			local args = filterString Stage0MapperArgs ((bit.IntAsChar 0x0d) + (bit.IntAsChar 0x0a))
			for i = 1 to args.count do format "3:Stage0 Mapper Args:%\n" args[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MAPPER_ARGS1															-- 0x0000002f
	(
		chunk,								-- W3D_CHUNK()
		Stage1MapperArgs,

		fn readChunk w3dStream= ( Stage1MapperArgs = ReadNullTerminatedString w3dStream ),
		fn dumpChunk dumpStream=
		(
			format "3:[W3D_CHUNK_VERTEX_MAPPER_ARGS1]\n" to:dumpStream
			local args = filterString Stage1MapperArgs ((bit.IntAsChar 0x0d) + (bit.IntAsChar 0x0a))
			for i = 1 to args.count do format "3:Stage1 Mapper Args:%\n" args[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MATERIAL																-- 0x0000002b
	(
		chunk,								-- W3D_CHUNK()
		materialName,						-- W3D_CHUNK_VERTEX_MATERIAL_NAME()					0x0000002c
		materialInfo,						-- W3D_CHUNK_VERTEX_MATERIAL_INFO()					0c0000002d
		mapperArgs0,						-- W3D_CHUNK_VERTEX_MAPPER_ARGS0()					0x0000002e
		mapperArgs1,						-- W3D_CHUNK_VERTEX_MAPPER_ARGS1()					0x0000002f

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x002c: (materialName = (W3D_CHUNK_VERTEX_MATERIAL_NAME c)).readChunk w3dStream
					0x002d: (materialInfo = (W3D_CHUNK_VERTEX_MATERIAL_INFO c)).readChunk w3dStream
					0x002e: (mapperArgs0 = (W3D_CHUNK_VERTEX_MAPPER_ARGS0 c)).readChunk w3dStream
					0x002f: (mapperArgs1 = (W3D_CHUNK_VERTEX_MAPPER_ARGS1 c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_VERTEX_MATERIAL]\n" to:dumpStream
			if materialName != undefined do materialName.dumpChunk dumpStream
			if materialInfo != undefined do materialInfo.dumpChunk dumpStream
			if mapperArgs0 != undefined do mapperArgs0.dumpChunk dumpStream
			if mapperArgs1 != undefined do mapperArgs1.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MATERIALS																-- 0x0000002a
	(
		chunk,								-- W3D_CHUNK()
		vMaterial = #(),					-- W3D_CHUNK_VERTEX_MATERIAL()						0x0000002b

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				(local c = W3D_CHUNK()).readHeader w3dStream
				(vMaterial[vMaterial.count+1] = (W3D_CHUNK_VERTEX_MATERIAL c)).readChunk w3dStream
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_VERTEX_MATERIALS]\n" to:dumpStream
			for vMat in vMaterial do vMat.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_TEXTURE_INFO																	-- 0x00000033
	(
		chunk,								-- W3D_CHUNK()
		ID,

		fn readChunk w3dStream= ( ID = ReadLong w3dStream #unsigned ),
		fn dumpChunk dumpStream= ( format "3:[W3D_CHUNK_TEXTURE_INFO]\n3:ID:%\n" ID to:dumpStream )
	)

	struct W3D_CHUNK_TEXTURE_NAME																	-- 0x00000032
	(
		chunk,								-- W3D_CHUNK()
		Name,

		fn readChunk w3dStream= ( Name = ReadNullTerminatedString w3dStream ),
		fn dumpChunk dumpStream= ( format "3:[W3D_CHUNK_TEXTURE_NAME]\n3:Name:%\n" Name to:dumpStream )
	)

	struct W3D_CHUNK_TEXTURE																		-- 0x00000031
	(
		chunk,								-- W3D_CHUNK()
		texName,							-- W3D_CHUNK_TEXTURE_NAME()							0x00000032
		texInfo,							-- W3D_CHUNK_TEXTURE_INFO()							0x00000033

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0032: (texName = (W3D_CHUNK_TEXTURE_NAME c)).readChunk w3dStream
					0x0033: (texInfo = (W3D_CHUNK_TEXTURE_INFO c)).readChunk w3dStream
				)
			)
		),

		fn getDependencies w3dStream=
		(
			if (local texturesOffset = getChunks w3dStream chunk.Start chunk.Size ofID:0x0032) > 0 do
			(
				fseek w3dStream texturesOffset #seek_set
				(local c = W3D_CHUNK()).readHeader w3dStream
				return (local t = (W3D_CHUNK_TEXTURE_NAME c)).readChunk w3dStream;
			)
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_TEXTURE]\n" to:dumpStream
			if textureName != undefined do textureName.dumpChunk dumpStream
			if textureInfo != undefined do textureInfo.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_TEXTURES																		-- 0x00000030
	(
		chunk,								-- W3D_CHUNK()
		textureChunk = #(),					-- W3D_CHUNK_TEXTURE()								0x00000031

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				(local c = W3D_CHUNK()).readHeader w3dStream
				(textureChunk[textureChunk.count+1] = (W3D_CHUNK_TEXTURE c)).readChunk w3dStream
			)
		),

		fn getDependencies w3dStream fOffset=
		(
			local deps = #()
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream
			while (ftell w3dStream) < (c.Start + c.Size) do
			(
				(local nC = W3D_CHUNK()).readHeader w3dStream
				append deps ((local t = (W3D_CHUNK_TEXTURE nC)).getDependencies w3dStream)
				fseek w3dStream (nC.Start + nC.Size) #seek_set
			)
			deps
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TEXTURES]\n" to:dumpStream
			for c in textureChunk do c.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_VERTEX_MATERIAL_IDS															-- 0x00000039
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_VERTEX_MATERIAL_IDS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_SHADER_IDS																		-- 0x0000003a
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SHADER_IDS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_DCG																			--	0x0000003b
	(
		chunk,								-- W3D_CHUNK()
		VertexColor,

		fn readChunk w3dStream numVertices= ( VertexColor = for a in numVertices collect(ReadColor w3dStream Alpha:true) ),
		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DCG]\n" to:dumpStream
			for i = 1 to VertexColor.count do format "1:Vertex[%].Color:%\n" i VertexColor[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_DIG																			-- 0x0000003c
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DIG]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_SCG																			-- 0x0000003e
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SCG]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_0x003F																			-- 0x0000003f
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_0x003F]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_TEXTURE_IDS																	-- 0x00000049
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TEXTURE_IDS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_STAGE_TEXTCOORDS																-- 0x0000004a
	(
		chunk,								-- W3D_CHUNK()
		UVW,

		fn readChunk w3dStream numVertices= ( UVW = for a in numVertices collect([(ReadFloat w3dStream), (ReadFloat w3dStream), 0]) ),
		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_STAGE_TEXTCOORDS]\n" to:dumpStream
			for i = 1 to UVW.count do format "1:Vertex[%].UVW:%\n" i UVW[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_PER_FACE_TEXCOORD_IDS															-- 0x0000004b
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PER_FACE_TEXCOORD_IDS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_TEXTURE_STAGE																	-- 0x00000048
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TEXTURE_STAGE]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MATERIAL_PASS																	-- 0x00000038
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MATERIAL_PASS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MULTI_MATERIAL_SHADER															-- 0x00000052
	(
		chunk,								-- W3D_CHUNK()
		Flags,
		Name,
		Unknown,

		fn readChunk w3dStream=
		(
			Flags = ReadByte w3dStream #unsigned
			Name = ReadW3DNameLen w3dStream doubleLen:true
			Unknown = ReadLong w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "3:[W3D_CHUNK_MULTI_MATERIAL_SHADER]\n" to:dumpStream
			format "3:Attributes:%\n" Flags to:dumpStream
			format "3:Name:%\n" Name to:dumpStream
			format "3:Unknown:%\n" Unknown to:dumpStream
		)
	)

	struct W3D_CHUNK_MULTI_MATERIAL_PROPERTIES														-- 0x00000053
	(
		chunk,								-- W3D_CHUNK()
		ValType,
		PropNames = #(),
		PropValues = #(),

		fn readChunk w3dStream=
		(
			ValType = ReadLong w3dStream #unsigned
			local nameLen = ReadLong w3dStream #unsigned
			local str = ""
			for i = 1 to nameLen do str += (bit.IntAsChar (ReadByte w3dStream #unsigned))
			PropNames[PropNames.count+1] = str

			case ValType of
			(
				0x0001:
				(
					local valNameLen = ReadLong w3dStream #unsigned
					local valStr = ""
					for i = 1 to valNameLen do valStr += (bit.IntAsChar (ReadByte w3dStream #unsigned))
					PropValues[PropValues.count+1] = valStr
				)
				0x0002: PropValues[PropValues.count+1] = ReadFloat w3dStream
				0x0003: PropValues[PropValues.count+1] = #(ReadFloat w3dStream, ReadFloat w3dStream)
				0x0004: PropValues[PropValues.count+1] = (for i = 1 to 3 collect(ReadLong w3dStream #unsigned))
				0x0005: PropValues[PropValues.count+1] = ReadFloatRGBA w3dStream
				0x0006: PropValues[PropValues.count+1] = ReadLong w3dStream #unsigned
				0x0007: PropValues[PropValues.count+1] = ReadByte w3dStream #unsigned
			)
		),

		fn dumpChunk dumpStream=
		(
			format "3:[W3D_CHUNK_MULTI_MATERIAL_PROPERTIES]\n" to:dumpStream
			for i = 1 to PropNames.count do format "3:%:%\n" PropNames[i] PropValues[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_MULTI_MATERIAL																	-- 0x00000051
	(
		chunk,								-- W3D_CHUNK()
		multiMaterialShader = #(),			-- W3D_CHUNK_MULTI_MATERIAL_SHADER()				0x00000052
		multiMaterialProps = #(),			-- W3D_CHUNK_MULTI_MATERIAL_PROPERTIES()			0x00000053

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0052: (multiMaterialShader[multiMaterialShader.count+1] = (W3D_CHUNK_MULTI_MATERIAL_SHADER c)).readChunk w3dStream
					0x0053: (multiMaterialProps[multiMaterialProps.count+1] = (W3D_CHUNK_MULTI_MATERIAL_PROPERTIES c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_MULTI_MATERIAL]\n" to:dumpStream
			for i = 1 to multiMaterialShader.count do multiMaterialShader[i].dumpChunk dumpStream
			for i = 1 to multiMaterialProps.count do multiMaterialProps[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_MULTI_MATERIALS																-- 0x00000050
	(
		chunk,								-- W3D_CHUNK()
		multiMaterial = #(),				-- W3D_CHUNK_MULTI_MATERIAL()						0x00000051

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0051: (multiMaterial[multiMaterial.count+1] = (W3D_CHUNK_MULTI_MATERIAL c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MULTI_MATERIALS]\n" to:dumpStream
			for i = 1 to multiMaterial.count do multiMaterial[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_DEFORM_SET																		-- 0x00000059
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DEFORM_SET]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_DEFORM_KEYFRAME																-- 0x0000005a
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DEFORM_KEYFRAME]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_DEFORM_DATA																	-- 0x0000005b
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DEFORM_DATA]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_DEFORM																			-- 0x00000058
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DEFORM]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_0x0060																			-- 0x00000060
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_0x0060]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_0x0061																			-- 0x00000061
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_0x0061]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_PS2_SHADERS																	-- 0x00000080
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PS2_SHADERS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_AABTREE_HEADER																	-- 0x00000091
	(
		chunk,								-- W3D_CHUNK()
		NodeCount,
		PolyCount,
		Padding,

		fn readChunk w3dStream=
		(
			NodeCount = ReadLong w3dStream #unsigned
			PolyCount = ReadLong w3dStream #unsigned
			Padding = for i = 1 to 6 collect(ReadLong w3dStream #unsigned)
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_AABTREE_HEADER]\n" NodeCount PolyCount to:dumpStream
			format "2:NodeCount:%\n" NodeCount to:dumpStream
			format "2:PolyCount:%\n" PolyCount to:dumpStream
		)
	)

	struct W3D_CHUNK_AABTREE_POLYINDICES															-- 0x00000092
	(
		chunk,								-- W3D_CHUNK()
		Index,

		fn readChunk w3dStream polyCount= ( Index = (for i = 1 to polyCount collect(ReadLong w3dStream #unsigned)) ),
		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_AABTREE_POLYINDICES]\n" to:dumpStream
			for i = 1 to Index.count do format "2:PolygonIndex[%]:%\n" i Index[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_AABTREE_NODES																	-- 0x00000093
	(
		chunk,								-- W3D_CHUNK()
		BoxMin = #(),
		BoxMax = #(),
		FrontOrPoly0 = #(),
		BackOrPolyCount = #(),

		fn readChunk w3dStream nodeCount=
		(
			for i = 1 to nodeCount do
			(
				BoxMin[i] = ReadPoint3 w3dStream
				BoxMax[i] = ReadPoint3 w3dStream
				FrontOrPoly0[i] = ReadLong w3dStream #unsigned
				BackOrPolyCount[i] = ReadLong w3dStream #unsigned
			)
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_AABTREE_NODES]\n" to:dumpStream
			for i = 1 to BoxMin.count do
			(
				format "2:Node[%].Min:%\n" i BoxMin[i] to:dumpStream
				format "2:Node[%].Max:%\n" i BoxMax[i] to:dumpStream
				if (bit.and FrontOrPoly0[i] 0x80000000) != 0 then
				(
					format "2:Node[%].Poly0:0x%\n" i (bit.and FrontOrPoly0[i] 0x7fffffff) to:dumpStream
					format "2:Node[%].PolyCount:0x%\n" i BackOrPolyCount[i] to:dumpStream
				)
				else
				(
					format "2:Node[%].Front:0x%\n" i (bit.and FrontOrPoly0[i] 0x7fffffff) to:dumpStream
					format "2:Node[%].Back:0x%\n" i BackOrPolyCount[i] to:dumpStream
				)
			)
		)
	)

	struct W3D_CHUNK_AABTREE																		-- 0x00000090
	(
		chunk,								-- W3D_CHUNK()
		aabHeader,							-- W3D_CHUNK_AABTREE_HEADER()						0x00000091
		aabPoly,							-- W3D_CHUNK_AABTREE_POLYINDICES()					0x00000092
		aabNodes,							-- W3D_CHUNK_AABTREE_NODES()						0x00000093
		subChunks,

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0091: (aabHeader = (W3D_CHUNK_AABTREE_HEADER c)).readChunk w3dStream
					0x0092: (aabPoly = (W3D_CHUNK_AABTREE_POLYINDICES c)).readChunk w3dStream aabHeader.PolyCount
					0x0093: (aabNodes = (W3D_CHUNK_AABTREE_NODES c)).readChunk w3dStream aabHeader.NodeCount
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_AABTREE]\n" to:dumpStream
			aabHeader.dumpChunk dumpStream
			if aabPoly != undefined do aabPoly.dumpChunk dumpStream
			if aabNodes != undefined do aabNodes.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_0x0C00																			-- 0x00000c00
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_0x0C00]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_0x0C01																			-- 0x00000c01
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_0x0C01]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MESH																			-- 0x00000000
	(
		chunk,								-- W3D_CHUNK()
		mesh_Header,						-- W3D_CHUNK_MESH_HEADER()							0x00000001
		mesh_Vertices,						-- W3D_CHUNK_VERTICES()								0x00000002
		mesh_VertexNormals,					-- W3D_CHUNK_VERTEX_NORMALS()						0x00000003
		mesh_SurrenderNormals,				-- W3D_CHUNK_SURRENDER_NORMALS()					0x00000004
		mesh_Texcoords,						-- W3D_CHUNK_TEXCOORDS()							0x00000005
		mesh_SurrenderTriangles,			-- W3D_CHUNK_SURRENDER_TRIANGLES()					0x00000009
		mesh_UserText,						-- W3D_CHUNK_MESH_USER_TEXT()						0x0000000c
		mesh_VertexInfluences,				-- W3D_CHUNK_VERTEX_INFLUENCES()					0x0000000e
		mesh_Materials2,					-- W3D_CHUNK_MATERIALS2()							0x00000014
		mesh_Materials3,					-- W3D_CHUNK_MATERIALS3()							0x00000015
		mesh_Header3,						-- W3D_CHUNK_MESH_HEADER3()							0x0000001f
		mesh_Triangles,						-- W3D_CHUNK_TRIANGLES()							0x00000020
		mesh_PerTriMaterials,				-- W3D_CHUNK_PER_TRI_TRIANGLES()					0x00000021
		mesh_VShadesIndices,				-- W3D_CHUNK_VERTEX_SHADES_INDICES()				0x00000022
		mesh_PrelitUnlit,					-- W3D_CHUNK_PRELIT_UNLIT()							0x00000023
		mesh_PrelitVertex,					-- W3D_CHUNK_PRELIT_VERTEX()						0x00000024
		mesh_PrelitMultiPass,				-- W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS()			0x00000025
		mesh_PrelitMultiTexture,			-- W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE()		0x00000026
		mesh_MaterialInfo,					-- W3D_CHUNK_MATERIAL_INFO()						0x00000028
		mesh_Shaders,						-- W3D_CHUNK_SHADERS()								0x00000029
		mesh_VertexMaterials,				-- W3D_CHUNK_VERTEX_MATERIALS()						0x0000002a
		mesh_Textures,						-- W3D_CHUNK_TEXTURES()								0x00000030
		mesh_MaterialPass,					-- W3D_CHUNK_MATERIAL_PASS()						0x00000038
		mesh_MultiMaterials,				-- W3D_CHUNK_MULTI_MATERIALS()						0x00000050
		mesh_Deform,						-- W3D_CHUNK_DEFORM()								0x00000058
		mesh_0x0060,						-- W3D_CHUNK_0x0060()								0x00000060
		mesh_0x0061,						-- W3D_CHUNK_0x0061()								0x00000061
		mesh_PS2Shaders,					-- W3D_CHUNK_PS2_SHADERS()							0x00000080
		mesh_AABTree,						-- W3D_CHUNK_AABTREE()								0x00000090
		mesh_0x0C00,						-- W3D_CHUNK_0x0C00()								0x00000c00
		mesh_0x0C01,						-- W3D_CHUNK_0x0C01()								0x00000c01
		subChunks = #(),

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				append subChunks ((local c = W3D_CHUNK()).readHeader w3dStream)
				case c.ID of
				(
					0x001f: (mesh_Header3 = (W3D_CHUNK_MESH_HEADER3 c)).readChunk w3dStream
					0x0001: (mesh_Header = (W3D_CHUNK_MESH_HEADER c)).readChunk w3dStream
					0x0002: (mesh_Vertices = (W3D_CHUNK_VERTICES c)).readChunk w3dStream mesh_Header3.NumVert
					0x0003: (mesh_VertexNormals = (W3D_CHUNK_VERTEX_NORMALS c)).readChunk w3dStream mesh_Header3.NumVert
					0x0004: (mesh_SurrenderNormals = (W3D_CHUNK_SURRENDER_NORMALS c)).readChunk w3dStream
					0x0005: (mesh_Texcoords = (W3D_CHUNK_TEXCOORDS c)).readChunk w3dStream
					0x0009: (mesh_SurrenderTriangles = (W3D_CHUNK_SURRENDER_TRIANGLES c)).readChunk w3dStream
					0x000c: (mesh_UserText = (W3D_CHUNK_MESH_USER_TEXT c)).readChunk w3dStream
					0x000e: (mesh_VertexInfluences = (W3D_CHUNK_VERTEX_INFLUENCES c)).readChunk w3dStream
					0x0014: (mesh_Materials2 = (W3D_CHUNK_MATERIALS2 c)).readChunk w3dStream
					0x0015: (mesh_Materials3 = (W3D_CHUNK_MATERIALS3 c)).readChunk w3dStream
					0x0020: (mesh_Triangles = (W3D_CHUNK_TRIANGLES c)).readChunk w3dStream mesh_Header3.NumTris
					0x0021: (mesh_PerTriMaterials = (W3D_CHUNK_PER_TRI_MATERIALS c)).readChunk w3dStream
					0x0022: (mesh_VShadesIndices = (W3D_CHUNK_VERTEX_SHADES_INDICES c)).readChunk w3dStream mesh_Header3.NumVert
					0x0023: (mesh_PrelitUnlit = (W3D_CHUNK_PRELIT_UNLIT c)).readChunk w3dStream
					0x0024: (mesh_PrelitVertex = (W3D_CHUNK_PRELIT_VERTEX c)).readChunk w3dStream
					0x0025: (mesh_PrelitMultiPass = (W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_PASS c)).readChunk w3dStream
					0x0026: (mesh_PrelitMultiTexture = (W3D_CHUNK_PRELIT_LIGHTMAP_MULTI_TEXTURE c)).readChunk w3dStream
					0x0028: (mesh_MaterialInfo = (W3D_CHUNK_MATERIAL_INFO c)).readChunk w3dStream
					0x0029: (mesh_Shaders = (W3D_CHUNK_SHADERS c)).readChunk w3dStream
					0x002a: (mesh_VertexMaterials = (W3D_CHUNK_VERTEX_MATERIALS c)).readChunk w3dStream
					0x0030: (mesh_Textures = (W3D_CHUNK_TEXTURES c)).readChunk w3dStream
					0x0038: (mesh_MaterialPass = (W3D_CHUNK_MATERIAL_PASS c)).readChunk w3dStream
					0x0050: (mesh_MultiMaterials = (W3D_CHUNK_MULTI_MATERIALS c)).readChunk w3dStream
					0x0058: (mesh_Deform = (W3D_CHUNK_DEFORM c)).readChunk w3dStream
					0x0060: (mesh_0x0060 = (W3D_CHUNK_0x0060 c)).readChunk w3dStream
					0x0061: (mesh_0x0061 = (W3D_CHUNK_0x0061 c)).readChunk w3dStream
					0x0080: (mesh_PS2Shaders = (W3D_CHUNK_PS2_SHADERS c)).readChunk w3dStream
					0x0090: (mesh_AABTree = (W3D_CHUNK_AABTREE c)).readChunk w3dStream
					0x0c00: (mesh_0x0C00 = (W3D_CHUNK_0x0C00 c)).readChunk w3dStream
					0x0c01: (mesh_0x0C01 = (W3D_CHUNK_0x0C01 c)).readChunk w3dStream
				)
				fseek w3dStream (c.Start + c.Size) #seek_set
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 16) #seek_set
			return ReadW3DNameLen w3dStream;
		),

		fn getDependencies w3dStream=
		(
			(local c = W3D_CHUNK()).readHeader w3dStream
			if (local texturesOffset = getChunks w3dStream c.Start c.Size ofID:0x0030) > 0 then
			(
				fseek w3dStream texturesOffset #seek_set
				c.readHeader w3dStream
				return (local t = (W3D_CHUNK_TEXTURES c)).getDependencies w3dStream c.Start;
			)
			else return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_MESH]\n" to:dumpStream
			for i in subChunks do
			(
				case i of
				(
					0x0001: mesh_Header.dumpChunk dumpStream
					0x0002: mesh_Vertices.dumpChunk dumpStream
					0x0003: mesh_VertexNormals.dumpChunk dumpStream
					0x0004: mesh_SurrenderNormals.dumpChunk dumpStream
					0x0005: mesh_Texcoords.dumpChunk dumpStream
					0x0009: mesh_SurrenderTriangles.dumpChunk dumpStream
					0x000c: mesh_UserText.dumpChunk dumpStream
					0x000e: mesh_VertexInfluences.dumpChunk dumpStream
					0x0014: mesh_Materials2.dumpChunk dumpStream
					0x0015: mesh_Materials3.dumpChunk dumpStream
					0x001f: mesh_Header3.dumpChunk dumpStream
					0x0020: mesh_Triangles.dumpChunk dumpStream
					0x0021: mesh_PerTriMaterials.dumpChunk dumpStream
					0x0022: mesh_VShadesIndices.dumpChunk dumpStream
					0x0023: mesh_PrelitUnlit.dumpChunk dumpStream
					0x0024: mesh_PrelitVertex.dumpChunk dumpStream
					0x0025: mesh_PrelitLightmapMultiPass.dumpChunk dumpStream
					0x0026: mesh_PrelitLightmapMultiTexture.dumpChunk dumpStream
					0x0028: mesh_MaterialInfo.dumpChunk dumpStream
					0x0029: mesh_Shaders.dumpChunk dumpStream
					0x002a: mesh_VertexMaterials.dumpChunk dumpStream
					0x0030: mesh_Textures.dumpChunk dumpStream
					0x0038: mesh_MaterialPass.dumpChunk dumpStream
					0x0050: mesh_MultiMaterials.dumpChunk dumpStream
					0x0058: mesh_Deform.dumpChunk dumpStream
					0x0060: mesh_0x0060.dumpChunk dumpStream
					0x0061: mesh_0x0061.dumpChunk dumpStream
					0x0080: mesh_PS2Shaders.dumpChunk dumpStream
					0x0090: mesh_AABTree.dumpChunk dumpStream
					0x0c00: mesh_0x0C00.dumpChunk dumpStream
					0x0c01: mesh_0x0C01.dumpChunk dumpStream
				)
			)
		)
	)

	Struct W3D_CHUNK_HIERARCHY_HEADER																-- 0x00000101
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,
		NumBones,
		Origin,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
			NumBones = ReadLong w3dStream #unsigned
			Origin = ReadPoint3 w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return ReadW3DNameLen w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HIERARCHY_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:NumPivots:%\n" NumBones to:dumpStream
			format "1:Origin:%\n" Origin to:dumpStream
		)
	)

	Struct W3D_CHUNK_PIVOTS																			-- 0x00000102
	(
		chunk,								-- W3D_CHUNK()
		Name = #(),
		ParentID = #(),
		Translation = #(),
		Euler = #(),
		Rotation = #(),

		fn readChunk w3dStream numPivots=
		(
			for i = 1 to numPivots do
			(
				append Name (ReadW3DNameLen w3dStream)
				append ParentID (ReadLong w3dStream #unsigned)
				append Translation (ReadPoint3 w3dStream)
				append Euler (ReadEuler w3dStream)
				append Rotation (ReadQuat w3dStream)
			)
		),

		fn dumpChunk dumpStream numPivots=
		(
			format "1:[W3D_CHUNK_PIVOTS]\n" to:dumpStream
			for i = 1 to numPivots do
			(
				format "1:Pivot[%].Name:%\n" (i-1) Name[i] to:dumpStream
				format "1:Pivot[%].ParentID:%\n" (i-1) ParentID[i] to:dumpStream
				format "1:Pivot[%].Translation:%\n" (i-1) Translation[i] to:dumpStream
				format "1:Pivot[%].Euler:%\n" (i-1) Euler[i] to:dumpStream
				format "1:Pivot[%].Rotation:%\n" (i-1) Rotation[i] to:dumpStream
			)
		)
	)

	Struct W3D_CHUNK_PIVOT_FIXUPS																	-- 0x00000103
	(
		chunk,								-- W3D_CHUNK()
		PivotMatrix = #(),

		fn readChunk w3dStream numFixups= ( PivotMatrix = for i = 1 to numFixups collect(ReadMatrix3 w3dStream) ),
		fn dumpChunk dumpStream numPivots=
		(
			format "1:[W3D_CHUNK_PIVOT_FIXUPS]\n" to:dumpStream
			for i = 1 to numPivots do format "1:Pivot[%].Transform:%\n" (i-1) PivotMatrix[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_HIERARCHY																		-- 0x00000100
	(
		chunk,								-- W3D_CHUNK()
		hHeader,							-- W3D_CHUNK_HIERARCHY_HEADER()						0x00000101
		hPivots,							-- W3D_CHUNK_PIVOTS()								0x00000102
		hFixups,							-- W3D_CHUNK_PIVOT_FIXUPS()							0x00000103

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0101: (hHeader = (W3D_CHUNK_HIERARCHY_HEADER c)).readChunk w3dStream
					0x0102: (hPivots = (W3D_CHUNK_PIVOTS c)).readChunk w3dStream hHeader.NumBones
					0x0103: (hFixups = (W3D_CHUNK_PIVOT_FIXUPS c)).readChunk w3dStream hHeader.NumBones
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream
			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000101) > 0 do
				return (hierarchy_Header = W3D_CHUNK_HIERARCHY_HEADER()).getName w3dStream headerOffset
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_HIERARCHY]\n" to:dumpStream
			hHeader.dumpChunk dumpStream
			hPivots.dumpChunk dumpStream hHeader.NumBones
			hFixups.dumpChunk dumpStream hHeader.NumBones
		)
	)

	Struct W3D_STRUCT_ANIMATION_HEADER
	(
		AnimHeaderType,
		Version,
		Name,
		HierarchyName,
		NumFrames,
		FrameRate,
		Flavor,
		ChannelCount,

		fn readStruct w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
			HierarchyName = ReadW3DNameLen w3dStream
			NumFrames = ReadLong w3dStream #unsigned

			case AnimHeaderType of
			(
				0x0201: FrameRate = ReadLong w3dStream #unsigned
				0x0281:
				(
					FrameRate = ReadShort w3dStream #unsigned
					Flavor = ReadShort w3dStream #unsigned
				)
				0x02c1:
				(
					FrameRate = ReadFloat w3dStream
					ChannelCount = ReadLong w3dStream #unsigned
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return #((ReadW3DNameLen w3dStream), (ReadW3DNameLen w3dStream), (ReadLong w3dStream #unsigned));
		),
			

		fn dumpStruct dumpStream=
		(
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:HierarchyName:%\n" HierarchyName to:dumpStream
			format "1:NumFrames:%\n" NumFrames to:dumpStream
			format "1:FrameRate:%\n" FrameRate to:dumpStream
			if AnimHeaderType == 0x281 then format "1:Flavor:%\n" Flavor to:dumpStream
			else if AnimHeaderType == 0x2c1 then format "1:ChannelCount:%\n" ChannelCount to:dumpStream
		)
	)

	Struct W3D_STRUCT_TIMECODED_ANIMATION_CHANNEL
	(
		NumTimeCodes,
		Pivot,
		VectorLen,
		ChannelType,
		TimeCodeData = #(),
		ChannelData = #(),

		fn readStruct w3dStream chunkEOF=
		(
			NumTimeCodes = ReadShort w3dStream #unsigned
			Pivot = ReadShort w3dStream #unsigned
			VectorLen = ReadByte w3dStream #unsigned
			ChannelType = ReadByte w3dStream #unsigned
			for i = 1 to NumTimeCodes do
			(
				case ChannelType of
				(
					0: (TimeCodeData[i] = ReadLong w3dStream #unsigned; ChannelData[i] = ReadFloat w3dStream)
					1: (TimeCodeData[i] = ReadLong w3dStream #unsigned; ChannelData[i] = ReadFloat w3dStream)
					2: (TimeCodeData[i] = ReadLong w3dStream #unsigned; ChannelData[i] = ReadFloat w3dStream)
					6: (TimeCodeData[i] = ReadLong w3dStream #unsigned; ChannelData[i] = ReadQuat w3dStream)
					default: format "ChannelType unexpected: %\n" ChannelType
				)
			)
		),

		fn dumpStruct dumpStream=
		(
			format "1:NumTimeCodes:%\n" NumTimeCodes to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:VectorLen:%\n" VectorLen to:dumpStream
			format "1:ChannelType:%\n" (getAnimChannelType ChannelType) to:dumpStream
			for i = 1 to ChannelData.count do
			(
				format "1:TimeCodeData[%]:0x%\n" i (bit.IntAsHex TimeCodeData[i]) to:dumpStream
				format "1:ChannelData[%]:%\n" i ChannelData[i] to:dumpStream
			)
		)
	)

	Struct W3D_STRUCT_ADAPTIVEDELTA_ANIMATION_CHANNEL
	(
		NumFrames,
		Pivot,
		VectorLen,
		ChannelType,
		Scale,
		Data = #(),

		fn readStruct w3dStream chunkEOF=
		(
			NumFrames = ReadLong w3dStream #unsigned
			Pivot = ReadShort w3dStream #unsigned
			VectorLen = ReadByte w3dStream #unsigned
			ChannelType = ReadByte w3dStream #unsigned
			Scale = ReadFloat w3dStream
			while (ftell w3dStream) < chunkEOF do Data[Data.count+1] = readLong w3dStream 
		),

		fn dumpStruct dumpStream=
		(
			format "1:NumFrames:%\n" NumFrames to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:VectorLen:%\n" VectorLen to:dumpStream
			format "1:ChannelType:%\n" (getAnimChannelType ChannelType) to:dumpStream
			format "1:Scale:%\n" Scale to:dumpStream
			for i = 1 to Data.count do format "1:Data[%]:%\n" i Data[i] to:dumpStream
		)
	)

	Struct W3D_STRUCT_TIMECODED_BIT_CHANNEL
	(
		NumTimeCodes,
		Pivot,
		ChannelType,
		DefaultVal,
		Data = #(),

		fn readStruct w3dStream=
		(
			NumTimeCodes = ReadLong w3dStream #unsigned
			Pivot = ReadShort w3dStream #unsigned
			ChannelType = ReadByte w3dStream #unsigned
			DefaultVal = ReadByte w3dStream #unsigned
			for i = 1 to (NumTimeCodes * 4) do Data[Data.count+1] = readLong w3dStream #unsigned
		),

		fn dumpStruct dumpStream=
		(
			format "1:NumTimeCodes:%\n" NumTimeCodes to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:ChannelType:%\n" (getBitChannelType ChannelType) to:dumpStream
			format "1:DefaultVal:%\n" DefaultVal to:dumpStream
			for i = 1 to Data.count do format "1:Data[%]:%\n" i Data[i] to:dumpStream
		)
	)

	Struct W3D_CHUNK_ANIMATION_HEADER																-- 0x00000201
	(
		chunk,								-- W3D_CHUNK()
		animHeader,							-- W3D_STRUCT_ANIMATION_HEADER()

		fn readChunk w3dStream=	( (animHeader = (W3D_STRUCT_ANIMATION_HEADER 0x0201)).readStruct w3dStream ),

		fn getName w3dStream fOffset= ( return (local a = (W3D_STRUCT_ANIMATION_HEADER 0x0201)).getName w3dStream fOffset; ),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_ANIMATION_HEADER]\n" to:dumpStream
			animHeader.dumpStruct dumpStream
		)
	)
	
	Struct W3D_CHUNK_ANIMATION_CHANNEL																-- 0x00000202
	(
		chunk,								-- W3D_CHUNK()
		FirstFrame,
		LastFrame,
		ChannelType,
		Pivot,
		VectorLen,
		Pad,
		ChannelData = #(),

		fn readChunk w3dStream=
		(
			FirstFrame = ReadShort w3dStream #unsigned
			LastFrame = ReadShort w3dStream #unsigned
			VectorLen = ReadShort w3dStream #unsigned
			ChannelType = ReadShort w3dStream #unsigned
			Pivot = ReadShort w3dStream #unsigned
			Pad = ReadShort w3dStream #unsigned
			for i = 1 to (LastFrame - FirstFrame + 1) do
			(
				case ChannelType of
				(
					0: ChannelData[i] = ReadFloat w3dStream
					1: ChannelData[i] = ReadFloat w3dStream
					2: ChannelData[i] = ReadFloat w3dStream
					6: ChannelData[i] = ReadQuat w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_ANIMATION_CHANNEL]\n" to:dumpStream
			format "1:FirstFrame:%\n" FirstFrame to:dumpStream
			format "1:LastFrame:%\n" LastFrame to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:VectorLen:%\n" VectorLen to:dumpStream
			format "1:ChannelType:%\n" (getAnimChannelType ChannelType) to:dumpStream
			for i = 1 to ChannelData.count do format "1:Frame[%]:%\n" (FirstFrame + i - 1) ChannelData[i] to:dumpStream
		)
	)

	Struct W3D_CHUNK_BIT_CHANNEL																	-- 0x00000203
	(
		chunk,								-- W3D_CHUNK()
		FirstFrame,
		LastFrame,
		ChannelType,
		Pivot,
		DefaultVal,
		Data = #(),

		fn readChunk w3dStream=
		(
			FirstFrame = ReadShort w3dStream #unsigned
			LastFrame = ReadShort w3dStream #unsigned
			ChannelType = (ReadShort w3dStream #unsigned)				-- + 15
			Pivot = ReadShort w3dStream #unsigned
			DefaultVal = ReadByte w3dStream #unsigned
			for i = 1 to ((LastFrame - FirstFrame + 1) / 8) do Data[Data.count + 1] = readByte w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_BIT_CHANNEL]\n" to:dumpStream
			format "1:FirstFrame:%\n" FirstFrame to:dumpStream
			format "1:LastFrame:%\n" LastFrame to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:ChannelType:%\n" (getBitChannelType ChannelType) to:dumpStream
			format "1:DefaultVal:%\n" DefaultVal to:dumpStream
			for i = 1 to Data.count do format "1:Data[%]:%\n" i Data[i] to:dumpStream
		)
	)

	struct W3D_CHUNK_ANIMATION																		-- 0x00000200
	(
		chunk,								-- W3D_CHUNK()
		animHeader,							-- W3D_CHUNK_ANIMATION_HEADER()						0x00000201
		animChannel = #(),					-- W3D_CHUNK_ANIMATION_CHANNEL()					0x00000202
		animBitChannel = #(),				-- W3D_CHUNK_BIT_CHANNEL()							0x00000203

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0201: (animHeader = (W3D_CHUNK_ANIMATION_HEADER c)).readChunk w3dStream
					0x0202: (animChannel[(animChannel.count + 1)] = (W3D_CHUNK_ANIMATION_CHANNEL c)).readChunk w3dStream
					0x0203: (animBitChannel[(animBitChannel.count + 1)] = (W3D_CHUNK_BIT_CHANNEL c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000201) > 0 do
				return (local a = W3D_CHUNK_ANIMATION_HEADER()).getName w3dStream headerOffset;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_ANIMATION]\n" to:dumpStream
			animHeader.dumpChunk dumpStream
			for i = 1 to animChannel.count do animChannel[i].dumpChunk dumpStream
			for i = 1 to animBitChannel.count do animBitChannel[i].dumpChunk dumpStream
		)
	)

	Struct W3D_CHUNK_COMPRESSED_ANIMATION_HEADER													-- 0x00000281
	(
		chunk,								-- W3D_CHUNK()
		animHeader,							-- W3D_STRUCT_ANIMATION_HEADER()

		fn readChunk w3dStream=	( (animHeader = (W3D_STRUCT_ANIMATION_HEADER 0x0281)).readStruct w3dStream ),

		fn getName w3dStream fOffset= ( return (local a = (W3D_STRUCT_ANIMATION_HEADER 0x0281)).getName w3dStream fOffset; ),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COMPRESSED_ANIMATION_HEADER]\n" to:dumpStream
			animHeader.dumpStruct dumpStream
		)
	)

	Struct W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL													-- 0x00000282
	(
		chunk,								-- W3D_CHUNK()
		AnimChannelStruct,					-- W3D_STRUCT_TIMECODED_ANIMATION_CHANNEL() or
											-- W3D_STRUCT_ADAPTIVEDELTA_ANIMATION_CHANNEL()

		fn readChunk w3dStream flavor=
		(
			local chunkEOF = chunk.Start + chunk.Size
			if flavor == 0 then (animChannelStruct = W3D_STRUCT_TIMECODED_ANIMATION_CHANNEL()).readStruct w3dStream chunkEOF
			else if flavor == 1 then (animChannelStruct = W3D_STRUCT_ADAPTIVEDELTA_ANIMATION_CHANNEL()).readStruct w3dStream chunkEOF
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL]\n" to:dumpStream
			animChannelStruct.dumpStruct dumpStream
		)
	)
	
	Struct W3D_CHUNK_COMPRESSED_BIT_CHANNEL															-- 0x00000283
	(
		chunk,								-- W3D_CHUNK()
		TimeCodedBitStruct,					-- W3D_STRUCT_TIMECODED_BIT_CHANNEL()

		fn readChunk w3dStream= ( (TimeCodedBitStruct = W3D_STRUCT_TIMECODED_BIT_CHANNEL()).readStruct w3dStream ),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COMPRESSED_BIT_CHANNEL]\n" to:dumpStream
			TimeCodedBitStruct.dumpStruct dumpStream
		)
	)

	Struct W3D_CHUNK_COMPRESSED_ANIMATION_0x0284													-- 0x00000284
	(
		chunk,								-- W3D_CHUNK()
		UnknownShort1,
		UnknownShort2,
		UnknownShort3,
		Pivot,
		UnknownFloat,
		Data = #(),

		fn readChunk w3dStream=
		(
			UnknownShort1 = ReadShort w3dStream #unsigned
			UnknownShort2 = ReadShort w3dStream #unsigned
			UnknownShort3 = ReadShort w3dStream #unsigned
			Pivot = ReadShort w3dStream #unsigned
			UnknownFloat = ReadFloat w3dStream
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do	Data[Data.count+1] = ReadFloat w3dStream
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COMPRESSED_0x0284]\n" to:dumpStream
			format "1:UnknownShort1:0x%\n" (bit.IntAsHex UnknownShort1) to:dumpStream
			format "1:UnknownShort2:0x%\n" (bit.IntAsHex UnknownShort2) to:dumpStream
			format "1:UnknownShort3:0x%\n" (bit.IntAsHex UnknownShort3) to:dumpStream
			format "1:Pivot:%\n" Pivot to:dumpStream
			format "1:UnknownFloat:%\n" UnknownFloat to:dumpStream
			format "1:Data.count:%\n" Data.count to:dumpStream
		)
	)

	struct W3D_CHUNK_COMPRESSED_ANIMATION															-- 0x00000280
	(
		chunk,								-- W3D_CHUNK()
		animHeader,							-- W3D_CHUNK_COMPRESSED_ANIMATION_HEADER()			0x00000281
		animChannel = #(),					-- W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL()			0x00000282
		animBitChannel = #(),				-- W3D_CHUNK_COMPRESSED_BIT_CHANNEL()				0x00000283
		anim0x0284 = #(),					-- W3D_CHUNK_COMPRESSED_ANIMATION_0x0284()			0x00000284

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0281: (animHeader = (W3D_CHUNK_COMPRESSED_ANIMATION_HEADER c)).readChunk w3dStream
					0x0282:
					(
						local flavor = animHeader.animHeader.Flavor
						(animChannel[animChannel.count+1] = (W3D_CHUNK_COMPRESSED_ANIMATION_CHANNEL c)).readChunk w3dStream flavor
					)
					0x0283: (animBitChannel[animBitChannel.count+1] = (W3D_CHUNK_COMPRESSED_BIT_CHANNEL c)).readChunk w3dStream
					0x0284: (anim0x0284[anim0x0284.count+1] = (W3D_CHUNK_COMPRESSED_ANIMATION_0x0284 c)).readChunk w3dStream
				)
				fseek w3dStream (c.Start + c.Size) #seek_set
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000281) > 0 do
				return (local a = W3D_CHUNK_COMPRESSED_ANIMATION_HEADER()).getName w3dStream headerOffset;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_COMPRESSED_ANIMATION]\n" to:dumpStream
			animHeader.dumpChunk dumpStream
			for i = 1 to animChannel.count do animChannel[i].dumpChunk dumpStream
			for i = 1 to animBitChannel.count do animBitChannel[i].dumpChunk dumpStream
			for i = 1 to anim0x0284.count do anim0x0284[i].dumpChunk dumpStream
		),

		fn check0x0284 w3dStream fOffset=
		(
			local shorts1 = #()
			local shorts2 = #()
			local shorts3 = #()
			local floats = #()
			fseek w3dStream fOffset #seek_set
			readChunk w3dStream
			for c in anim_0x0284 do
			(
				if findItem shorts1 c.UnknownShort1 == 0 do append shorts1 c.UnknownShort1
				if findItem shorts2 c.UnknownShort2 == 0 do append shorts2 c.UnknownShort2
				if findItem shorts3 c.UnknownShort3 == 0 do append shorts3 c.UnknownShort3
				if findItem floats c.UnknownFloat == 0 do append floats c.UnknownFloat
			)
			
			if anim_0x0284.count > 0 do
			(
				format "Shorts1: %\n" shorts1
				format "Shorts2: %\n" shorts2
				format "Shorts3: %\n" shorts3
				format "Floats.count: %\n\n" floats.count
			)
		)
	)

	Struct W3D_CHUNK_MORPHANIM_HEADER																-- 0x000002c1
	(
		chunk,								-- W3D_CHUNK()
		animHeader,							-- W3D_STRUCT_ANIMATION_HEADER()

		fn readChunk w3dStream= ( (animHeader = (W3D_STRUCT_ANIMATION_HEADER 0x02c1)).readStruct w3dStream ),

		fn getName w3dStream fOffset= ( return (local a = (W3D_STRUCT_ANIMATION_HEADER 0x02c1)).getName w3dStream fOffset; ),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MORPHANIM_HEADER]\n" to:dumpStream
			animHeader.dumpStruct dumpStream
		)
	)

	Struct W3D_CHUNK_MORPHANIM_CHANNEL																-- 0x000002c2
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MORPHANIM_CHANNEL]\n" to:dumpStream
		)
	)

	Struct W3D_CHUNK_MORPHANIM_POSENAME																-- 0x000002c3
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MORPHANIM_POSENAME]\n" to:dumpStream
		)
	)

	Struct W3D_CHUNK_MORPHANIM_KEYDATA																-- 0x000002c4
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MORPHANIM_KEYDATA]\n" to:dumpStream
		)
	)

	Struct W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA														-- 0x000002c5
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_MORPH_ANIMATION																-- 0x000002c0
	(
		chunk,								-- W3D_CHUNK()
		morphHeader,						-- W3D_CHUNK_MORPHANIM_HEADER()						0x000002c1
		morphChannel,						-- W3D_CHUNK_MORPHANIM_CHANNEL()					0x000002c2
		morphPoseName,						-- W3D_CHUNK_MORPHANIM_POSENAME()					0x000002c3
		morphKeyData,						-- W3D_CHUNK_MORPHANIM_KEYDATA()					0x000002c4
		morphPivotData,						-- W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA()			0x000002c5

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x02c1: (morphHeader = (W3D_CHUNK_MORPHANIM_HEADER c)).readChunk w3dStream
					0x02c2: (morphChannel[(morphChannel.count + 1)] = (W3D_CHUNK_MORPHANIM_CHANNEL c)).readChunk w3dStream
					0x02c3: (morphPoseName[(morphPoseName.count + 1)] = (W3D_CHUNK_MORPHANIM_POSENAME c)).readChunk w3dStream
					0x02c4: (morphKeyData[(morphKeyData.count + 1)] = (W3D_CHUNK_MORPHANIM_KEYDATA c)).readChunk w3dStream
					0x02c5: (morphPivotData[(morphPivotData.count + 1)] = (W3D_CHUNK_MORPHANIM_PIVOTCHANNELDATA c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x000002c1) > 0 do
				return (local a = W3D_CHUNK_MORPHANIM_HEADER()).getName w3dStream headerOffset;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_MORPH_ANIMATION]\n" to:dumpStream
			morphHeader.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_HMODEL_HEADER																	-- 0x00000301
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,
		HierarchyName,
		NumConnections,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
			HierarchyName = ReadW3DNameLen w3dStream
			NumConnections = ReadShort w3dStream #unsigned
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return #((Name = ReadW3DNameLen w3dStream), (HierarchyName = ReadW3DNameLen w3dStream));
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HMODEL_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:HierarchyName:%\n" HierarchyName to:dumpStream
			format "1:NumConnections:%\n" NumConnections to:dumpStream
		)
	)

	struct W3D_CHUNK_NODE																			-- 0x00000302
	(
		chunk,								-- W3D_CHUNK()
		RenderObjName,
		PivotID,

		fn readChunk w3dStream=
		(
			RenderObjName = ReadW3DNameLen w3dStream
			PivotID = ReadShort w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_NODE]\n" to:dumpStream
			format "1:RenderObjName:%\n" RenderObjName to:dumpStream
			format "1:PivotID:%\n" PivotID to:dumpStream
		)
	)

	struct W3D_CHUNK_COLLISION_NODE																	-- 0x00000303
	(
		chunk,								-- W3D_CHUNK()
		CollisionMeshName,
		PivotID,

		fn readChunk w3dStream=
		(
			CollisionMeshName = ReadW3DNameLen w3dStream
			PivotID = ReadShort w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COLLISION_NODE]\n" to:dumpStream
			format "1:CollisionMeshName:%\n" CollisionMeshName to:dumpStream
			format "1:PivotID:%\n" PivotID to:dumpStream
		)
	)

	struct W3D_CHUNK_SKIN_NODE																		-- 0x00000304
	(
		chunk,								-- W3D_CHUNK()
		SkinMeshName,
		PivotID,

		fn readChunk w3dStream=
		(
			SkinMeshName = ReadW3DNameLen w3dStream
			PivotID = ReadShort w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SKIN_NODE]\n" to:dumpStream
			format "1:SkinMeshName:%\n" SkinMeshName to:dumpStream
			format "1:PivotID:%\n" PivotID to:dumpStream
		)
	)

	struct W3D_CHUNK_HMODEL_AUX_DATA																-- 0x00000305
	(
		chunk,								-- W3D_CHUNK()
		ModelAttributes,
		MeshCount,
		CollisionCount,
		SkinCount,
		FutureCounts = #(),
		LODMin,
		LODMax,
		FutureUse = #(),

		fn readChunk w3dStream=
		(
			ModelAttributes = ReadLong w3dStream #unsigned
			MeshCount = ReadLong w3dStream #unsigned
			CollisionCount = ReadLong w3dStream #unsigned
			SkinCount = ReadLong w3dStream #unsigned
			for i = 1 to 8 do append FutureCounts (ReadLong w3dStream #unsigned)
			LODMin = ReadFloat w3dStream
			LODMax = ReadFloat w3dStream
			for i = 1 to 32 do append FutureUse (ReadLong w3dStream #unsigned)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HMODEL_AUX_DATA]\n" to:dumpStream
			format "1:ModelAttributes:%\n" ModelAttributes to:dumpStream
			format "1:MeshCount:%\n" MeshCount to:dumpStream
			format "1:CollisionCount:%\n" CollisionCount to:dumpStream
			format "1:SkinCount:%\n" SkinCount to:dumpStream
			format "1:FutureCounts:%\n" FutureCounts to:dumpStream
			format "1:LODMin:%\n" LODMin to:dumpStream
			format "1:LODMax:%\n" LODMax to:dumpStream
			format "1:FutureUse:%\n" FutureUse to:dumpStream
		)
	)

	struct W3D_CHUNK_SHADOW_NODE																	-- 0x00000306
	(
		chunk,								-- W3D_CHUNK()
		ShadowMeshName,
		PivotID,

		fn readChunk w3dStream=
		(
			ShadowMeshName = ReadW3DNameLen w3dStream
			PivotID = ReadShort w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SHADOW_NODE]\n" to:dumpStream
			format "1:ShadowMeshName:%\n" ShadowMeshName to:dumpStream
			format "1:PivotID:%\n" PivotID to:dumpStream
		)
	)

	struct W3D_CHUNK_HMODEL																			-- 0x00000300
	(
		chunk,								-- W3D_CHUNK()
		modelHeader,						-- W3D_CHUNK_HMODEL_HEADER()						0x00000301
		modelNode = #(),					-- W3D_CHUNK_NODE()									0x00000302
		modelCollisionNode = #(),			-- W3D_CHUNK_COLLISION_NODE()						0x00000303
		modelSkinNode = #(),				-- W3D_CHUNK_SKIN_NODE()							0x00000304
		modelAuxData = #(),					-- W3D_CHUNK_HMODEL_AUX_DATA()						0x00000305
		modelShadowNode = #(),				-- W3D_CHUNK_SHADOW_NODE()							0x00000306

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0301: (modelHeader = (W3D_CHUNK_HMODEL_HEADER c)).readChunk w3dStream
					0x0302:	(modelNode[modelNode.count+1] = (W3D_CHUNK_NODE c)).readChunk w3dStream
					0x0303: (modelCollisionNode[modelCollisionNode.count+1] = (W3D_CHUNK_COLLISION_NODE c)).readChunk w3dStream
					0x0304: (modelSkinNode[modelSkinNode.count+1] = (W3D_CHUNK_SKIN_NODE c)).readChunk w3dStream
					0x0305: (modelAuxData[modelAuxData.count+1] = (W3D_CHUNK_HMODEL_AUX_DATA c)).readChunk w3dStream
					0x0306: (modelShadowNode[modelShadowNode.count+1] = (W3D_CHUNK_HMODEL_SHADOW_NODE c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000301) > 0 do
				return (local n = W3D_CHUNK_HMODEL_HEADER()).getName w3dStream headerOffset;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_MODEL]\n" to:dumpStream
			modelHeader.dumpChunk dumpStream
			for i = 1 to modelNode.count do modelNode[i].dumpChunk dumpStream
			for i = 1 to modelCollisionNode.count do modelCollisionNode[i].dumpChunk dumpStream
			for i = 1 to modelSkinNode.count do modelSkinNode[i].dumpChunk dumpStream
			for i = 1 to modelAuxData.count do modelAuxData[i].dumpChunk dumpStream
			for i = 1 to modelShadowNode.count do modelShadowNode[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_COLLECTION_HEADER																-- 0x00000421
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,
		RenderObjectCount,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
			RenderObjectCount = ReadLong w3dStream #unsigned
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COLLECTION_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:RenderObjectCount:%\n" RenderObjectCount to:dumpStream
		)
	)

	struct W3D_CHUNK_COLLECTION_OBJ_NAME															-- 0x00000422
	(
		chunk,								-- W3D_CHUNK()
		Name,
		Container,

		fn readChunk w3dStream=
		(
			Name = (local W3DName = ReadW3DNameLen w3dStream ContainerName:true)[1]
			Container = W3DName[2]
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_COLLECTION_OBJ_NAME]\n" to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:Container:%\n" Container to:dumpStream
		)
	)

	struct W3D_CHUNK_PLACEHOLDER																	-- 0x00000423
	(
		chunk,								-- W3D_CHUNK()
		Version,
		TransformMatrix,
		NameLen,
		Name,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			TransformMatrix = ReadMatrix3 w3dStream
			NameLen = ReadLong w3dStream #unsigned
			Name = ReadNullTerminatedString w3dStream
		),

		fn getDependencies w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 64) #seek_set
			return ReadNullTerminatedString w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_PLACEHOLDER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Transform:%\n" TransformMatrix to:dumpStream
			format "1:NameLen:%\n" NameLen to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			
		)
	)

	struct W3D_CHUNK_TRANSFORM_NODE																	-- 0x00000424
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TRANSFORM_NODE]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_COLLECTION																		-- 0x00000420
	(
		chunk,								-- W3D_CHUNK()
		colHeader,							-- W3D_CHUNK_COLLECTION_HEADER()					0x00000421
		colObjName = #(),					-- W3D_CHUNK_COLLECTION_OBJ_NAME()					0x00000422
		colPlaceHolder = #(),				-- W3D_CHUNK_PLACEHOLDER()							0x00000423
		colTransformNode = #(),				-- W3D_CHUNK_TRANSFORM_NODE()						0x00000424

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0421: (colHeader = (W3D_CHUNK_COLLECTION_HEADER c)).readChunk w3dStream
					0x0422:	(colObjName[colObjName.count+1] = (W3D_CHUNK_COLLECTION_OBJ_NAME c)).readChunk w3dStream
					0x0423: (colPlaceHolder[colPlaceHolder.count+1] = (W3D_CHUNK_PLACEHOLDER c)).readChunk w3dStream
					0x0424: (colTransformNode[colTransformNode.count+1] = (W3D_CHUNK_TRANSFORM_NODE c)).readChunk w3dStream
				)
			)
		),

		fn getDependencies w3dStream=
		(
			readHeader w3dStream
			local subChunks = getChunks w3dStream chunk.Start chunk.Size
			local deps = #()
			for c in subChunks where c[1] == 0x0423 do append deps ((local s = W3D_CHUNK_PLACEHOLDER()).getDependencies w3dStream c[2])
			return deps;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_COLLECTION]\n" to:dumpStream
			colHeader.dumpChunk dumpStream
			for i = 1 to colObjName.count do colObjName[i].dumpChunk dumpStream
			for i = 1 to colPlaceHolder.count do colPlaceHolder[i].dumpChunk dumpStream
			for i = 1 to colTransformNode.count do colTransformNode[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_HEADER																	-- 0x00000501
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return Name = ReadW3DNameLen w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_USER_DATA																-- 0x00000502
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_USER_DATA]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_INFO																	-- 0x00000503
	(
		chunk,								-- W3D_CHUNK()
		TextureName,
		StartSize,
		EndSize,
		LifeTime,
		EmitionRate,
		MaxEmitions,
		VelocityRandom,
		PositionRandom,
		FadeTime,
		Gravity,
		Elasticity,
		Velocity,
		Acceleration,
		StartColor,
		EndColor,

		fn readChunk w3dStream=
		(
			local curOffset = ftell w3dStream
			TextureName = ReadNullTerminatedString w3dStream
			fseek w3dStream (260 - ((ftell w3dStream) - curOffset)) #seek_set
			StartSize = ReadFloat w3dStream
			EndSize = ReadFloat w3dStream
			LifeTime = ReadFloat w3dStream
			EmitionRate = ReadFloat w3dStream
			MaxEmitions = ReadFloat w3dStream
			VelocityRandom = ReadFloat w3dStream
			PositionRandom = ReadFloat w3dStream
			FadeTime = ReadFloat w3dStream
			Gravity = ReadFloat w3dStream
			Elasticity = ReadFloat w3dStream
			Velocity = ReadPoint3 w3dStream
			Acceleration = ReadPoint3 w3dStream
			StartColor = ReadColor w3dStream Alpha:true
			EndColor = ReadColor w3dStream Alpha:true
		),

		fn getdependencies w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 8) #seek_set
			return ReadNullTerminatedString w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_INFO]\n" to:dumpStream
			format "1:TextureName:%\n" TextureName to:dumpStream
			format "1:StartSize:%\n" StartSize to:dumpStream
			format "1:EndSize:%\n" EndSize to:dumpStream
			format "1:LifeTime:%\n" LifeTime to:dumpStream
			format "1:EmitionRate:%\n" EmitionRate to:dumpStream
			format "1:MaxEmitions:%\n" MaxEmitions to:dumpStream
			format "1:VelocityRandom:%\n" VelocityRandom to:dumpStream
			format "1:PositionRandom:%\n" PositionRandom to:dumpStream
			format "1:FadeTime:%\n" FadeTime to:dumpStream
			format "1:Gravity:%\n" Gravity to:dumpStream
			format "1:Elasticity:%\n" Elasticity to:dumpStream
			format "1:Velocity:%\n" Velocity to:dumpStream
			format "1:Acceleration:%\n" Acceleration to:dumpStream
			format "1:StartColor:%\n" StartColor to:dumpStream
			format "1:EndColor:%\n" EndColor to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_INFOV2																	-- 0x00000504
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_INFOV2]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_PROPS																	-- 0x00000505
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_PROPS]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_COLOR_KEYFRAME															-- 0x00000506
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_COLOR_KEYFRAME]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_OPACITY_KEYFRAME														-- 0x00000507
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_OPACITY_KEYFRAME]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_SIZE_KEYFRAME															-- 0x00000508
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_SIZE_KEYFRAME]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_LINE_PROPERTIES														-- 0x00000509
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_LINE_PROPERTIES]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES														-- 0x0000050a
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_FRAME_KEYFRAMES														-- 0x0000050b
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_FRAME_KEYFRAMES]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES													-- 0x0000050c
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER_0x050d																	-- 0x0000050d
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_EMITTER_0X050D]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_EMITTER																		-- 0x00000500
	(
		chunk,								-- W3D_CHUNK()
		emitterHeader,						-- W3D_CHUNK_EMITTER_HEADER()						0x00000501
		emitterUserData,					-- W3D_CHUNK_EMITTER_USER_DATA()					0x00000502
		emitterInfo,						-- W3D_CHUNK_EMITTER_INFO()							0x00000503
		emitterInfoV2,						-- W3D_CHUNK_EMITTER_INFOV2()						0x00000504
		emitterProps,						-- W3D_CHUNK_EMITTER_PROPS()						0x00000505
		emitterColorKeyFrame,				-- W3D_CHUNK_EMITTER_COLOR_KEYFRAME()				0x00000506
		emitterOpacityKeyFrame,				-- W3D_CHUNK_EMITTER_OPACITY_KEYFRAME()				0x00000507
		emitterSizeKeyFrame,				-- W3D_CHUNK_EMITTER_SIZE_KEYFRAME()				0x00000508
		emitterLineProperties,				-- W3D_CHUNK_EMITTER_LINE_PROPERTIE()				0x00000509
		emitterRotationKeyFrames,			-- W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES()			0x0000050a
		emitterFrameKeyFrames,				-- W3D_CHUNK_EMITTER_FRAME_KEYFRAMES()				0x0000050b
		emitterBlurTimeKeyFrames,			-- W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES()			0x0000050c
		emitter0x050d,						-- W3D_CHUNK_EMITTER_0x050d()						0x0000050d

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0501: (emitterHeader = (W3D_CHUNK_EMITTER_HEADER c)).readChunk w3dStream
					0x0502: (emitterUserData = (W3D_CHUNK_EMITTER_USER_DATA c)).readChunk w3dStream
					0x0503: (emitterInfo = (W3D_CHUNK_EMITTER_INFO c)).readChunk w3dStream
					0x0504: (emitterInfoV2 = (W3D_CHUNK_EMITTER_INFOV2 c)).readChunk w3dStream
					0x0505: (emitterProps = (W3D_CHUNK_EMITTER_PROPS c)).readChunk w3dStream
					0x0506: (emitterColorKeyFrame = (W3D_CHUNK_EMITTER_COLOR_KEYFRAME c)).readChunk w3dStream
					0x0507: (emitterOpacityKeyFrame = (W3D_CHUNK_EMITTER_OPACITY_KEYFRAME c)).readChunk w3dStream
					0x0508: (emitterSizeKeyFrame = (W3D_CHUNK_EMITTER_SIZE_KEYFRAME c)).readChunk w3dStream
					0x0509: (emitterLineProperties = (W3D_CHUNK_EMITTER_LINE_PROPERTIE c)).readChunk w3dStream
					0x050a: (emitterRotationKeyFrames = (W3D_CHUNK_EMITTER_ROTATION_KEYFRAMES c)).readChunk w3dStream
					0x050b: (emitterFrameKeyFrames = (W3D_CHUNK_EMITTER_FRAME_KEYFRAMES c)).readChunk w3dStream
					0x050c: (emitterBlurTimeKeyFrames = (W3D_CHUNK_EMITTER_BLUR_TIME_KEYFRAMES c)).readChunk w3dStream
					0x050d: (emitter0x050d = (W3D_CHUNK_EMITTER_0x050d c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000501) > 0 do
				return (emitterHeader = W3D_CHUNK_EMITTER_HEADER()).getName w3dStream headerOffset;
		),

		fn getDependencies w3dStream=
		(
			readHeader w3dStream
			if (local infoOffset = getChunks w3dStream chunk.Start chunk.Size ofID:0x00000503) > 0 do
				return #((local s = W3D_CHUNK_EMITTER_INFO()).getDependencies w3dStream infoOffset;)
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_EMITTER]\n" to:dumpStream
			emitterHeader.dumpChunk dumpStream
			if emitterUserData != undefined do emitterUserData.dumpChunk dumpStream
			if emitterInfo != undefined do emitterInfo.dumpChunk dumpStream
			if emitterInfoV2 != undefined do emitterInfoV2.dumpChunk dumpStream
			if emitterProps != undefined do emitterProps.dumpChunk dumpStream
			if emitterColorKeyFrame != undefined do emitterColorKeyFrame.dumpChunk dumpStream
			if emitterOpacityKeyFrame != undefined do emitterOpacityKeyFrame.dumpChunk dumpStream
			if emitterSizeKeyFrame != undefined do emitterSizeKeyFrame.dumpChunk dumpStream
			if emitterLineProperties != undefined do emitterLineProperties.dumpChunk dumpStream
			if emitterRotationKeyFrames != undefined do emitterRotationKeyFrames.dumpChunk dumpStream
			if emitterFrameKeyFrames != undefined do emitterFrameKeyFrames.dumpChunk dumpStream
			if emitterBlurTimeKeyFrames != undefined do emitterBlurTimeKeyFrames.dumpChunk dumpStream
			if emitter0x050d != undefined do emitter0x050d.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_AGGREGATE_HEADER																-- 0x00000601
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return (ReadW3DNameLen w3dStream);
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_AGGREGATE_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
		)
	)

	struct W3D_CHUNK_AGGREGATE_INFO																	-- 0x00000602
	(
		chunk,								-- W3D_CHUNK()
		BaseModelName,
		SubobjectCount,
		SubobjectNames = #(),
		BonesNames = #(),
		
		fn readChunk w3dStream=
		(
			BaseModelName = ReadW3DNameLen w3dStream doubleLen:true
			SubobjectCount = ReadLong w3dStream #unsigned
			for i = 1 to SubobjectCount do
			(
				append SubobjectNames (ReadW3DNameLen w3dStream doubleLen:true)
				append BonesNames (ReadW3DNameLen w3dStream doubleLen:true)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 8) #seek_set
			BaseModelName = ReadW3DNameLen w3dStream doubleLen:true
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_AGGREGATE_INFO]\n" to:dumpStream
			format "1:BaseModelName:%\n" BaseModelName to:dumpStream
			format "1:SubobjectCount:%\n" SubobjectCount to:dumpStream
			for i = 1 to SubobjectCount do
			(
				format "1:SubobjectNames[%]:%\n" (i-1) SubobjectNames to:dumpStream
				format "1:BonesNames[%]:%\n" (i-1) BonesNames to:dumpStream
			)
		)
	)

	struct W3D_CHUNK_TEXTURE_REPLACER_INFO															-- 0x00000603
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_TEXTURE_REPLACER_INFO]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_AGGREGATE_CLASS_INFO															-- 0x00000604
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_AGGREGATE_CLASS_INFO]\n" to:dumpStream
		)
	)

	struct W3D_CHUNK_AGGREGATE																		-- 0x00000600
	(
		chunk,								-- W3D_CHUNK()
		aggHeader,							-- W3D_CHUNK_AGGREGATE_HEADER()						0x00000601
		aggInfo,							-- W3D_CHUNK_AGGREGATE_INFO()						0x00000602
		aggTexReplacer,						-- W3D_CHUNK_TEXTURE_REPLACER_INFO()				0x00000603
		aggClassInfo,						-- W3D_CHUNK_AGGREGATE_CLASS_INFO()					0x00000604

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0601: (aggHeader = (W3D_CHUNK_AGGREGATE_HEADER c)).readChunk w3dStream
					0x0602: (aggInfo = (W3D_CHUNK_AGGREGATE_INFO c)).readChunk w3dStream
					0x0603: (aggTexReplacer = (W3D_CHUNK_TEXTURE_REPLACER_INFO c)).readChunk w3dStream
					0x0604: (aggClassInfo = (W3D_CHUNK_AGGREGATE_CLASS_INFO c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			local mName = ((local n = W3D_CHUNK_AGGREGATE_HEADER()).getName w3dStream (ftell w3dStream))
			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000602) > 0 do
			(
				local hName = ((local n = W3D_CHUNK_AGGREGATE_INFO()).getName w3dStream headerOffset)
				return #(mName, hName);
			)
			return #();
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_AGGREGATE]\n" to:dumpStream
			aggHeader.dumpChunk dumpStream
			if aggInfo != undefined do aggInfo.dumpChunk dumpStream
			if aggTexReplacer != undefined do aggTexReplacer.dumpChunk dumpStream
			if aggClassInfo != undefined do aggClassInfo.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER													-- 0x00000703
	(
		chunk,								-- W3D_CHUNK()
		ModelCount,
		MaxScreenSize,

		fn readChunk w3dStream=
		(
			ModelCount = ReadLong w3dStream #unsigned
			MaxScreenSize = ReadFloat w3dStream
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER]\n" to:dumpStream
			format "2:ModelCount:%\n" ModelCount to:dumpStream
			format "2:MaxScreenSize:%\n" MaxScreenSize to:dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_SUB_OBJECT																-- 0x00000704
	(
		chunk,								-- W3D_CHUNK()
		BoneIndex,
		Name,
		Container,

		fn readChunk w3dStream=
		(
			BoneIndex = ReadLong w3dStream #unsigned
			Name = (local W3DName = ReadW3DNameLen w3dStream ContainerName:true)[1]
			Container = W3DName[2]
		),

		fn dumpChunk dumpStream=
		(
			format "2:[W3D_CHUNK_HLOD_SUB_OBJECT]\n" to:dumpStream
			format "2:BoneIndex:%\n" BoneIndex to:dumpStream
			if Container != "" then format "2:Name:%.%\n" Container Name to:dumpStream
			else  format "2:Name:%\n" Name to:dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_HEADER																	-- 0x00000701
	(
		chunk,								-- W3D_CHUNK()
		Version,
		LodCount,
		Name,
		HTreeName,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			LodCount = ReadLong w3dStream #unsigned
			Name = ReadW3DNameLen w3dStream
			HTreeName = ReadW3DNameLen w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 16) #seek_set
			return #((Name = ReadW3DNameLen w3dStream), (HTreeName = ReadW3DNameLen w3dStream));
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HLOD_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:LodCount:%\n" LodCount to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:HTreeName:%\n" HTreeName to:dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_LOD_ARRAY																	-- 0x00000702
	(
		chunk,								-- W3D_CHUNK()
		subHeader,							-- W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER()			0x00000703
		subObject = #(),					-- W3D_CHUNK_HLOD_SUB_OBJECT() ARRAY				0x00000704

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0703: (subHeader = (W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER c)).readChunk w3dStream
					0x0704: (subObject[subObject.count+1]= (W3D_CHUNK_HLOD_SUB_OBJECT c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HLOD_LOD_ARRAY]\n" to:dumpStream
			subHeader.dumpChunk dumpStream
			for i = 1 to subHeader.ModelCount do subObject[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_AGGREGATE_ARRAY															-- 0x00000705
	(
		chunk,								-- W3D_CHUNK()
		aggHeader,							-- W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER()			0x00000703
		aggSubObject = #(),					-- W3D_CHUNK_HLOD_SUB_OBJECT() ARRAY				0x00000704

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0703: (aggHeader = (W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER c)).readChunk w3dStream
					0x0704: (aggSubObject[aggSubObject.count+1]= (W3D_CHUNK_HLOD_SUB_OBJECT c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HLOD_AGGREGATE_ARRAY]\n" to:dumpStream
			aggHeader.dumpChunk dumpStream
			for i = 1 to aggHeader.ModelCount do aggSubObject[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_HLOD_PROXY_ARRAY																-- 0x00000706
	(
		chunk,								-- W3D_CHUNK()
		proxyHeader,						-- W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER()			0x00000703
		proxySubObject = #(),				-- W3D_CHUNK_HLOD_SUB_OBJECT() ARRAY				0x00000704

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0703: (proxyHeader = (W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER c)).readChunk w3dStream
					0x0704: (proxySubObject[proxySubObject.count+1]= (W3D_CHUNK_HLOD_SUB_OBJECT c)).readChunk w3dStream
				)
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_HLOD_PROXY_ARRAY]\n" to:dumpStream
			proxyHeader.dumpChunk dumpStream
			for i = 1 to proxyHeader.ModelCount do proxySubObject[i].dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_HLOD																			-- 0x00000700
	(
		chunk,								-- W3D_CHUNK()
		hlodHeader,							-- W3D_CHUNK_HLOD_HEADER()							0x00000701
		hlodLODArray = #(),					-- W3D_CHUNK_HLOD_LOD_ARRAY() ARRAY					0x00000702
		hlodAggArray,						-- W3D_CHUNK_HLOD_AGGREGATE_ARRAY()					0x00000705
		hlodProxyArray,						-- W3D_CHUNK_HLOD_PROXY_ARRAY()						0x00000706

		fn readChunk w3dStream=
		(
			while (ftell w3dStream) < (chunk.Start + chunk.Size) do
			(
				case ((local c = W3D_CHUNK()).readHeader w3dStream) of
				(
					0x0701: (hlodHeader = (W3D_CHUNK_HLOD_HEADER c)).readChunk w3dStream
					0x0702: (hlodLODArray[hlodLODArray.count+1]= (W3D_CHUNK_HLOD_LOD_ARRAY c)).readChunk w3dStream
					0x0705: (hlodAggArray = (W3D_CHUNK_HLOD_AGGREGATE_ARRAY c)).readChunk w3dStream
					0x0706: (hlodProxyArray = (W3D_CHUNK_HLOD_PROXY_ARRAY c)).readChunk w3dStream
				)
			)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream
	
			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000701) > 0 do
				return (local n = W3D_CHUNK_HLOD_HEADER()).getName w3dStream headerOffset;
		),

		fn hasAggregate w3dStream fOffset=
		(
			if chunk == undefined do
			(
				fseek w3dStream fOffset #seek_set
				(chunk = W3D_CHUNK()).readHeader w3dStream
			)

			if (local headerOffset = getChunks w3dStream chunk.Start chunk.Size chunkOffset:fOffset ofID:0x00000705) > 0 then
			(
				fseek w3dStream headerOffset #seek_set
				return true;
			)
			else return false;
		),

		fn hasProxy w3dStream fOffset=
		(
			if chunk == undefined do
			(
				fseek w3dStream fOffset #seek_set
				(chunk = W3D_CHUNK()).readHeader w3dStream
			)

			if (local headerOffset = getChunks w3dStream chunk.Start chunk.Size chunkOffset:fOffset ofID:0x00000706) > 0 then
			(
				fseek w3dStream headerOffset #seek_set
				return true;
			)
			else return false;
		),

		fn getDependencies w3dStream forAggregate:false=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_HLOD]\n" to:dumpStream
			hlodHeader.dumpChunk dumpStream
			for i = 1 to hlodHeader.LodCount do hlodLODArray[i].dumpChunk dumpStream
			if hlodAggArray != undefined do hlod_AggregateArray.dumpChunk dumpStream
			if hlodProxyArray != undefined do hlod_ProxyArray.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_BOX																			-- 0x00000740
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Flags,
		Name,
		Container,
		BoxColor,
		Pos,
		Extent,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Flags = ReadLong w3dStream #unsigned
			Name = (local w3dName = ReadW3DNameLen w3dStream ContainerName:true)[1]
			Container = w3dName[2]
			BoxColor = ReadColor w3dStream
			Pos = ReadPoint3 w3dStream
			Extent = ReadPoint3 w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 16) #seek_set
			return ReadW3DNameLen w3dStream ContainerName:true;
		),

		fn getFlags=
		(
			local flagsArray = #()
			if (bit.and Flags 0x00000001) == 0x00000001 do append flagsArray "W3D_BOX_ATTRIBUTE_ORIENTED"
			if (bit.and Flags 0x00000002) == 0x00000002 do append flagsArray "W3D_BOX_ATTRIBUTE_ALIGNED"
			if (bit.and Flags 0x00000ff0) == 0x00000ff0 do append flagsArray "W3D_BOX_ATTRIBUTE_COLLISION_TYPE_MASK"
			if (bit.and Flags 0x00000004) == 0x00000004 do append flagsArray "W3D_BOX_ATTRIBUTE_COLLISION_TYPE_SHIFT"
			if (bit.and Flags 0x00000010) == 0x00000010 do append flagsArray "W3D_BOX_ATTRIBTUE_COLLISION_TYPE_PHYSICAL"
			if (bit.and Flags 0x00000020) == 0x00000020 do append flagsArray "W3D_BOX_ATTRIBTUE_COLLISION_TYPE_PROJECTILE"
			if (bit.and Flags 0x00000040) == 0x00000040 do append flagsArray "W3D_BOX_ATTRIBTUE_COLLISION_TYPE_VIS"
			if (bit.and Flags 0x00000080) == 0x00000080 do append flagsArray "W3D_BOX_ATTRIBTUE_COLLISION_TYPE_CAMERA"
			if (bit.and Flags 0x00000100) == 0x00000100 do append flagsArray "W3D_BOX_ATTRIBTUE_COLLISION_TYPE_VEHICLE"

			return flagsArray;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_BOX]\n" to:dumpStream
			format "0:Version:%\n" Version to:dumpStream
			format "0:Attributes:%\n" Flags to:dumpStream
			for i = 1 to (local flagsArray = getFlags()).count do format "0:Attributes Flag:%\n" flagsArray[i] to:dumpStream
			format "0:Name:%.%\n" Container Name to:dumpStream
			format "0:Color:%\n" BoxColor to:dumpStream
			format "0:Center:%\n" Pos to:dumpStream
			format "0:Extent:%\n" Extent to:dumpStream
		)
	)

	struct W3D_CHUNK_SPHERE_HEADER
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Flags,
		Name,
		UnknownLong,
		UnknownPoint3s = #(),
		TextureName,
		UnknownShorts = #(),
		
		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Flags = ReadLong w3dStream #unsigned
			Name = ReadW3DNameLen w3dStream doubleLen:true
			UnknownLong = ReadLong w3dStream #unsigned
			UnknownPoint3s = #()
			for i = 1 to 6 do append UnknownPoint3s (ReadPoint3 w3dStream)
			TextureName = ReadW3DNameLen w3dStream doubleLen:true
			UnknownShorts = #()
			for i = 1 to ((chunk.Size - 0x00000094) / 2) do append UnknownShorts (ReadShort w3dStream #unsigned)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 16) #seek_set
			return Name = ReadW3DNameLen w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:Version:%\n" Version to:dumpStream
			format "1:Flags:%\n" Flags to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:UnknownLong:%\n" UnknownLong to:dumpStream
			format "1:UnknownPoint3s:%\n" UnknownPoint3s to:dumpStream
			format "1:TextureName:%\n" TextureName to:dumpStream
			format "1:UnknownShorts:%\n" UnknownShorts to:dumpStream
		)
	)

	struct W3D_CHUNK_SPHERE																			-- 0x00000741
	(
		chunk,								-- W3D_CHUNK()
		sphereHeader,						-- W3D_CHUNK_SPHERE_HEADER()						0x00000001

		fn readChunk w3dStream=
		(
			(local c = W3D_CHUNK()).readHeader w3dStream
			(sphereHeader = (W3D_CHUNK_SPHERE_HEADER c)).readChunk w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000001) > 0 do
				return (local n = W3D_CHUNK_SPHERE_HEADER()).getName w3dStream headerOffset;
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_SPHERE]\n" to:dumpStream
			format "1:[W3D_CHUNK_SPHERE_HEADER]\n" to:dumpStream
			sphereHeader.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_RING																			-- 0x00000742
	(
		chunk,								-- W3D_CHUNK()
		ringHeader,						-- W3D_CHUNK_SPHERE_HEADER()						0x00000001

		fn readChunk w3dStream=
		(
			(local c = W3D_CHUNK()).readHeader w3dStream
			(ringHeader = (W3D_CHUNK_SPHERE_HEADER c)).readChunk w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000001) > 0 do
				return (local n = W3D_CHUNK_SPHERE_HEADER()).getName w3dStream headerOffset;
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_RING]\n" to:dumpStream
			format "1:[W3D_CHUNK_RING_HEADER]\n" to:dumpStream
			ringHeader.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_NULL_OBJECT							-- 0x00000750
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Flags,
		Pad,
		Name,
		Container,

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Flags = ReadLong w3dStream #unsigned
			Pad = ReadLong w3dStream #unsigned
			Name = (local W3DName = ReadW3DNameLen w3dStream ContainerName:true)[1]
			Container = W3DName[2]
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_NULL_OBJECT]\n" to:dumpStream
			format "0:Version:%\n" Version to:dumpStream
			format "0:Flags:%\n" Flags to:dumpStream
			format "0:Pad:%\n" Pad to:dumpStream
			format "0:Name:%.%\n" Container Name to:dumpStream
		)
	)

	struct W3D_CHUNK_DAZZLE_NAME																	-- 0x00000901
	(
		chunk,								-- W3D_CHUNK()
		Name,
		Container,

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 8) #seek_set
			return ReadW3DNameLen w3dStream ContainerName:true;
		),

		fn readChunk w3dStream=
		(
			Name = (local W3DName = ReadW3DNameLen w3dStream ContainerName:true)[1]
			Container = W3DName[2]
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_DAZZLE_NAME]\n" to:dumpStream
			format "1:Dazzle Name:%.%\n" Container Name to:dumpStream
		)
	)

	struct W3D_CHUNK_DAZZLE_TYPENAME																-- 0x00000902
	(
		chunk,								-- W3D_CHUNK()
		Name,

		fn readChunk w3dStream= ( Name = ReadNullTerminatedString w3dStream ),
		fn dumpChunk dumpStream= ( format "1:[W3D_CHUNK_DAZZLE_TYPENAME]\n1:Dazzle Type Name:%\n" Name to:dumpStream )
	)

	struct W3D_CHUNK_DAZZLE																			-- 0x00000900
	(
		chunk,								-- W3D_CHUNK()
		dazzleName,							-- W3D_CHUNK_DAZZLE_NAME()							0x00000901
		dazzleTypeName,						-- W3D_CHUNK_DAZZLE_TYPENAME()						0x00000902

		fn readChunk w3dStream=
		(
			(local c = W3D_CHUNK()).readHeader w3dStream
			(dazzleName = (W3D_CHUNK_DAZZLE_NAME c)).readChunk w3dStream
			(c = W3D_CHUNK()).readHeader w3dStream
			(dazzleTypeName = (W3D_CHUNK_DAZZLE_TYPENAME c)).readChunk w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000901) > 0 do
				return (local n = W3D_CHUNK_DAZZLE_NAME()).getName w3dStream headerOffset;
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_DAZZLE]\n" to:dumpStream
			dazzleName.dumpChunk dumpStream
			dazzleTypeName.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_SOUNDROBJ_HEADER																-- 0x00000a01
	(
		chunk,								-- W3D_CHUNK()
		Version,
		Name,
		Flags,
		Padding = #(),

		fn readChunk w3dStream=
		(
			Version = ReadVersion w3dStream
			Name = ReadW3DNameLen w3dStream
			Flags = ReadLong w3dStream #unsigned
			Padding = #()
			for i = 1 to 8 do append Padding (ReadLong w3dStream #unsigned)
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream (fOffset + 12) #seek_set
			return Name = ReadW3DNameLen w3dStream;
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SOUNDROBJ_HEADER]\n" to:dumpStream
			format "1:Version:%\n" Version to:dumpStream
			format "1:Name:%\n" Name to:dumpStream
			format "1:Flags:%\n" Flags to:dumpStream
--			format "1:Padding:%\n" Padding to:dumpStream
		)
	)

	struct W3D_CHUNK_SOUNDROBJ_DEFINITION															-- 0x00000a02
	(
		chunk,								-- W3D_CHUNK()
		ParamSize,
		ParamTypes = #(),
		ParamValues = #(),
		SoundFile,

		fn readChunk w3dStream=
		(
			ParamTypes = #()
			ParamValues = #()

			if (ReadLong w3dStream #unsigned) != 0x0100 do return false;
			ParamSize = (bit.and (ReadLong w3dStream #unsigned) 0x7fffffff)

			local fOffset = ftell w3dStream			
			local fEOF = fOffset + ParamSize

			while (fOffset) < fEOF do
			(
				local paramID = ReadShort w3dStream #unsigned
				append ParamTypes paramID

				case paramID of
				(
					0x0103: append ParamValues (ReadByte w3dStream #unsigned)
					0x010f: append ParamValues (ReadByte w3dStream #unsigned)
					0x0401: append ParamValues (ReadFloat w3dStream)
					0x0402: append ParamValues (ReadFloat w3dStream)
					0x0403: append ParamValues (ReadFloat w3dStream)
					0x0404: append ParamValues (ReadFloat w3dStream)
					0x0405: append ParamValues (ReadFloat w3dStream)
					0x0406: append ParamValues (ReadFloat w3dStream)
					0x0407: append ParamValues (ReadFloat w3dStream)
					0x0408: append ParamValues (ReadFloat w3dStream)
					0x0409:	append ParamValues #((ReadShort w3dStream #unsigned), (ReadShort w3dStream #unsigned), \
													(ReadShort w3dStream #unsigned))
					0x040d: append ParamValues (ReadFloat w3dStream)
					0x040e: append ParamValues (ReadFloat w3dStream)
					0x0410: append ParamValues (ReadFloat w3dStream)
					0x0412: append ParamValues (ReadFloat w3dStream)
					0x0b01:
					(
						SoundFile = ""
						local nameLen = ReadByte w3dStream #unsigned
						for i = 1 to nameLen do SoundFile += (bit.IntAsChar (ReadByte w3dStream #unsigned))
						local byte1 = ReadByte w3dStream #unsigned
						local short1 = ReadShort w3dStream #unsigned
						append ParamValues #(SoundFile, byte1, short1)
					)
					0x0c11:	append ParamValues (ReadPoint3 w3dStream)
				)

				fOffset = ftell w3dStream
			)
		),

		fn dumpChunk dumpStream=
		(
			format "1:[W3D_CHUNK_SOUNDROBJ_DEFINITION]\n" to:dumpStream
			format "1:ParamSize:%\n" ParamSize to:dumpStream
			for i = 1 to ParamTypes.count do
			(
				format "1:ParamTypes[%]:0x%\n" i (bit.IntAsHex ParamTypes[i]) to:dumpStream
				format "1:ParamValues[%]:%\n" i ParamValues[i] to:dumpStream
			)
		)
	)

	struct W3D_CHUNK_SOUNDROBJ																		-- 0x00000a00
	(
		chunk,								-- W3D_CHUNK()
		soundRenderObjectHeader,			-- W3D_CHUNK_SOUNDROBJ_HEADER()						0x00000a01
		soundRenderObjectDefinition,		-- W3D_CHUNK_SOUNDROBJ_DEFINITION()					0x00000a02

		fn readChunk w3dStream=
		(
			(local c = W3D_CHUNK()).readHeader w3dStream
			(soundRenderObjectHeader = (W3D_CHUNK_SOUNDROBJ_HEADER c)).readChunk w3dStream
			(c = W3D_CHUNK()).readHeader w3dStream
			(soundRenderObjectDefinition = (W3D_CHUNK_SOUNDROBJ_DEFINITION c)).readChunk w3dStream
		),

		fn getName w3dStream fOffset=
		(
			fseek w3dStream fOffset #seek_set
			(local c = W3D_CHUNK()).readHeader w3dStream

			if (local headerOffset = getChunks w3dStream c.Start c.Size ofID:0x00000a01) > 0 do
				return (local n = W3D_CHUNK_SOUNDROBJ_HEADER()).getName w3dStream headerOffset;
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_SOUNDROBJ]\n" to:dumpStream
			soundRenderObjectHeader.dumpChunk dumpStream
			soundRenderObjectDefinition.dumpChunk dumpStream
		)
	)

	struct W3D_CHUNK_0X0B00																			-- 0x00000b00
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn getDependencies w3dStream=
		(
			return #();
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_0x0B00]\n" to:dumpStream
		)
	)
	
	struct W3D_CHUNK_UNKNOWN
	(
		chunk,								-- W3D_CHUNK()

		fn readChunk w3dStream=
		(
			return 0;
		),

		fn dumpChunk dumpStream=
		(
			format "0:[W3D_CHUNK_UNKNOWN]\n" to:dumpStream
		)
	)

	struct W3D_FILE
	(
		w3dFileInfo,						-- W3DInfo()
		w3d_Hierarchy,						-- W3D_CHUNK_HIERARCHY()							0x00000100
		w3d_Animation,						-- W3D_CHUNK_ANIMATION()							0x00000200
		w3d_CompressedAnimation,			-- W3D_CHUNK_COMPRESSED_ANIMATION()					0x00000280
		w3d_MorphAnimation,					-- W3D_CHUNK_MORPH_ANIMATION()						0x000002c0
		w3d_HModel,							-- W3D_CHUNK_HMODEL()								0x00000300
		w3d_Collection,						-- W3D_CHUNK_COLLECTION()							0x00000420
		w3d_Emitter,						-- W3D_CHUNK_EMITTER()								0x00000500
		w3d_Aggregate,						-- W3D_CHUNK_AGGREGATE()							0x00000600
		w3d_SoundRenderObject,				-- W3D_CHUNK_SOUNDROBJ()							0x00000a00
		w3d_HLOD,							-- W3D_CHUNK_HLOD()									0x00000700
		w3d_Mesh = #(),						-- W3D_CHUNK_MESH() ARRAY							0x00000000
		w3d_Box = #(),						-- W3D_CHUNK_BOX() ARRAY							0x00000740
		w3d_Sphere = #(),					-- W3D_CHUNK_SPHERE() ARRAY							0x00000741
		w3d_Ring = #(),						-- W3D_CHUNK_RING() ARRAY							0x00000742
		w3d_Dazzle = #(),					-- W3D_CHUNK_DAZZLE() ARRAY							0x00000900
		w3d_0x0B00 = #(),					-- W3D_CHUNK_0x0B00() ARRAY							0x00000b00
		w3d_80000000 = #(),					-- W3D_CHUNK_UNKNOWN() ARRAY
		chunks = #(),
		lastfName,
		w3dStream,
		exportType,
		modelName,
		skeletonName,
		numFrames,

		fn openW3D fInfo=
		(
			if (w3dStream = fopen (w3dFileInfo = fInfo).fName "rb") == undefined do return false;
			fseek w3dStream w3dFileInfo.fStart #seek_set
			return true;
		),

		fn closeW3D= ( fclose w3dStream ),

		fn getW3DChunks= ( chunks = getChunks w3dStream w3dFileInfo.fStart w3dFileInfo.fSize ),

		fn getW3DInfo fInfo rejectTypes:0 getFrames:false closeAfter:false=
		(
			modelName = ""
			skeletonName = ""
			exportType = 0
			numFrames = 0

			if closeAfter then openW3D fInfo
			else
			(
				if fInfo.fName == lastfName then fseek w3dStream (w3dFileInfo = fInfo).fStart #seek_set
				else ( closeW3D(); openW3D fInfo)

				lastfName = w3dFileInfo.fName
			)

			getW3DChunks()
			local chunkIDs = for a in chunks collect a[1]
			
			if finditem chunkIDs 0x00000000 > 0 do
			(
				if chunkIDs.count == 1 then
				(
					if (bit.and rejectTypes 512) == 512 do return #();
					exportType = 512
				)
				else exportType = (bit.or exportType 2)
			)
		
			if findItem chunkIDs 0x00000420 > 0 do
			(
				if (bit.and rejectTypes 1024) == 1024 do return #();
				exportType = (bit.or exportType 1024)
			)

			if (local i = finditem chunkIDs 0x00000100) > 0 do
			(
				if (bit.and rejectTypes 1) == 1 do return #();
				exportType = (bit.or exportType 1)

				skeletonName = modelName = (w3d_Hierarchy = W3D_CHUNK_HIERARCHY()).getName w3dStream chunks[i][2]
			)

			if (local i = finditem chunkIDs 0x00000200) > 0 do
			(
				if (bit.and rejectTypes 4) == 4 do return #();
				exportType = (bit.or exportType 4)

				if modelName == "" or getFrames do
				(
					local props = (local a = W3D_CHUNK_ANIMATION()).getName w3dStream chunks[i][2]

					if modelName == "" do (modelName = props[1]; skeletonName = props[2])
					if getFrames do numFrames = props[3]
				)
			)

			if (local i = finditem chunkIDs 0x00000280) > 0 do
			(
				if (bit.and rejectTypes 4) == 4 do return #();
				exportType = (bit.or exportType 4)

				if modelName == "" or getFrames do
				(
					local props = (local a = W3D_CHUNK_COMPRESSED_ANIMATION()).getName w3dStream chunks[i][2]

					if modelName == "" do (modelName = props[1]; skeletonName = props[2])
					if getFrames do numFrames = props[3]
				)
			)

			if (local i = finditem chunkIDs 0x000002c0) > 0 do
			(
				if (bit.and rejectTypes 4) == 4 do return #();
				exportType = (bit.or exportType 4)

				if modelName == "" or getFrames do
				(
					local props = (local a = W3D_CHUNK_MORPH_ANIMATION()).getName w3dStream chunks[i][2]

					if modelName == "" do (modelName = props[1]; skeletonName = props[2])
					if getFrames do numFrames = props[3]
				)
			)

			if (local i = finditem chunkIDs 0x00000300) > 0 do
			(
				if (bit.and rejectTypes 32) == 32 do return #();
				exportType = (bit.or exportType 32)

				if modelName == "" do
				(
					modelName = (local nameArray = (w3d_HModel = W3D_CHUNK_HMODEL()).getName w3dStream chunks[i][2])[1]
					skeletonName = nameArray[2]
				)
			)

			if (local i = finditem chunkIDs 0x00000500) > 0 do
			(
				if (bit.and rejectTypes 64) == 64 do return #();
				exportType = (bit.or exportType 64)

				modelName = (w3d_Emitter = W3D_CHUNK_EMITTER()).getName w3dStream chunks[i][2]
			)

			if (local i = finditem chunkIDs 0x00000600) > 0 do
			(
				if (bit.and rejectTypes 16) == 16 do return #();
				exportType = (bit.or exportType 16)

				modelName = (local nameArray = (w3d_Aggregate = W3D_CHUNK_AGGREGATE()).getName w3dStream chunks[i][2])[1]
				skeletonName = nameArray[2]
			)

			if (local i = finditem chunkIDs 0x00000700) > 0 do
			(
				if (bit.and rejectTypes 8) == 8 do return #();
				exportType = (bit.or exportType 8)

				w3d_HLOD = W3D_CHUNK_HLOD()
				if w3d_HLOD.hasAggregate w3dStream chunks[i][2] do exportType = (bit.or exportType 16)

				if modelName == "" do
				(
					modelName = (local nameArray = w3d_HLOD.getName w3dStream chunks[i][2])[1]
					skeletonName = nameArray[2]
				)
			)

			if (local i = finditem chunkIDs 0x00000740) > 0 do
			(
				if (bit.and rejectTypes 256) == 256 do return #();
				exportType = (bit.or exportType 256)

				if modelName == "" do
				(
					w3d_Box[1] = W3D_CHUNK_BOX()
					if (local nameArray = w3d_Box[1].getName w3dStream chunks[i][2]) != undefined do
					(
						modelName = nameArray[1]
						skeletonName = nameArray[2]
					)
				)
			)

			if (local i = finditem chunkIDs 0x00000741) > 0 do
			(
				if (bit.and rejectTypes 256) == 256 do return #();
				exportType = (bit.or exportType 256)

				if modelName == "" do
				(
					modelName = (local nameArray = (w3d_Sphere[1] = W3D_CHUNK_SPHERE()).getName w3dStream chunks[i][2])[1]
					skeletonName = nameArray[2]
				)
			)

			if (local i = finditem chunkIDs 0x00000742) > 0 do
			(
				if (bit.and rejectTypes 256) == 256 do return #();
				exportType = (bit.or exportType 256)

				if modelName == "" do
				(
					modelName = (local nameArray = (w3d_Ring[1] = W3D_CHUNK_RING()).getName w3dStream chunks[i][2])[1]
					skeletonName = nameArray[2]
				)
			)

			if finditem chunkIDs 0x00000900 > 0 do
			(
				if (bit.and rejectTypes 2048) == 2048 do return #();
				exportType = (bit.or exportType 2048)
			)

			if (local i = finditem chunkIDs 0x00000a00) > 0 do
			(
				if (bit.and rejectTypes 128) == 128 do return #();
				exportType = (bit.or exportType 128)

				modelName = (w3d_SoundRenderObject = W3D_CHUNK_SOUNDROBJ()).getName w3dStream chunks[i][2]
			)

			if closeAfter do closeW3D()

			if exportType > 0 then
			(
				local infoArray = #(modelName, skeletonName, exportType)
				if getFrames do append infoArray numFrames
				return infoArray;
			)
			else return #();
		),

		fn getDependencies IDs:#(0, 0x420, 0x500, 0x600, 0x700, 0x705, 0x741, 0x742, 0x900, 0xa00, 0xb00)=
		(
			getW3DChunks()

			local deps = #()
			for i = 1 to chunks.count do
			(
				fseek w3dStream chunks[i][2] #seek_set

				local s
				(local c = W3D_CHUNK()).readHeader w3dStream
				case chunks[i][1] of
				(
					0x0000: if finditem IDs 0x000 > 0 do join deps ((s = (W3D_CHUNK_MESH c)).getDependencies w3dStream)
					0x0420: if finditem IDs 0x420 > 0 do join deps ((s = (W3D_CHUNK_COLLECTION c)).getDependencies w3dStream)
					0x0500: if finditem IDs 0x500 > 0 do join deps ((s = (W3D_CHUNK_EMITTER c)).getDependencies w3dStream)
					0x0600: if finditem IDs 0x600 > 0 do join deps ((s = (W3D_CHUNK_AGGREGATE c)).getDependencies w3dStream)
					0x0700:
					(
						if finditem IDs 0x700 > 0 do join deps ((s = (W3D_CHUNK_HLOD c)).getDependencies w3dStream)
						if finditem IDs 0x705 > 0 do join deps ((s = (W3D_CHUNK_HLOD c)).getDependencies w3dStream forAggregate:true)
					)
					0x0741: if finditem IDs 0x741 > 0 do join deps ((s = (W3D_CHUNK_SPHERE c)).getDependencies w3dStream)
					0x0742: if finditem IDs 0x742 > 0 do join deps ((s = (W3D_CHUNK_RING c)).getDependencies w3dStream)
					0x0900: if finditem IDs 0x900 > 0 do join deps ((s = (W3D_CHUNK_DAZZLE c)).getDependencies w3dStream)
					0x0a00: if finditem IDs 0xa00 > 0 do join deps ((s = (W3D_CHUNK_SOUNDROBJ c)).getDependencies w3dStream)
					0x0b00: if finditem IDs 0xb00 > 0 do join deps ((s = (W3D_CHUNK_0x0B00 c)).getDependencies w3dStream)
				)
			)

			local uniqueDeps = #((getFileNameFile w3dFileInfo.w3dName) + (getFileNameType w3dFileInfo.w3dName))
			if skeletonName != modelName do append deps skeletonName
			for a in deps where (findItem uniqueDeps a) == 0 do append uniqueDeps a
			closeW3D()
			return uniqueDeps;
		),

		fn readW3D fInfo=
		(
			openW3D fInfo
			getW3DChunks()

			for c in chunks do
			(
				fseek w3dStream c[2] #seek_set
				(local chnk = W3D_CHUNK()).readHeader w3dStream
				case c[1] of
				(
					0x0000: (w3d_Mesh[(w3d_Mesh.count + 1)] = (W3D_CHUNK_MESH chnk)).readChunk w3dStream
					0x0100:	(w3d_Hierarchy = (W3D_CHUNK_HIERARCHY chnk)).readChunk w3dStream
					0x0200:	(w3d_Animation = (W3D_CHUNK_ANIMATION chnk)).readChunk w3dStream
					0x0280:	(w3d_CompressedAnimation = (W3D_CHUNK_COMPRESSED_ANIMATION chnk)).readChunk w3dStream
					0x02c0:	(w3d_MorphAnimation = (W3D_CHUNK_MORPH_ANIMATION chnk)).readChunk w3dStream
					0x0300:	(w3d_HModel = (W3D_CHUNK_HMODEL chnk)).readChunk w3dStream
					0x0420:	(w3d_Collection = (W3D_CHUNK_COLLECTION chnk)).readChunk w3dStream
					0x0500:	(w3d_Emitter = (W3D_CHUNK_EMITTER chnk)).readChunk w3dStream
					0x0600:	(w3d_Aggregate = (W3D_CHUNK_AGGREGATE chnk)).readChunk w3dStream
					0x0700:	(w3d_HLOD = (W3D_CHUNK_HLOD chnk)).readChunk w3dStream
					0x0740:	(w3d_Box[(w3d_Box.count + 1)] = (W3D_CHUNK_BOX chnk)).readChunk w3dStream
					0x0741:	(w3d_Sphere[(w3d_Sphere.count + 1)] = (W3D_CHUNK_SPHERE chnk)).readChunk w3dStream
					0x0742:	(w3d_Ring[(w3d_Ring.count + 1)] = (W3D_CHUNK_RING chnk)).readChunk w3dStream
					0x0900:	(w3d_Dazzle[(w3d_Dazzle.count + 1)] = (W3D_CHUNK_DAZZLE chnk)).readChunk w3dStream
					0x0a00:	(w3d_SoundRenderObject = (W3D_CHUNK_SOUNDROBJ chnk)).readChunk w3dStream
					0x0b00:	(w3d_0x0B00 = (W3D_CHUNK_0x0B00 chnk)).readChunk w3dStream
				)
			)

			closeW3D()
		),

		fn dumpW3D fInfo=
		(
			readW3D fInfo

			local meshCount = 0
			local boxCount = 0
			local sphereCount = 0
			local ringCount = 0
			local dazzleCount = 0
			local dumpStream = stringstream ""

			for c in chunks do
			(
				case c[1] of
				(
					0x0000: (meshCount += 1; w3d_Mesh[meshCount].dumpChunk dumpStream)
					0x0100: w3d_Hierarchy.dumpChunk dumpStream
					0x0200: w3d_Animation.dumpChunk dumpStream
					0x0280:	w3d_CompressedAnimation.dumpChunk dumpStream
					0x02c0:	w3d_MorphAnimation.dumpChunk dumpStream
					0x0300: w3d_HModel.dumpChunk dumpStream
					0x0420:	w3d_Collection.dumpChunk dumpStream
					0x0500:	w3d_Emitter.dumpChunk dumpStream
					0x0600:	w3d_Aggregate.dumpChunk dumpStream
					0x0700:	w3d_HLOD.dumpChunk dumpStream
					0x0740: (boxCount += 1; w3d_Box[boxCount].dumpChunk dumpStream)
					0x0741: (sphereCount += 1; w3d_Sphere[sphereCount].dumpChunk dumpStream)
					0x0742: (ringCount += 1; w3d_Ring[ringCount].dumpChunk dumpStream)
					0x0900: (dazzleCount += 1; w3d_Dazzle[dazzleCount].dumpChunk dumpStream)
					0x0a00: w3d_SoundRenderObject.dumpChunk dumpStream
					0x0b00:	w3d_0x0B00.dumpChunk dumpStream
				)
			)

			seek dumpStream 0
			clearListener()
			local listenerStream = stringstream ""

			while not (eof dumpStream) do
			(
				local strArray = filterString (readLine dumpStream) ":"
				local lvlStr = ""

				for i = 1 to (strArray[1] as integer) do lvlStr += "\t"
				if strArray[2][1] == "[" then format "\n%%\n" lvlStr strArray[2] to:listenerStream
				else
				(
					local tabStr = ""
					for j = 1 to (8 - ((strArray[2].count + 2) / 4)) do tabStr += "\t"
					format "% %:%%\n" lvlStr strArray[2] tabStr strArray[3] to:listenerStream
				)
			)
			format "%" (listenerStream as string)
		)
	)

	struct SCENE_MATERIALS
	(
		Materials,
		TextureMaps,
		PassCounts,

		fn AddNewMaterial Name Pass Maps=
		(
			local index = finditem Materials Name
			if index == 0 then
			(
				append Materials Name
				append Materials Pass
				for i = 1 to Pass do
				append Materials Maps[i]
			)
		)
	)

	struct MIX_FILE
	(
		MixFilesOffset,
		MixNamesOffset,
		MixNumFilesNames,
		MixNumFiles,
		MixfOffset,
		MixfSize,
		MixfName,
		MixStream,

		fn getFilesNames typeFilter mixIndex updateProgress:false=
		(
			local filesArray = #()

			if updateProgress do
			(
				local searchTypeStr = ("Searching " + (getFileNameFile MixfName) + (getFileNameType MixfName))
				searchTypeStr += if (findItem typeFilter "*.w3d") > 0 then " for w3d files..." else " for texture files..."
				W3DImportProgressDlg.Stage.text = searchTypeStr
			)

			for i = 1 to MixNumFiles do
			(
				local fName = ""
				local fNameLen = ReadByte MixStream #unsigned
				for j = 1 to fNameLen do fName += (bit.IntAsChar (readByte MixStream #unsigned))

				for a in typeFilter where matchPattern fName pattern:a do
				(
					local curOffset = ftell MixStream
					fseek MixStream (MixFilesOffset + (12 * (i-1)) + 8) #seek_Set
					MixfOffset = ReadLong MixStream #unsigned
					MixfSize = ReadLong MixStream #unsigned
					fseek MixStream curOffset #seek_set

					append filesArray #(fName, mixIndex, MixfOffset, MixfSize)
					exit;
				)

				if updateProgress do W3DImportProgressDlg.updateProgress i MixNumFiles
			)
			return filesArray;
		),

		fn close= ( fclose MixStream ),

		fn open fName=
		(
			local mixID = ""

			MixfName = fName
			MixStream = fopen fName "rb"
			fseek Mixstream 0 #seek_set

			for i = 1 to 4 do mixID += bit.IntAsChar (readByte MixStream #unsigned)
			if mixID != "MIX1" then
			(
				fclose MixStream
				return false;
			)

			MixFilesOffset = ReadLong MixStream #unsigned
			MixNamesOffset = ReadLong MixStream #unsigned

			fseek MixStream MixFilesOffset #seek_Set
			MixNumFiles = ReadLong MixStream #unsigned

			fseek MixStream MixNamesOffset #seek_Set
			MixNumFilesNames = ReadLong MixStream #unsigned

			if MixNumFiles != MixNumFilesNames then
			(
				print "Warning: Num Files doesnt match Num Files Names !"
				format "MixNumFiles = %, MixNumFilesNames = %\n" MixNumFiles MixNumFilesNames
			)

			return true;
		)
	)

	struct BIG_FILE
	(
		BigFileSize,
		BigNumFiles,
		BigFilesHeaders,
		BigStream,
		BigfOffset,
		BigfSize,
		BigfName,

		fn getFilesNames typeFilter bigIndex updateProgress:false=
		(
			fseek BigStream BigFilesHeaders #seek_Set

			local filesArray = #()

			if updateProgress do
			(
				local searchTypeStr = ("Searching " + (getFileNameFile BigfName) + (getFileNameType BigfName))
				searchTypeStr += if (findItem typeFilter "*.w3d") > 0 then " for w3d files..." else " for texture files..."
				W3DImportProgressDlg.Stage.text = searchTypeStr
			)

			for i = 1 to BigNumFiles do
			(
				local fOffset = ReadLongReversed BigStream
				local fSize = ReadLongReversed BigStream
				local fName = ReadNullTerminatedString BigStream

				for a in typeFilter where matchPattern fName pattern:a do
				(
					append filesArray #(fName, bigIndex, fOffset, fSize)
					exit;
				)

				if updateProgress do W3DImportProgressDlg.updateProgress i BigNumFiles
			)
			return filesArray;
		),

		fn close= ( fclose BigStream ),

		fn open fName=
		(
			local bigID = ""

			BigfName = fName
			BigStream = fopen fName "rb"
			fseek BigStream 0 #seek_set

			for i = 1 to 4 do bigID += bit.IntAsChar (readByte BigStream #unsigned)
			if bigID != "BIG4" and bigID != "BIGF" then
			(
				fclose BigStream
				return false;
			)

			BigFileSize = ReadLong BigStream #unsigned
			BigNumFiles = ReadLongReversed BigStream
			ReadLong BigStream

			BigFilesHeaders = ftell BigStream

			return true;
		)
	)
	
	struct W3D_FILES_LIST
	(
		fileNames,
		filesArray,

		fn getFilesArray curPath typePatterns mixSkip:#() datSkip:#() bigSkip:#()=
		(
			local bigArray = #()
			fileNames = #()
			filesArray = #()

			for a in (getFiles (curPath + "*.*")) do
			(
				for b in typePatterns where matchPattern a pattern:b do
				(
					append fileNames a
					append filesArray #(((getFileNameFile a) + (getFileNameType a)), fileNames.count, 0, (getFileSize a))
					exit;
				)
			)

			bigArray = (getFiles (curPath + "*.pkg"))
			for a in (getFiles (curPath + "*.mix")) do
			(
				local ignore = false
				for b in mixSkip do if matchPattern (getFileNameFile a) pattern:b do (ignore = true; exit;)
				if not ignore do append bigArray a
			)	
			for a in (getFiles (curPath + "*.dat")) do if findItem datSkip ((getFileNameFile a) as name) == 0 then append bigArray a
			for a in (getFiles (curPath + "*.big")) do if findItem bigskip ((getFileNameFile a) as name) == 0 then append bigArray a

			for i = 1 to bigArray.count do
			(
--				gc()
				if matchPattern (getFileNameType bigArray[i]) pattern:".big" and (local BigFile = BIG_FILE()).open bigArray[i] then
				(
					append fileNames bigArray[i]
					join filesArray (BigFile.getFilesNames typePatterns i updateProgress:true)
					BigFile.close
				)
				else if (local MixFile = MIX_FILE()).open bigArray[i] then
				(
					append fileNames bigArray[i]
					join filesArray (MixFile.getFilesNames typePatterns i updateProgress:true)
					MixFile.close
				)
			)
		),
		fn sortFiles= ( qsort filesArray compareArrays ),
		fn getFileInfo fID=	( (W3DInfo filesArray[fID][1] fileNames[filesArray[fID][2]] filesArray[fID][3] filesArray[fID][4]) )
	)


-------------------------------------------------- W3D Importer Functions ------------------------------------------------


/*
	fn getW3DHierarchy w3df=
	(
		local fStream = fopen w3df[1] "rb"

		W3Dchunk.FindChunk fStream 0x00000100 w3df[2] w3df[3] resetOffset:true
		local ChunkHeaderStart = W3Dchunk.Start
		local ChunkHeaderSize = W3Dchunk.Size

		while W3DFileOffset < (ChunkHeaderStart + ChunkHeaderSize) do
		(
			fseek fStream W3DFileOffset #seek_set
			local ChunkID = W3Dchunk.getChunkID fStream

			case ChunkID of
			(
				0x00000101: W3DHierarchyHeader.ReadW3D fStream

				0x00000102:
				(
					local bPos

					for i = 1 to W3DHierarchyHeader.NumBones do
					(
						W3DPivots.ReadW3D fStream
						if i > 1 do
						(
							bPos = W3DPivots.Translation
							if W3DPivots.ParentID > 0 do bPos += w3d.bonesArray[W3DPivots.ParentID][3]

							append w3d.bonesArray #(W3DPivots.Name, W3DPivots.ParentID, bPos, W3DPivots.Rotation, W3DPivots.Euler)
						)
					)
				)
				0x00000103:
				(
					for i = 1 to W3DHierarchyHeader.NumBones do
					(
						W3DPivotFixups.ReadW3D fStream
						if i > 1 do append w3d.pivotsFixups W3DPivotFixups.PivotMatrix3
					)
				)

				default: W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
			)
		)

		fclose fStream
		return true;
	)

	fn getW3DAnimation w3df=
	(
		local ChunkHeaderStart, ChunkHeaderSize, NextChunk
		local fStream = fopen w3df[1] "rb"

		if (W3Dchunk.FindChunk fStream 0x00000200 w3df[2] w3df[3] resetOffset:true) or \
			(W3Dchunk.FindChunk fStream 0x00000280 w3df[2] w3df[3] resetOffset:true) do
		(
			ChunkHeaderStart = W3Dchunk.Start
			ChunkHeaderSize = W3Dchunk.Size
			NextChunk = ChunkHeaderStart + ChunkHeaderSize
		)

		while W3DFileOffset < NextChunk do
		(
			fseek fStream W3DFileOffset #seek_set
			local ChunkID = W3Dchunk.getChunkID fStream

			case ChunkID of
			(
				0x00000201:
				(
					W3DAnimHeader.ReadW3D fStream
					
					w3d.animFramesCount = W3DAnimHeader.NumFrames
					w3d.animFrameRate = W3DAnimHeader.FrameRate
				)
				0x00000202:
				(
					W3DAnimChannel.ReadW3D fStream
					append w3d.animBones #(W3DAnimChannel.Pivot, W3DAnimChannel.VectorLen, W3DFileOffset)
					append w3d.animInfo #(W3DAnimChannel.ChannelType, W3DAnimChannel.FirstFrame, W3DAnimChannel.LastFrame)
					W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
				)
--				0x00000203:
--				(
--					W3DBitChannel.ReadW3D fStream
--					append w3d.animBones #(W3DBitChannel.Pivot, W3DBitChannel.DefaultVal, W3DFileOffset)
--					append w3d.animInfo #(W3DBitChannel.ChannelType, W3DBitChannel.FirstFrame, W3DBitChannel.LastFrame)
--					W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
--				)

				0x00000281:
				(
					W3DCompressedAnimHeader.ReadW3D fStream
					
					w3d.animFramesCount = W3DCompressedAnimHeader.NumFrames
					w3d.animFrameRate = W3DCompressedAnimHeader.FrameRate
					W3DFileOffset = ChunkHeaderStart + ChunkHeaderSize
				)
--				0x00000282:
--				(
--					W3DAnimChannel.ReadW3D fStream
--					append w3d.animBones #(W3DAnimChannel.Pivot, W3DAnimChannel.VectorLen, W3DFileOffset)
--					append w3d.animInfo #(W3DAnimChannel.ChannelType, W3DAnimChannel.FirstFrame, W3DAnimChannel.LastFrame)
--					W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
--				)

--				0x000002c0:
--				(
--					ChunkHeaderStart = W3Dchunk.Start
--					ChunkHeaderSize = W3Dchunk.Size
--					W3DFileOffset = W3Dchunk.Start
--				)
				default: W3DFileOffset = NextChunk
			)
		)

		fclose fStream
		return true;
	)

	fn getW3DHLOD w3df=
	(
		local fStream = fopen w3df[1] "rb"

		W3Dchunk.FindChunk fStream 0x00000700 w3df[2] w3df[3] resetOffset:true
		local ChunkHeaderStart = W3Dchunk.Start
		local ChunkHeaderSize = W3Dchunk.Size

		while W3DFileOffset < (ChunkHeaderStart + ChunkHeaderSize) do
		(
			fseek W3Dstream W3DFileOffset #seek_set
			local ChunkID = W3Dchunk.getChunkID fStream

			case ChunkID of
			(
				0x00000701:
				(
					W3DHLODHeader.ReadW3D fStream
					w3d.LODCount = W3DHLODHeader.LODCount

					for i = w3d.LODCount to 1 by -1 do
					(
						W3Dchunk.FindChunk fStream 0x00000702 ChunkHeaderStart ChunkHeaderSize
						local HLODArrayStart = W3Dchunk.Start
						local HLODArraySize = W3Dchunk.Size

						W3Dchunk.FindChunk fStream 0x00000703 HLODArrayStart HLODArraySize
						W3DHLODArrayHeader.ReadW3D fStream

						for j = 1 to W3DHLODArrayHeader.ModelCount do
						(
							W3Dchunk.FindChunk fStream 0x00000704 HLODArrayStart HLODArraySize
							W3DHLODSubObject.ReadW3D fStream

							append w3d.LODModelsArray #(i, W3DHLODSubObject.Container, W3DHLODSubObject.Name, W3DHLODSubObject.BoneIndex) 
						)
					)
				)

				0x00000705:
				(
					local AggregateArrayStart = W3Dchunk.Start
					local AggregateArraySize = W3Dchunk.Size

					W3DFileOffset = W3Dchunk.Start

					W3Dchunk.FindChunk fStream 0x00000703 AggregateArrayStart AggregateArraySize
					W3DHLODArrayHeader.ReadW3D fStream
					w3d.aggregatesCount = W3DHLODArrayHeader.ModelCount

					for i = 1 to w3d.aggregatesCount do
					(
						W3Dchunk.FindChunk fStream 0x00000704 AggregateArrayStart AggregateArraySize
						W3DHLODSubObject.ReadW3D fStream

						append w3d.aggregatesArray #(W3DHLODSubObject.Name, W3DHLODSubObject.BoneIndex)
					)
				)

				0x00000706:
				(
					local ProxyArrayStart = W3Dchunk.Start
					local ProxyArraySize = W3Dchunk.Size

					W3DFileOffset = W3Dchunk.Start

					W3Dchunk.FindChunk fStream 0x00000703 ProxyArrayStart ProxyArraySize
					W3DHLODArrayHeader.ReadW3D fStream

					for i = 1 to W3DHLODArrayHeader.ModelCount do
					(
						W3Dchunk.FindChunk fStream 0x00000704 ProxyArrayStart ProxyArraySize
						W3DHLODSubObject.ReadW3D fStream

						append w3d.proxiesArray w3d.bonesArray[W3DHLODSubObject.BoneIndex]
					)
				)

				default: W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
			)
		)

		fclose fStream
		return true;
	)

	fn getW3DObjects w3df=
	(
		local fStream = fopen w3df[1] "rb"
		W3DFileOffset = w3df[2]

		while W3DFileOffset < (w3df[2] + w3df[3]) do
		(
			fseek fStream  W3DFileOffset #seek_set
			local ChunkID = W3Dchunk.getChunkID fStream

			case ChunkID of
			(
				0x00000000:
				(
					W3DFileOffset = W3Dchunk.Start
					NextObjectOffset = W3Dchunk.Start + W3Dchunk.Size
				)
				0x0000001f:
				(
					W3DMeshHeader.ReadW3D fStream

					append w3d.meshesArray #(W3DMeshHeader.Container, W3DMeshHeader.Name)
					W3DFileOffset = NextObjectOffset
				)
				0x00000740:
				(
					W3DBox.ReadW3D fStream

					append w3d.boxesArray #(W3DBox.Name, W3DBox.BoxColor, W3DBox.Pos, W3DBox.Extent, W3DBox.Flags)
				)
				0x00000900: W3DFileOffset = W3Dchunk.Start
				0x00000901:
				(
					W3DDazzleName.ReadW3D fStream
					append w3d.dazzlesArray #(W3DDazzleName.Name)
					W3DFileOffset = W3Dchunk.Start + W3Dchunk.size
				)
				0x00000902:
				(
					W3DDazzleType.ReadW3D fStream
					w3d.dazzlesArray[(w3d.dazzlesArray).count][2] = W3DDazzleType.Name
					W3DFileOffset = W3Dchunk.Start + W3Dchunk.size
				)
				default: W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
			)
		)

		fclose fStream
		return true;
	)
*/
/*
	fn ConvertW3D w3df=
	(
		local W3DMesh, MeshParent
		local MeshChunkStart, MeshChunkSize
		local MeshVertices, MeshFaces, MeshVertsNormals, MeshFacesNormals, MeshTVerts, VertsBones
		local W3DMeshMaterial, MaterialNames, TextureNames, TextureIDs, VerticesColor
		local VMaterials, VertexMaterial, VertexMaterialInfo, VMatInfos, vmTexture, vmIDs, vmInfo
		local vmPassCount, vmCount, vmShaderCount, vmTextureCount
		local ChunkID
		local UnknownMat = 0

		fStream = fopen w3df[1] "rb"
		W3DFileOffset = w3df[2]

		W3DImportProgressDlg.Stage.text = ("Building Meshes...")


		for i = 1 to meshesArray.count do
		(
			local MeshLOD, LODSelected = true, SkipMesh = false, SkinVertsOffset
			local vStr = ""

			MeshParent = 0
			MeshVertices = #()
			MeshFaces = #()
			MeshVertsNormals = #()
			MeshFacesNormals = #()
			MeshTVerts = #()
			VertsBones = #()
			VerticesColor = #()
			MaterialNames = #()
			VMatInfos = #()
			TextureNames = #()
			TextureIDs = #()
			VMaterials = #()
			vmIDs = #()
			SkinBones = #{}
			vmPassCount = 0
			vmCount = 0
			vmShaderCount = 0
			vmTextureCount = 0
			hasTVerts = false
			isWWSkin = false

			if W3Dchunk.FindChunk W3Dstream 0x00000000 w3df[2] w3df[3] then
			(
				MeshIndex += 1
				MeshChunkStart = W3Dchunk.Start
				MeshChunkSize = W3Dchunk.Size

				W3DFileOffset = W3Dchunk.start
			)
			else exit

			while W3DFileOffset < (MeshChunkStart + MeshChunkSize) do
			(
				fseek W3Dstream W3DFileOffset #seek_set
				ChunkID = W3Dchunk.getChunkID W3Dstream

				case ChunkID of
				(
					0x0000001f:
					(
						W3DMeshHeader.ReadW3D W3Dstream

						if MultipleLODFiles then
						(
							for j = 1 to LODModelsArray.count by 3 do
							(
								if LODModelsArray[j] == currentLOD and LODModelsArray[j+1] == W3DMeshHeader.Name then
								(
									MeshParent = LODModelsArray[j+2]
									MeshLOD = currentLOD
									exit;
								)
							)
						)
						else
						(
							local mIndex = findItem LODModelsArray W3DMeshHeader.Name
							if mIndex != 0 do	MeshParent = LODModelsArray[mIndex+1]

							for j = 1 to MeshesNames.count by 5 do
							(
								if MeshesNames[j+1] == W3DMeshHeader.Name then
								(
									MeshLOD = MeshesNames[j]
									exit;
								)
							)
						)

						if radioLOD.state == 2 and (MeshLOD < CurrentLODRange[1] or MeshLOD > CurrentLODRange[2]) do
							LODSelected = false

						if (ImportSelectedOnly and findItem SelMeshToImport W3DMeshHeader.Name == 0) or not LODSelected do
						(
							W3DFileOffset = MeshChunkStart + MeshChunkSize

							PercentDone = 100*MeshIndex/MeshesCount
							if PercentDone != OldPercentDone do
							(
								OldPercentDone = PercentDone
								W3DImportProgressDlg.Progress.value = PercentDone
								W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
							)

							SkipMesh = true
							exit;
						)

						for j = 1 to MeshesNames.count by 5 do
						(
							if MeshesNames[j+1] == W3DMeshHeader.Name and MeshesNames[j] == MeshLOD then
							(
								W3DMeshHeader.Name = MeshesNames[j+2]
								exit;
							)
						)

						numImportedMesh += 1
					)

					0x0000000c:
					(
						local Utext = ReadNullTerminatedString W3Dstream
						print Utext
						W3DFileOffset = ftell W3Dstream
					)

					0x00000002:
					(
						for j = 1 to W3DMeshHeader.NumVert do
						(
							W3Dvert.ReadW3D W3Dstream
							append MeshVertices W3Dvert.Position
						)
					)

					0x00000003:
					(
						for j = 1 to W3DMeshHeader.NumVert do
						(
							W3DvNormal.ReadW3D W3Dstream
							append MeshVertsNormals W3DvNormal.Normal
						)
					)
	
					0x00000020:
					(
						for j = 1 to W3DMeshHeader.NumTris do
						(
							W3Dtriangle.ReadW3D W3Dstream
							append MeshFaces W3Dtriangle.TriIndices
							append MeshFacesNormals W3Dtriangle.Normal
						)
					)

					0x00000022:
					(
						for j = 1 to W3DMeshHeader.NumVert do
						(
							local tmp = ReadLong W3Dstream #unsigned
						)

						W3DFileOffset = ftell W3Dstream
					)

					0x0000000e:
					(
						for j = 1 to BonesArray.count by 5 do append VertsBones (#())

						for j = 1 to W3DMeshHeader.NumVert do
						(
							W3DVertInf.ReadW3D W3Dstream
							if W3DVertInf.BoneIndex > 0 do append VertsBones[W3DVertInf.BoneIndex] j

							k = (5 * W3DVertInf.BoneIndex) - 4
							if k > 0 do MeshVertices[j] += BonesArray[k+2]
						)

						isWWSkin = true
					)
-- 

				------------- Check for Prelit flags

			if bit.and W3DmeshHeader.Flags 0x02000000 > 0x00000000 then
			else if bit.and W3DmeshHeader.Flags 0x04000000 > 0x00000000 then
			else if bit.and W3DmeshHeader.Flags 0x08000000 > 0x00000000 then
				
-- 

					0x00000024: W3DFileOffset = W3Dchunk.Start

					0x00000028:
					(
						W3DMaterialInfo.ReadW3D W3Dstream
						vmPassCount = W3DMaterialInfo.PassCount
						vmCount = W3DMaterialInfo.VMaterialCount
						vmShaderCount = W3DMaterialInfo.ShaderCount
						vmTextureCount = W3DMaterialInfo.TextureCount
					)

					0x0000002a: W3DFileOffset = W3Dchunk.Start

					0x0000002b: W3DFileOffset = W3Dchunk.Start

					0x0000002c:
					(
						W3DVMaterialName.ReadW3D W3Dstream
						append MaterialNames W3DVMaterialName.Name
					)

					0x0000002d:
					(
						VertexMaterialInfo = #()
						W3DVMatInfo.ReadW3D W3Dstream
						append VertexMaterialInfo W3DVMatInfo.Flags
						append VertexMaterialInfo W3DVMatInfo.Ambient
						append VertexMaterialInfo W3DVMatInfo.Diffuse
						append VertexMaterialInfo W3DVMatInfo.Specular
						append VertexMaterialInfo W3DVMatInfo.Emissive
						append VertexMaterialInfo W3DVMatInfo.Shininess
						append VertexMaterialInfo W3DVMatInfo.Opacity
						append VertexMaterialInfo W3DVMatInfo.Translucency
						append VMatInfos VertexMaterialInfo
						W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
					)

					0x00000029:
					(
						-- Set Shaders Properties
						for j = 1 to W3Dchunk.Size do ReadByte W3Dstream
						W3DFileOffset = ftell W3Dstream
					)

					0x0000002e:
					(
						ReadNullTerminatedString W3Dstream
						W3DFileOffset = ftell W3Dstream
					)
					0x0000002f:
					(
						ReadNullTerminatedString W3Dstream
						W3DFileOffset = ftell W3Dstream
					)

					0x00000030: W3DFileOffset = W3Dchunk.start

					0x00000031: W3DFileOffset = W3Dchunk.start

					0x00000032:
					(
						W3DTextureName.ReadW3D W3Dstream
						append TextureNames W3DTextureName.Name
					)

					0x00000033:
					(
						-- Set Texture Info
						W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
					)

					0x00000038: W3DFileOffset = W3Dchunk.start

					0x00000039:
					(
						-- Set Material IDS
						if W3Dchunk.size == 4 then
						(
							readLong W3Dstream #unsigned
							W3DFileOffset = ftell W3Dstream
						)
						else W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
					)

					0x0000003a:
					(
						if W3Dchunk.size == 4 then
						(
							readLong W3Dstream #unsigned
							W3DFileOffset = ftell W3Dstream
						)
						else
						(
							for j = 1 to W3DMeshHeader.NumVert do
							(
								W3DDCG.ReadW3D W3Dstream
								append VerticesColor W3DDCG.VertexColor
							)
						)
					)

					0x0000003b:
					(
						-- Set Vertices DCG
						W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
					)

					0x00000048: W3DFileOffset = W3Dchunk.start

					0x00000049:
					(
						if W3Dchunk.size == 4 then
						(
							readLong W3Dstream #unsigned
							W3DFileOffset = ftell W3Dstream
						)
						else
						(
							for j = 1 to W3DmeshHeader.NumTris do
							(
								if (W3Dchunk.size > 8) or (j == 1) do
								W3DTextureID.ReadW3D W3Dstream

								append TextureIDs W3DTextureID.ID
							)
						)
					)

					0x0000004a:
					(
						for j = 1 to W3DmeshHeader.NumVert do
						(
							W3Dtvert.ReadW3D W3Dstream
							append MeshTVerts W3Dtvert.UVW
						)
						hasTVerts = true
					)

					default:
					(
						W3DFileOffset = W3Dchunk.Start + W3Dchunk.Size
					)
				)
			)

			if SkipMesh do continue

			if vmCount > 0 do
			(				
				for j = 1 to vmCount do
				(
					if MaterialNames[j] != undefined then
					(
						VertexMaterial = standardMaterial name:MaterialNames[j]
					)

					else
					(
						local str = "Unknown" + UnknownMat as string
						VertexMaterial = standardMaterial name:str
						UnknownMat += 1
					)

					if vmTextureCount > 0 and TextureNames[j] != undefined do
					(
						vmTexture = bitmapTexture filename:TextureNames[j]
						-- assignNewName vmTexture
						vmInfo = VMatInfos[j]

						-- VertexMaterial.ambient = vmInfo[3]

						VertexMaterial.adLock = on
						VertexMaterial.diffuse = vmInfo[2]

						VertexMaterial.specular = vmInfo[4]
						VertexMaterial.mapEnables[3] = true

						-- VertexMaterial.selfillumColor = vmInfo[5]
						VertexMaterial.glossiness = vmInfo[6]

						VertexMaterial.opacity = vmInfo[7]

						-- VertexMaterial.maps[7] = vmInfo[7]

						VertexMaterial.maps[13] = vmTexture
						VertexMaterial.mapEnables[13] = true
						showTextureMap VertexMaterial vmTexture true
					)

					append VMaterials VertexMaterial
					append vmIDs j
				)

				W3DMeshMaterial = multimaterial numsubs:vmCount
				W3DMeshMaterial.materialList = VMaterials
				W3DMeshMaterial.materialIDList = vmIDs
			)

			W3DMesh = mesh name:W3dMeshHeader.Name \
				numverts:W3DmeshHeader.NumVert numfaces:W3DmeshHeader.NumTris

			setMesh W3DMesh vertices:MeshVertices faces:MeshFaces

			-- for i = 1 to W3DmeshHeader.NumVert do
			-- setNormal W3DMesh i MeshVertsNormals[i]

			for j = 1 to W3DmeshHeader.NumTris do
			setFaceNormal W3DMesh j MeshFacesNormals[j]

			if hasTVerts do
			(
				setMesh W3DMesh tverts:MeshTVerts 
				W3DMesh.material = W3DMeshMaterial
				buildTVFaces W3DMesh

				for j = 1 to W3DmeshHeader.NumTris do
				(
					setTVFace W3DMesh j (getface W3DMesh j)
					local TextureID = if TextureIDs[j] != undefined then TextureIDs[j] else 1
					setFaceMatID W3DMesh j TextureID
				)
			)

			if vmTextureCount == 0 do
				if W3DVMatInfo.Diffuse != undefined do W3DMesh.wireColor = W3DVMatInfo.Diffuse

			setAppData W3DMesh 0x01000000 (bit.IntAsChar 2)
			setAppData W3DMesh 0x02000000 (W3DMeshHeader.Flags as string)
			setAppData W3DMesh 0x00307000 ""
			setAppData W3DMesh 0x00000080 (bit.intAsChar MeshLOD)
			setAppData W3DMesh 0x00000081 (bit.intAsChar MeshParent)

			if isWWSkin do
			(
				local bData = 0x00001000
				local vData = 0x00002000

				for j = 1 to VertsBones.count where VertsBones[j].count > 0 do
				(
					local vStr = ""
					local vBones = VertsBones[j]

					for v in vBones do vStr += (v as string + ",")

					setAppData W3DMesh bData (bit.intAsChar j)
					setAppData W3DMesh vData vStr
					bData += 1
					vData += 1
				)

				setAppData W3DMesh 0x00000090 (bit.intAsChar (bData - 0x00001000))
			)

			append W3DMeshes W3DMesh
			append W3DMeshParents MeshParent

			update W3DMesh

			PercentDone = 100*MeshIndex/MeshesCount
			if PercentDone != OldPercentDone do
			(
				OldPercentDone = PercentDone
				W3DImportProgressDlg.Progress.value = PercentDone
				W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
			)

			W3DFileOffset = MeshChunkStart + MeshChunkSize
		)

		)

		for i = 1 to BoxesArray.count by 5 do
		(
			local BoundingBox = box name:BoxesArray[i] \
						      width:(2 * BoxesArray[i+3].x) \
							length:(2 * BoxesArray[i+3].y) \
							height:(2 * BoxesArray[i+3].z) \
							pos:[BoxesArray[i+2].x, BoxesArray[i+2].y, BoxesArray[i+2].z - BoxesArray[i+3].z]

			BoundingBox.wireColor = BoxesArray[i+1]
			setAppData BoundingBox 0x01000000 (bit.intAsChar 2)
			setAppData BoundingBox 0x02000000 (BoxesArray[i+4] as string)
			setAppData BoundingBox 0x00307000 ""
		)

		CloseW3D
		return true;
	),





		fn BuildHierarchy=
		(
			local numAddedBone = 0
			local linkedMeshArray = #()

			PercentDone = 0
			OldPercentDone = 0

			W3DImportProgressDlg.Stage.text = "BuildingHierarchy..."
			W3DImportProgressDlg.Progress.value = PercentDone
			W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")

			for i = 0 to (LODCount-1) do
			(
				local OriginLOD = if radioLOD.state == 1 then i + 1 else i - CurrentLODRange[1] + 1

				if CreateLODBones then
				(
					if radioLOD.state == 1 or (i >= CurrentLODRange[1] and i <= CurrentLODRange[2]) do
						OriginBone[OriginLOD] = CreateBone "Origin" ("Origin.0" + i as string) [0.0,0.0,0.0]
						setAppData OriginBone[OriginLOD] 0x01000000 (bit.intAsChar 1)
						setAppData OriginBone[OriginLOD] 0x00307000 ""
				)
				else
				(
					OriginBone[1] = CreateBone "Origin" "Origin" [0.0,0.0,0.0]
					setAppData OriginBone[1] 0x01000000 (bit.intAsChar 1)
					setAppData OriginBone[1] 0x00307000 ""

					exit;
				)
			)

			for i = 1 to OriginBone.count do OriginNeeded[i] = false

			PercentDone = 1
			W3DImportProgressDlg.Progress.value = PercentDone
			W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")

			for i = 1 to BonesArray.count by 5 do
			(
				local W3DBone
				local W3DBoneIndex = (i + 4) / 5
				local W3DBoneParent
				local W3DBoneType = "Bone"
				local W3DBoneLOD = 0
				local BoneCreated = false, BoneAdded = false
				local OriginLOD

				PercentDone = 1 + ((100*(i-1)/BonesArray.count) / 2)
				if PercentDone != OldPercentDone do
				(
					OldPercentDone = PercentDone
					W3DImportProgressDlg.Progress.value = PercentDone
					W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
				)

				if findItem ProxyArray BonesArray[i] > 0 do
				(
					if (not ImportSelectedOnly or findItem ProxiesSelected BonesArray[i] > 0) and not ImportBonesOnly do
					(
						local ProxyParentLOD

						W3DBoneType = "Proxy"
						W3DBone = CreateBone W3DBoneType BonesArray[i] BonesArray[i+2]
						setAppData W3DBone 0x01000000 (bit.intAsChar 1)
						setAppData W3DBone 0x00307000 ""

						if CreateLODBones do
							if radioLOD.state == 2 and CurrentLODRange[1] != 0 do ProxyParentLOD = CurrentLODRange[1]

						W3DBoneParent = getW3DBoneParent BonesArray[i+1] ProxyParentLOD

						if W3DBoneParent > 0 then W3DBone.parent = W3DBones[W3DBoneParent]
						else W3DBone.parent = OriginBone[1]

						join W3DBones #(W3DBone, W3DBoneIndex, W3DBoneParent, W3DBoneType, 0, true)
						Continue
					)
				)

				for j = 1 to DazzlesNames.count by 5 do
				(
					if DazzlesNames[j+3] != BonesArray[i] do continue

					local LODDazzleImported = false

					if (not ImportSelectedOnly or findItem DazzlesSelected DazzlesNames[j+2] > 0) and not ImportBonesOnly do
						LODDazzleImported = true

					W3DBoneLOD = DazzlesNames[j]

					if CreateLODBones then
					(
						if radioLOD.state == 2 and (W3DBoneLOD < CurrentLODRange[1] or W3DBoneLOD > CurrentLODRange[2]) do continue
						W3DBoneParent = getW3DBoneParent BonesArray[i+1] W3DBoneLOD
					)
					else W3DBoneParent = getW3DBoneParent BonesArray[i+1] 0


					OriginLOD = if radioLOD.state == 1 then W3DBoneLOD + 1 else W3DBoneLOD - CurrentLODRange[1] + 1

					W3DBoneType = if LODDazzleImported then "Dazzle" else "Bone"

					W3DBone = CreateBone W3DBoneType DazzlesNames[j+2] BonesArray[i+2]

					k = findItem DazzleArray DazzlesNames[j+1]
					setAppData W3DBone 0x01000000 (bit.intAsChar 7)
					setAppData W3DBone 0x00100000 DazzleArray[k+1]
					setAppData W3DBone 0x00307000 ""

					if W3DBoneParent > 0 then W3DBone.parent = W3DBones[W3DBoneParent]
					else W3DBone.parent = if CreateLODBones then OriginBone[OriginLOD] else OriginBone[1]

					join W3DBones #(W3DBone, W3DBoneIndex, W3DBoneParent, W3DBoneType, W3DBoneLOD, LODDazzleImported)
					BoneCreated = true
				)

				if BoneCreated do continue

				for j = 1 to MeshesNames.count by 5 do
				(
					if MeshesNames[j+3] != BonesArray[i] do continue

					local LODMesh, LODMeshImported = false
					local index = (13 * CurrentProfile) - 12
					local CreateMeshBone = W3DImporterInit.UserProfiles[index+12] 

					for k = 1 to W3DMeshes.count do
					(
						if W3DMeshes[k].name == MeshesNames[j+2] do
						(
							LODMeshImported = true
							LODMesh = k
						)
					)

					W3DBoneLOD = MeshesNames[j]

					OriginLOD = if radioLOD.state == 1 then W3DBoneLOD + 1 else W3DBoneLOD - CurrentLODRange[1] + 1

					if CreateMeshBone or not LODMeshImported then
					(
						if CreateLODBones then
						(
							if radioLOD.state == 2 and (W3DBoneLOD < CurrentLODRange[1] or W3DBoneLOD > CurrentLODRange[2]) do continue
							W3DBoneParent = getW3DBoneParent BonesArray[i+1] W3DBoneLOD
						)
						else W3DBoneParent = getW3DBoneParent BonesArray[i+1] 0

						local boneName

						if LODMeshImported then
						(
							boneName = "AddedBone" + numAddedBone as string
							BoneAdded = true
						)
						else boneName = BonesArray[i]

						if CreateLODBones do boneName = boneName + ".0" + W3DBoneLOD as string
						W3DBone = CreateBone "Bone" boneName BonesArray[i+2]
						setAppData W3DBone 0x01000000 (bit.intAsChar 1)
						setAppData W3DBone 0x00307000 ""
--						setAppData W3DBone 0x00200000 (W3DBoneIndex as string)
--						setAppData W3DBone 0x00300000 (if CreateLODBones then (W3DBoneLOD as string) else "0")

						if W3DBoneParent > 0 then W3DBone.parent = W3DBones[W3DBoneParent]
						else W3DBone.parent = if CreateLODBones then OriginBone[OriginLOD] else OriginBone[1]

						join W3DBones #(W3DBone, W3DBoneIndex, W3DBoneParent, W3DBoneType, W3DBoneLOD, LODMeshImported)
					)

					else if LODMeshImported do
					(
						W3DMeshes[LODMesh].pos = BonesArray[i+2]
						W3DBoneParent = getW3DBoneParent BonesArray[i+1] W3DBoneLOD

						if W3DBoneParent > 0 then W3DMeshes[LODMesh].parent = W3DBones[W3DBoneParent]
						else W3DMeshes[LODMesh].parent = if CreateLODBones then OriginBone[OriginLOD] else OriginBone[1]

						join W3DBones #(W3DMeshes[LODMesh], W3DBoneIndex, W3DBoneParent, "Mesh", W3DBoneLOD, true)
						setAppData W3DMeshes[LODMesh] 0x01000000 (bit.intAsChar 3)
					)

					BoneCreated = true
				)

				if BoneAdded do numAddedBone += 1
				if BoneCreated do continue

				if CreateLODBones then
				(
					for j = 0 to (LODCount-1) do
					(
						OriginLOD = if radioLOD.state == 1 then j + 1 else j - CurrentLODRange[1] + 1

						if radioLOD.state == 1 or (j >= CurrentLODRange[1] and j <= CurrentLODRange[2]) do
						(
							local boneName = BonesArray[i] + ".0" + j as string
							W3DBone = CreateBone "Bone" boneName BonesArray[i+2]
							setAppData W3DBone 0x01000000 (bit.intAsChar 1)
							setAppData W3DBone 0x00307000 ""

							W3DBoneParent = getW3DBoneParent BonesArray[i+1] j

							if W3DBoneParent > 0 then W3DBone.parent = W3DBones[W3DBoneParent]
							else W3DBone.parent = OriginBone[OriginLOD]

							join W3DBones #(W3DBone, W3DBoneIndex, W3DBoneParent, W3DBoneType, j, not DepBonesOnly)
						)
					)
				)

				else
				(
					W3DBone = CreateBone "Bone" BonesArray[i] BonesArray[i+2]
					setAppData W3DBone 0x01000000 (bit.intAsChar 1)
					setAppData W3DBone 0x00307000 ""

					W3DBoneParent = getW3DBoneParent BonesArray[i+1] 0

					if W3DBoneParent > 0 then W3DBone.parent = W3DBones[W3DBoneParent]
					else W3DBone.parent = OriginBone[1]

					join W3DBones #(W3DBone, W3DBoneIndex, W3DBoneParent, W3DBoneType, 0, not DepBonesOnly)
				)
			)

			PercentDone = 51
			W3DImportProgressDlg.Progress.value = PercentDone
			W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")

			local mIndex = 0

			for m in W3DMeshes do
			(
				local vb = getAppData m 0x00000090
				local vBones = if vb != undefined then bit.charAsInt vb else 0
				local MeshLOD = if CreateLODBones then bit.charAsInt (getAppData m 0x00000080) else 0

				PercentDone = (51 + ((100*(mIndex)/W3DMeshes.count) / 2.857)) as integer
				if PercentDone != OldPercentDone do
				(
					OldPercentDone = PercentDone
					W3DImportProgressDlg.Progress.value = PercentDone
					W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
				)

				if vBones > 0 do
				(
					max modify mode
					setFocus W3DImportProgressDlg
					enableShowEndRes false
					setFocus W3DImportProgressDlg
					select m
					setFocus W3DImportProgressDlg

					for i = 1 to vBones do
					(
						local vBoneID = bit.charAsInt (getAppData m (0x00001000 + (i-1)))
						local vStr = getAppData m (0x00002000 + (i-1))
						local vStrArray = filterString vStr ","
						local vArray = for v in vStrArray collect v as integer
						local vertBone

						for j = 1 to W3DBones.count by 6 where (W3DBones[j+1] == vBoneID and W3DBones[j+4] == MeshLOD) do
						(
							vertBone = W3DBones[j] 
							if DepBonesOnly do W3DBones[j+5] = true
							exit;
						)

						modPanel.addModToSelection (Mesh_Select ())
						setFocus W3DImportProgressDlg
						subObjectLevel = 1
						setFocus W3DImportProgressDlg
						setVertselection m m.modifiers[#Mesh_Select] vArray
						setFocus W3DImportProgressDlg
						modPanel.addModToSelection (Linked_XForm ())
						setFocus W3DImportProgressDlg
						m.modifiers[#Linked_Xform].control = vertBone
						setFocus W3DImportProgressDlg

						local vbStr = vertBone.handle as string
						setAppData m (0x00001000 + (i-1)) vbStr
					)

					enableShowEndRes true
					setFocus W3DImportProgressDlg

					append linkedMeshArray i
				)

				if m.parent != undefined do continue

				local OriginLOD = if radioLOD.state == 1 then MeshLOD + 1 else MeshLOD - CurrentLODRange[1] + 1
				local MeshParent = getW3DBoneParent (bit.charAsInt (getAppData m 0x00000081)) MeshLOD

				if MeshParent > 0 then
				(
					m.pos = W3DBones[MeshParent].pos
					m.parent = W3DBones[MeshParent]
					if DepBonesOnly do W3DBones[MeshParent+5] = true
				)

				else m.parent = if CreateLODBones then OriginBone[OriginLOD] else OriginBone[1]
				mIndex += 1
			)

			PercentDone = 86
			W3DImportProgressDlg.Progress.value = PercentDone
			W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")

			for i = 1 to AggregateArray.count by 2 do
			(
				PercentDone = (86 + ((100*(i-1)/(AggregateArray.count/2)) / 20))
				if PercentDone != OldPercentDone do
				(
					OldPercentDone = PercentDone
					W3DImportProgressDlg.Progress.value = PercentDone
					W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
				)

				if (not ImportSelectedOnly or findItem AggregatesSelected AggregateArray[i] > 0) and not ImportBonesOnly do
				(
					local Aggregate, AggParentLOD = 0

					if CreateLODBones do
						if radioLOD.state == 2 and CurrentLODRange[1] != 0 do AggParentLOD = CurrentLODRange[1]

					local AggParent = getW3DBoneParent AggregateArray[i+1] AggParentLOD

					if AggParent > 0 then
					(
						Aggregate = CreateBone "Aggregate" AggregateArray[i] W3DBones[AggParent].pos
						setAppData Aggregate 0x01000000 (bit.intAsChar 10)
						setAppData Aggregate 0x00307000 ""

						Aggregate.parent = W3DBones[AggParent]
						if DepBonesOnly do W3DBones[AggParent+5] = true
					)
					else
					(
						Aggregate = CreateBone "Aggregate" AggregateArray[i] [0.0,0.0,0.0]
						Aggregate.parent = OriginBone[1]
						if DepBonesOnly do OriginNeeded[1] = true
					)
				)
			)

			W3DImportProgressDlg.Progress.value = 91
			W3DImportProgressDlg.Percent.text = "91 %"

			for i = 1 to BonesArray.count by 5 do
				for j = 1 to W3DBones.count by 6 do if W3DBones[j+1] == ((i+4) / 5) do
					in coordsys local rotate W3DBones[j] BonesArray[i+3]


			W3DImportProgressDlg.Progress.value = 94
			W3DImportProgressDlg.Percent.text = "94 %"

			local i = W3DBones.count
			while i > 0 do
			(
				if W3DBones[i] and DepBonesOnly then
				(
					local W3DBoneParent = W3DBones[i-3]
					while W3DBoneParent >= 0 do
					(
						if W3DBoneParent == 0 do
						(
							local lodID = if radioLOD.state == 1 then W3DBones[i-1] + 1 else W3DBones[i-1] - CurrentLODRange[1] + 1
							if CreateLODBones then OriginNeeded[lodID] = true
							else OriginNeeded[1] = true
							exit;
						)

						W3DBones[W3DBoneParent+5] = true
						W3DBoneParent = W3DBones[W3DBoneParent+2]
					)
				)

				i -= 6
			)

			W3DImportProgressDlg.Progress.value = 97
			W3DImportProgressDlg.Percent.text = "97 %"

			if not checkBones.checked do
			(
				for i = 1 to W3DMeshes.count do
				(
					if findItem linkedMeshArray i > 0 do convertToMesh W3DMeshes[i]
					W3DMeshes[i].parent = undefined
				)
			)

			local i = W3DBones.count
			while i > 0 do
			(
				i -= 6

				if checkBones.checked and W3DBones[i+6] do continue
				if ImportBonesOnly and W3DBones[i+4] == "Bone" do continue
				if W3DBones[i+4] != "Mesh" and W3DBones[i+4] != "Dazzle" and W3DBones[i+4] != "Proxy" do
				(
					delete W3DBones[i+1]
					for j = 1 to 6 do deleteItem W3DBones (i+1)
				)
			)

			local i = OriginBone.count
			while i > 0 do
			(
				if not CreateOrigin or (DepBonesOnly and not OriginNeeded[i]) do
				(
					delete OriginBone[i]
					deleteItem OriginBone i
					deleteItem OriginNeeded i
				)
				i -= 1
			)

			W3DImportProgressDlg.Progress.value = 100
			W3DImportProgressDlg.Percent.text = "100 %"
		),

		fn W3DAnimate=
		(
			OpenW3D W3DAnimationFile

			if AnimFrameCount > 0 and checkBones.checked and checkAnim.checked do
			(
				local SingleFrame = false, frameIndex
				local ChannelIndex, AnimBone, VectorLen, VectorStart
				local ChannelType, ChannelFirstFrame, ChannelLastFrame
				local PosControllers = #(0,1,2,7,8,9,11,12,13)
				local ChannelPercentDone = 0

				PercentDone = 0
				OldPercentDone = 0

				if radioFrames.state == 2 then
				(
					AnimFirstFrame = fromFrameSpin.value
					AnimLastFrame = toFrameSpin.value 
					if AnimFirstFrame == AnimLastFrame do SingleFrame = true
				)
				else
				(
					AnimFirstFrame = 0
					AnimLastFrame = AnimFrameCount - 1
				)

				frameRate = AnimFrameRate
				animationRange = interval 0 (AnimLastFrame - AnimFirstFrame)
				sliderTime = 0f

				W3DImportProgressDlg.Stage.text = "Animating..."
				W3DImportProgressDlg.Progress.value = PercentDone
				W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")

				for i = 1 to W3DBones.count by 6 do
				(
					local boneIndex = W3DBones[i+1]

					for j = 1 to AnimChannelCount do
					(
						ChannelIndex = (j * 3) - 2
						AnimBone = AnimBones[ChannelIndex]
						VectorLen = AnimBones[ChannelIndex+1]
						VectorStart = AnimBones[ChannelIndex+2]
						ChannelType = AnimInfo[ChannelIndex]
						ChannelFirstFrame = AnimInfo[ChannelIndex+1]
						ChannelLastFrame = AnimInfo[ChannelIndex+2]
						frameIndex = 1

						if AnimBone == boneIndex do
						(
							local c, k, InitialPos

							if findItem PosControllers ChannelType > 0 then
							(
								c = bezier_position()
								W3DBones[i].pos.controller = c
							)
							else
							(
								c = bezier_rotation()
								W3DBones[i].rotation.controller = c
							)

							if AnimFirstFrame > 0 then frameIndex = 0
							else
							(
								k = addNewKey c 0
								InitialPos = k.value
							)

							W3DFileOffset = VectorStart
							fseek W3Dstream W3DFileOffset #seek_set

							for n = ChannelFirstFrame to ChannelLastFrame do
							(
								if n < AnimFirstFrame do
								(
									W3DFileOffset += (VectorLen * 4)
									fseek W3Dstream W3DFileOffset #seek_set
									continue
								)

								if n > AnimLastFrame then exit;

								k = addNewKey c frameIndex
								if frameIndex == 0 do InitialPos = k.value

								case ChannelType of
								(
									0: k.value.x = InitialPos.x + (ReadAnimVector W3Dstream)
									1: k.value.y = InitialPos.y + (ReadAnimVector W3Dstream)
									2: k.value.z = InitialPos.z + (ReadAnimVector W3Dstream)
									3: k.value.x = InitialPos.x + (ReadAnimVector W3Dstream)
									4: k.value.y = InitialPos.y + (ReadAnimVector W3Dstream)
									5: k.value.z = InitialPos.z + (ReadAnimVector W3Dstream)
									6: k.value = InitialPos + (ReadAnimVector W3Dstream isQuat:true)
									7: k.value.x = InitialPos.x + (ReadAnimVector W3Dstream)
									8: k.value.y = InitialPos.y + (ReadAnimVector W3Dstream)
									9: k.value.z = InitialPos.z + (ReadAnimVector W3Dstream)
									10: k.value = InitialPos + (ReadAnimVector W3Dstream isQuat:true)
									11: k.value.x = InitialPos.x + (ReadAnimVector W3Dstream)
									12: k.value.y = InitialPos.y + (ReadAnimVector W3Dstream)
									13: k.value.z = InitialPos.z + (ReadAnimVector W3Dstream)
									14: k.value = InitialPos + (ReadAnimVector W3Dstream isQuat:true)
								)

								frameIndex += 1
								ChannelPercentDone = 100*n/(ChannelLastFrame-ChannelFirstFrame)
								PercentDone = (100*(j-1)/AnimChannelCount)+(ChannelPercentDone/AnimChannelCount)

								if PercentDone != OldPercentDone do
								(
									OldPercentDone = PercentDone
									W3DImportProgressDlg.Progress.value = PercentDone
									W3DImportProgressDlg.Percent.text = ((PercentDone as string) + " %")
								)
							)
						)
					)
				)

			W3DImportProgressDlg.Progress.value = 100
			W3DImportProgressDlg.Percent.text = "100 %"
			)

			W3DImportProgressDlg.Stage.text = "Updating Gmax Viewports..."
		)

*/

	fn Import=
	(
		if w3d.isHierarchical do getW3DHierarchy w3d.w3dFiles[w3d.hierarchyFile]
		if w3d.isAnimated do getW3DAnimation w3d.w3dFiles[w3d.animationFile]
		if w3d.LODCount > 0 do getW3DHLOD w3d.w3dFiles[w3d.HLODFile]
		for i = 1 to (w3d.objectsFiles).count do getW3DObjects w3d.w3dFiles[w3d.objectsFiles[i]]

		local PanelShown = cui.commandPanelOpen
		local CurrentPanel = getCommandPanelTaskMode()

		if maxFileName != "" or getSaveRequired() do W3DMergePrompt.Open()

		cui.commandPanelOpen = false
		disableSceneRedraw()

		W3DImportProgressDlg.Open()

--		try
--		(
	--			for i = 1 to 0 to (w3d.objectsFiles).count do ConvertW3D w3d.w3dFiles[w3d.objectsFiles[i]]
--		)
--		catch
--		(
--			messagebox "An Error Occured While Converting Meshes"
--			format "W3D File Selected: %\n" W3DFileName
--			format "LOD Count = %\n" LODCount
--			for i = 1 to LODCount do
--			format "LOD[%] File: %\n" (i-1) W3DObjectsFile[i]
--			W3DImportProgressDlg.fclose()
--			setCommandPanelTaskMode mode:CurrentPanel
--			cui.commandPanelOpen = PanelShown
--			enableSceneRedraw()
--			max views redraw
--		)

--		try
--		(
	--			importer.BuildHierarchy()
	--			clearselection()
--		)
--		catch
--		(
--			messagebox "Error Building Hierarchy"
--			W3DImportProgressDlg.fclose()
--			setCommandPanelTaskMode mode:CurrentPanel
--			cui.commandPanelOpen = PanelShown
--			enableSceneRedraw()
--			max views redraw
--		)

--		try (
	--			if isAnimated do importer.W3DAnimate()
--		)
--		catch	(
--			messagebox "Error occured in Animating process"
--			W3DImportProgressDlg.fclose()
--			setCommandPanelTaskMode mode:CurrentPanel
--			cui.commandPanelOpen = PanelShown
--			enableSceneRedraw()
--			max views redraw
--		)

		W3DImportProgressDlg.Close()
		setCommandPanelTaskMode mode:CurrentPanel
		cui.commandPanelOpen = PanelShown
		enableSceneRedraw()
		max views redraw
		setSaveRequired true
		setAppData rootNode 0x00307000 (bit.intAsChar 1)
	)

	fn CheckDependencies val=
	(
		local curPath = W3DImporterInit.W3DFolders[CurrentW3DPath]
		local filesToSearch = #()
		local bigFilesArray = #()
		local tmpArray = #()
		local fileTypes = #()
		local searchArray = #()
		local filesRequired = #()

		dependencies[1] += "        ( Found )"
		append filesRequired (w3dFiles.getFileInfo val)


--		format "Dependencies = %\n" dependencies
		for i = 1 to dependencies.count where (local str = filterString dependencies[i] ".").count == 1 do
		(
			if (j = findItem (for b in w3dFiles.filesArray collect ((getFileNameFile b[1]) as name)) (dependencies[i] as name)) > 0 do
			(
				dependencies[i] = ((getFileNameFile w3dFiles.filesArray[j][1]) + (getFileNameType w3dFiles.filesArray[j][1]))
				dependencies[i] += "        ( Found )"
				append filesRequired (w3dFiles.getFileInfo j)
			)
		)

		DependenciesList.items = dependencies
		format "filesRequired = %\n" filesRequired
/*
		for i = 1 to (DependenciesList.items).count do
		(
			append dependencies #(((DependenciesList.items)[i]))
			local fType = getFileNameType dependencies[i][1]
			
			if (fType == ".tga" and (tmpArray = getFiles (curPath + (getFileNameFile dependencies[i][1]) + ".dds")).count > 0) or \
				((tmpArray = getFiles (curPath + dependencies[i][1])).count > 0) then
			(
				dependencies[i][2] = tmpArray[1]
				dependencies[i][3] = 0
				dependencies[i][4] = getFileSize tmpArray[1]
				DependenciesList.selection = i
				DependenciesList.selected = dependencies[i][1] + "        ( Found )"
				append w3d.w3dFiles #(dependencies[i][2], dependencies[i][3], dependencies[i][4])
			)
			else
			(
				DependenciesList.selection = i
				append filesToSearch DependenciesList.selected
				if fType == ".tga" then append fileTypes fType else append fileTypes ".w3d"
				DependenciesList.selected = dependencies[i][1] + "        ( Searching... )"
			)
		)

		DependenciesList.selection = 0

		if filesToSearch.count == 0 do return true;

		local mixToIgnore = #("mixfile_sound_*", "mixfile_talktree_*", "Skirmish00")
		local datToIgnore = #(#asset, #game, #game2, #Generals, #gi, #langdata, #patchget)
		local bigToIgnore = #(#AmbientStreams, #Audio, #AudioEnglish, #AudioZH, #AudioEnglishZH, #Bases, #Data1, \
								#gensec, #GensecZH, #INIZH, #ini, #Libraries, #lotrsec, #Music, #MusicZH, #Shaders, \
								#ShadersZH, #Speech, #SpeechZH, #SpeechEnglish, #SpeechEnglishZH, #Window, #WindowZH)		


		bigFilesArray = (getFiles (curPath + "*.pkg"))
		for i = 1 to (tmpArray = (getFiles (curPath + "*.mix"))).count do
		(
			local ignore = false
			local fName = getFileNameFile tmpArray[i]
			for j = 1 to mixToIgnore.count do
				if matchPattern fName pattern:mixToIgnore[j] do ignore = true
			if not ignore do append bigFilesArray tmpArray[i]
		)	
		for i = 1 to (tmpArray = (getFiles (curPath + "*.dat"))).count do
		(
			local fName = getFileNameFile tmpArray[i]
			if findItem datToIgnore (fName as name) == 0 then append bigFilesArray tmpArray[i]
		)	
		for i = 1 to (tmpArray = (getFiles (curPath + "*.big"))).count do
		(
			local fName = getFileNameFile tmpArray[i]
			if findItem bigToIgnore (fName as name) == 0 then append bigFilesArray tmpArray[i]
		)	

		if w3dListArray[fIndex][4] > 0 do
		(
			local bigIndex = findItem bigFilesArray w3dListArray[fIndex][2]
			bigFilesArray[bigIndex] = bigFilesArray[1]
			bigFilesArray[1] = w3dListArray[fIndex][2]
		)
			
		for i = 1 to bigFilesArray.count do
		(
			if MixFile.open bigFilesArray[i] then
			(
				searchArray  = MixFile.getFilesNames #(".dds", ".tga", ".w3d") trimType:false trimPath:true
				MixFile.close
			)
			else if BigFile.open bigFilesArray[i] then
			(
				searchArray = BigFile.getFilesNames #(".dds", ".tga", ".w3d") trimType:false trimPath:true
				BigFile.close
			)

			local removeIDs = #()
			local fArray = (for k = 1 to searchArray.count collect(searchArray[k][1]))

			for j = 1 to filesToSearch.count do
			(
				local fOffset
				if (fileTypes[j] == ".tga" and (fIndex = findItem fArray ((getFileNameFile filesToSearch[j]) + ".dds")) > 0) or \
					((fIndex = findItem fArray filesToSearch[j]) > 0) then
				(
					local k = findItem (for m = 1 to (dependencies).count collect(dependencies[m][1])) filesToSearch[j]
					dependencies[k][2] = searchArray[fIndex][2]
					dependencies[k][3] = searchArray[fIndex][4]
					dependencies[k][4] = searchArray[fIndex][5]
					DependenciesList.selection = k
					DependenciesList.selected = dependencies[k][1] + "        ( Found )"
					DependenciesList.selection = 0
					append removeIDs j
				)
			)

			if removeIDs.count > 0 do
			(
				for j = removeIDs.count to 1 by -1 do
				(
					deleteItem filesToSearch removeIDs[j]
					deleteItem fileTypes removeIDs[j]
				)
			)
		)

		for i = 1 to filesToSearch.count do
		(
			j = findItem (for k = 1 to (dependencies).count collect(dependencies[k][1])) filesToSearch[i]
			DependenciesList.selection = j
			DependenciesList.selected = dependencies[j][1] + "        ( Not Found! )"
			DependenciesList.selection = 0
		)
			
		join w3d.w3dFiles (for i = 1 to dependencies.count collect(#(dependencies[i][2], dependencies[i][3], dependencies[i][4])))

		if filesToSearch.count == 0 do return true;
		return false;

*/
	)

	fn checkSelectedW3D val=
	(
		local exportTypeStr = ""
		local fw3d
		if (local w3dInfo = (fw3d = W3D_FILE()).getW3DInfo (w3dFiles.getFileInfo val) getFrames:true).count == 0 do
			return false;
		if (bit.and w3dInfo[3] 1) == 1 then
		(
			if (bit.and w3dInfo[3] 4) == 4 then exportTypeStr = "Hierarchical Animated Model"
			else if (bit.and w3dInfo[3] 2) == 2 or (bit.and w3dInfo[3] 8) == 8 or (bit.and w3dInfo[3] 32) == 32 then
				exportTypeStr = "Hierarchical Model"
			else exportTypeStr = "Skeleton"
		)
		else if (bit.and w3dInfo[3] 8) == 8 or (bit.and w3dInfo[3] 32) == 32 then
		(
			if (bit.and w3dInfo[3] 2) == 2 or (bit.and w3dInfo[3] 256) == 256 then exportTypeStr = "Skin or LOD Model"
			else if w3dInfo[3] == 8 then exportTypeStr = "LOD References Array"
			else if w3dInfo[3] == 32 then exportTypeStr = "Model"
		)
		else if w3dInfo[3] == 4 then exportTypeStr = "Animation"
		else if w3dInfo[3] == 2 then exportTypeStr = "Renegade Terrain"
		else if w3dInfo[3] == 16 then exportTypeStr = "Aggregate"
		else if w3dInfo[3] == 64 then exportTypeStr = "Emitter"
		else if w3dInfo[3] == 128 then exportTypeStr = "Sound Emitter"
		else if w3dInfo[3] == 256 then exportTypeStr = "Bounding Box"
		else if w3dInfo[3] == 512 then exportTypeStr = "Mesh"
		else if w3dInfo[3] == 1024 then exportTypeStr = "Mesh Collection"

		local fName = w3dFiles.fileNames[(w3dFiles.filesArray[val][2])]
		if w3dFiles.filesArray[val][3] > 0 then
			PathProptxt.text = ("...\\(" + ((getFileNameFile fName) + (getFileNameType fName)) + ")\\" + w3dFiles.filesArray[val][1])
		else PathProptxt.text = fName

		SizeProptxt.text = getFileSizeString w3dFiles.filesArray[val][4]
		NameProptxt.text = w3dInfo[1]
		FramesProptxt.text = w3dInfo[4] as string
		TypeProptxt.text = exportTypeStr

		dependencies = fw3d.getDependencies()
		DependenciesList.items = dependencies
		DependenciesList.selection = 0
		fw3d.closeW3D()

--		if (bit.and w3dInfo[3] 1024) == 1024 do (local f = W3D_FILE()).dumpW3D (w3dFiles.getFileInfo val)

--		if (bit.and w3dInfo[3] 2048) == 2048 do format "Type: %\n\n" exportTypeStr
	)

	fn UpdateFilesList val forceUpdate=
	(
		if val == CurrentW3DPath and forceUpdate == false then return false;
		CurrentW3DPath = val

		setFocus W3DImportDlg

		W3DFilesList.items = #()
		
		PathProptxt.text = ""

		for i = (DependenciesList.items).count to 1 by -1 do
		(
			DependenciesList.selection = i
			DependenciesList.selected = ""
		)
		DependenciesList.selection = 0

		local curPath = W3DImporterInit.W3DFolders[CurrentW3DPath]
		local fTypes = #("*.w3d")
		local mixToSkip = #("mixfile_sound_*", "mixfile_talktree_*", "Skirmish00")
		local datToSkip = #(#asset, #game, #game2, #Generals, #gi, #langdata, #patchget)
		local bigToSkip = #(#AmbientStreams, #Audio, #AudioEnglish, #AudioZH, #AudioEnglishZH, #Bases, #Data1, \
								#English, #EnglishZH, #gensec, #GensecZH, #INIZH, #ini, #Libraries, #lotrsec, #Maps, \
								#MapsZH, #Music, #MusicZH, #Shaders, #ShadersZH, #Speech, #SpeechZH, #SpeechEnglish, \
								#SpeechEnglishZH, #Terrain, #TerrainZH, #Textures, #TexturesZH, #Textures0, #Textures1, \
								#Textures2, #Textures3, #Textures4, #Window, #WindowZH)		

		W3DImportProgressDlg.Open()
		(w3dFiles = W3D_FILES_LIST()).getFilesArray curPath fTypes mixSkip:mixToSkip datSkip:datToSkip bigSkip:bigToSkip
		w3dFiles.sortFiles()
		W3DImportProgressDlg.Close()

		W3DFilesList.items = (for a in w3dFiles.filesArray collect ((getFileNameFile a[1]) + (getFileNameType a[1])))
		setFocus W3DFilesList

		if w3dFiles.filesArray.count > 0 then
		(
			W3DFilesList.selection = 1
			CheckSelectedW3D 1
		)
	)

	fn dumpW3D to:Listener= ( (local fW3D = W3DImportDlg.W3D_FILE()).dumpW3D (w3dFiles.getFileInfo W3DFilesList.selection) )

	fn testTypes=
	(
		for i = 1 to (W3DFilesList.items).count do
		(
			W3DFilesList.selection = i
			checkSelectedW3D i
		)
	)

	fn Init=
	(
		CurrentW3DPath = W3DImporterInit.DefaultFolders
		W3DFolder.selection = CurrentW3DPath
		UpdateFilesList CurrentW3DPath true
	)

	on W3DFolder selected val do UpdateFilesList val false
	on W3DFilesList selected val do CheckSelectedW3D val
	on W3DFilesList doubleclicked val do checkDependencies val
	on DependenciesList selected val do (DependenciesList.selection = 0 ; setFocus W3DFilesList)
	on DependenciesList doubleclicked val do setFocus W3DFilesList

	on SetPathsButton pressed do SetW3DPathsDlg.open()
	on dumpListenerButton pressed do dumpW3D()
	on checkDependenciesButton pressed do checkDependencies W3DFilesList.selection

	on ImportButton pressed do
	(
		testTypes()

		checkDependencies W3DFilesList.selection
--		import()
--		destroyDialog W3DImportDlg
	)

	on cancelButton pressed do destroyDialog W3DImportDlg
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- W3D TEXTURES BROWSER DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DTexturesBrowserDlg "W3D Textures Browser" width:676 height:440 silentErrors:false
(
	local CurrentTexturesPath
	local texturesList

	label lblTexturesFolder "Look in:" pos:[15,13] align:#left enabled:true
	dropdownlist TexturesFolder pos:[65,10] width:480 items:W3DImporterInit.FoldersList enabled:true
	button SetPathsButton "Set Paths..." pos:[560,9] width:100
	
	groupBox TexturesFiles "W3D Textures:" width:356 height:308 pos:[13,45]
	listBox TexturesFilesList pos:[22,63] width:338 height:21 items:#()

	bitmap TextureImage pos:[394,62] width:256 height:256

	groupBox TextureInfo "" width:274 height:308 pos:[385,45]
	label TextureDimlbl "Texture Size:" pos:[395,328] width:65
	label TextureDimtxt "" pos:[460,328] width:88
	label TexturefSizelbl "File Size:" pos:[550,328] width:45
	label TexturefSizetxt "" pos:[595,328] width:62

	groupBox TexturesFileLoc "" width:647 height:30 pos:[13,360]
	label PathProptxt "" pos:[17,371] width:642

	button ImportButton "Import" pos:[415,404] width:100
	button CancelButton "Cancel" pos:[530,404] width:100


	fn CheckSelectedTexture val=
	(
		if texturesList.filesArray[val][4] > 100000 do
			(TextureImage.bitmap = (local b = openBitmap "K:\\3dsmax5\\textures\\w3dTexturesBrowser\\w3dTexture_load.bmp"); close b)

		local fName = texturesList.fileNames[texturesList.filesArray[val][2]]
		local wName = ("K:\\3dsmax5\\textures\\w3dTexturesBrowser\\tmpw3dImg" + (getFileNameType TexturesFilesList.selected))
		local tmpf = (fopen wName "wb")
		local thisImg = fopen fName "rb"
		fseek thisImg texturesList.filesArray[val][3] #seek_set

		for i = 1 to (texturesList.filesArray[val][4]) do (writeByte tmpf (readByte thisImg #unsigned) #unsigned)
			
		fclose thisImg
		fclose tmpf

		local tmpBmp = openBitmap wName
		local resizedBmp = bitmap 256 256

		TexturefSizetxt.text = (W3DImportDlg.getFileSizeString texturesList.filesArray[val][4])
		TextureDimtxt.text = ("[" + (tmpBmp.width as string) + " X " + (tmpBmp.height as string) + "]")
			
		if tmpBmp.width > 256 or tmpBmp.height > 256 then
		(
			if tmpBmp.width > tmpBmp.height then resizedBmp = bitmap 256 (tmpBmp.height/(tmpBmp.width/256))
			else resizedBmp = bitmap (tmpBmp.width/(tmpBmp.height/256)) 256
			copy tmpBmp resizedBmp
			TextureImage.bitmap = resizedBmp
		)
		else TextureImage.bitmap = tmpBmp

		close tmpBmp
		close resizedBmp
	
		if texturesList.filesArray[val][3] > 0 then
			PathProptxt.text =  ("[ " + (getFileNameFile fName) + (getFileNameType fName) + " ] \\" + texturesList.filesArray[val][1])
		else PathProptxt.text = fName
	)

	fn UpdateFilesList val forceUpdate=
	(
		if val == CurrentTexturesPath and forceUpdate == false do return false;			
		CurrentTexturesPath = val

		setFocus W3DTexturesBrowserDlg

		TexturesFilesList.items = #()
		PathProptxt.text = ""

		local curPath = W3DImporterInit.W3DFolders[CurrentTexturesPath]
		local fTypes = #("*.dds", "*.tga", "*.png") -- "*.jpg", 
		local mixToSkip = #("mixfile_sound_*", "mixfile_talktree_*", "Skirmish00")
		local datToSkip = #(#asset, #game, #game2, #Generals, #gi, #langdata, #patchget)
		local bigToSkip = #(#AmbientStreams, #Audio, #AudioEnglish, #AudioZH, #AudioEnglishZH, #Bases, #Data1, \
								#gensec, #GensecZH, #INIZH, #ini, #Libraries, #lotrsec, #Music, #MusicZH, #Shaders, \
								#ShadersZH, #Speech, #SpeechZH, #SpeechEnglish, #SpeechEnglishZH, #Window, #WindowZH)		

		W3DImportProgressDlg.Open()
		texturesList.getFilesArray curPath fTypes mixSkip:mixToSkip datSkip:datToSkip bigSkip:bigToSkip
		texturesList.sortFiles()
		W3DImportProgressDlg.Close()

		TexturesFilesList.items = (for a in texturesList.filesArray collect ((getFileNameFile a[1]) + (getFileNameType a[1])))
		setFocus TexturesFilesList

		if texturesList.filesArray.count > 0 then
		(
			TexturesFilesList.selection = 1
			CheckSelectedTexture 1
		)
	)

	fn open=
	(
		if (maxVersion())[1] == 4200 do
		(
			messagebox "Sorry this tool is not available in Gmax"
			return false;
		)

		createDialog W3DTexturesBrowserDlg style:#(#style_titlebar, #style_sysmenu) \
			pos:[(CurrentScreenWidth / 2) - 359, (CurrentScreenHeight / 2) - 286]

		CurrentTexturesPath = W3DImporterInit.DefaultFolders
		TexturesFolder.selection = CurrentTexturesPath
		texturesList = W3DImportDlg.W3D_FILES_LIST()

		local tmpBmp = openBitmap "K:\\3dsmax5\\textures\\w3dTexturesBrowser\\w3dTexture_empty.bmp"
		TextureImage.bitmap = tmpBmp
		close tmpBmp

		UpdateFilesList CurrentTexturesPath true
	)

	
	on TexturesFolder selected val do UpdateFilesList val false
	on TexturesFilesList selected val do CheckSelectedTexture val
)


------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- W3D HIERARCHY BUILDER DIALOG
------------------------------------------------------------------------------------------------------- 

rollout W3DHierarchyBuilderDlg "W3D Hierarchy Builder" width:690 height:400 silentErrors:false
(
	local curHierarchyPath
	local w3dFilesList
	local SkeletonsArray = #()
	local SkinsArray = #()
	local AnimationsArray = #()
	local AggregatesArray = #()
	local EmittersArray = #()
	local ModelsArray = #()
	local BoxesArray = #()
	local DependenciesArray = #()
	local SkeletonSkins = #()
	local SkeletonAnims = #()
	local SkinsAggregates = #()
	local curSkeletonsDeps = #()
	local curSkinsDeps = #()
	local curAnimsDeps = #()
	local curAggregatesDeps = #()
	local curSkeleton
	local curSkin
	local curAnimation
	local curAggregate

	label lblHierarchyFolder "Look in:" pos:[15,18] align:#left enabled:true
	dropdownlist HierarchyFolder pos:[65,15] width:276 items:W3DImporterInit.FoldersList enabled:true
	button SetPathsButton "Set Paths..." pos:[356,14] width:90

	groupBox SkeletonsGrp "Skeletons:" width:206 height:296 pos:[15,55]
	listBox SkeletonsList pos:[24,73] width:188 height:20 items:#()
	
	groupBox SkinsGrp "Appliable Skins/LOD Meshes:" width:206 height:140 pos:[240,55]
	listBox SkinsList pos:[249,73] width:188 height:8 items:#()

	groupBox AnimationsGrp "Appliable Animations:" width:206 height:140 pos:[240,211]
	listBox AnimationsList pos:[249,229] width:188 height:8 items:#()

	groupBox AggregatesGrp "Appliable Aggregates:" width:206 height:140 pos:[465,55]
	listBox AggregatesList pos:[474,73] width:188 height:8 items:#()

	groupBox DependenciesGrp "Required Files:" width:206 height:140 pos:[465,211]
	listBox DependenciesList pos:[474,229] width:188 height:8 items:#()

	button ImportButton "Import" pos:[225,364] width:100
	button CancelButton "Cancel" pos:[340,364] width:100

--			local extractStream = fopen ("K:\\3dsmax5\\w3d\\" + (getFileNameFile w3dListArray[fIndex][1]) + ".w3d") "wb"
--			fseek fStream fSOF #seek_set
--			for i = 1 to fSize do writeByte extractStream (readByte fStream #unsigned) #unsigned
--			fclose extractStream
--			format "W3D File: %\n" w3dListArray[fIndex][1]
--			format "Chunks List: ("
--			for i = 1 to ChunksList.count do format "%, " (bit.IntAsHex ChunksList[i])
--			format ")\n"

	fn getFileDependencies fileArray objectsOnly:false texturesOnly:false isAggregate:false trimType:false w3dType:#()=
	(
		local fName = fileArray[1]
		local fStream = fopen fName "rb"
		local fSOF = fileArray[2]
		local fSize = fileArray[3]
		local ChunksList = W3Dchunk.getChunks fStream fSOF fSize
		local depsArray = #()

		if w3dType.count > 0 do
		(
			if findItem w3dType "emit" > 0 do
			(
				if finditem ChunksList 0x00000500 > 0 do
				(
					W3Dchunk.FindChunk fStream 0x00000500 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000503 W3Dchunk.Start W3Dchunk.Size
					W3DEmitterInfo.ReadW3D fStream

					if findItem depsArray W3DEmitterInfo.TextureName == 0 do append depsArray W3DEmitterInfo.TextureName
				)				
			)
			if findItem w3dType "snd" > 0 do
			(
				if finditem ChunksList 0x00000a00 > 0 do
				(
					W3Dchunk.FindChunk fStream 0x00000a00 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000a02 W3Dchunk.Start W3Dchunk.Size
					W3DSoundEmitterInfo1.ReadW3D fStream 

					local sndFile = ((getFileNameFile W3DSoundEmitterInfo1.SoundFile) + (getFileNameType W3DSoundEmitterInfo1.SoundFile))
					if (findItem depsArray sndFile) == 0 do append depsArray sndFile
				)
			)
			if findItem w3dType "box" > 0 do
			(
				if finditem ChunksList 0x00000741 > 0 then
				(
					W3Dchunk.FindChunk fStream 0x00000741 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000001 fSOF fSize
					W3DSphereHeader.ReadW3D fStream W3Dchunk.Size

					if findItem depsArray W3DSphereHeader.TextureName == 0 do append depsArray W3DSphereHeader.TextureName
				)

				else if finditem ChunksList 0x00000742 > 0 then
				(
					W3Dchunk.FindChunk fStream 0x00000742 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000001 fSOF fSize
					W3DRingHeader.ReadW3D fStream W3Dchunk.Size

					if findItem depsArray W3DRingHeader.TextureName == 0 do append depsArray W3DRingHeader.TextureName
				)
			)
			if findItem w3dType "agg" > 0 do
			(
				if finditem ChunksList 0x00000600 > 0 then
				(
					W3Dchunk.FindChunk fStream 0x00000600 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000602 W3Dchunk.Start W3Dchunk.Size
					W3DAggregateInfo.ReadW3D fStream 

					for i = 1 to (W3DAggregateInfo.SubobjectNames).count do
					(
						local w3dName = (W3DAggregateInfo.SubobjectNames)[i] + ".w3d"
						if findItem depsArray w3dNAme == 0 do append depsArray w3dName
					)
				)
				else if finditem ChunksList 0x00000700 > 0 then
				(
					W3Dchunk.FindChunk fStream 0x00000700 fSOF fSize resetOffset:true
					W3Dchunk.FindChunk fStream 0x00000705 W3Dchunk.Start W3Dchunk.Size
					local aggStart = W3Dchunk.Start
					local aggSize = W3Dchunk.Size

					if W3Dchunk.FindChunk fStream 0x00000703 aggStart aggSize do
					(
						W3DHLODArrayHeader.ReadW3D fStream
						for i = 1 to W3DHLODArrayHeader.ModelCount do
						(
							W3Dchunk.FindChunk fStream 0x00000704 aggStart aggSize 
							W3DHLodSubObject.ReadW3D fStream
							local w3dName = W3DHLodSubObject.Name + ".w3d"
							if findItem depsArray w3dName == 0 do append depsArray w3dName
						)
					)
				)
			)
			if findItem w3dType "skn" > 0 do
			(
				if finditem ChunksList 0x00000000 > 0 do
				(
					W3DImportDlg.W3DFileOffset = fSOF
					while W3Dchunk.FindChunk fStream 0x00000000 fSOF fSize do
					(
						local meshStart = W3Dchunk.Start
						local meshSize = W3Dchunk.Size

						if (W3Dchunk.FindChunk fStream 0x00000030 meshStart meshSize) do
						(
							local texturesStart = W3Dchunk.Start
							local texturesSize = W3Dchunk.Size
							W3DFileOffset = texturesStart

							while W3Dchunk.FindChunk fStream 0x00000031 texturesStart texturesSize do
							(
								local textStart = W3Dchunk.Start
								local textSize = W3Dchunk.Size

								if W3Dchunk.FindChunk fStream 0x00000032 textStart textSize resetOffset:true do
								(
									W3DTextureName.ReadW3D fStream
									if findItem depsArray W3DTextureName.Name == 0 do append depsArray W3DTextureName.Name
								)

								W3DImportDlg.W3DFileOffset = textStart + textSize 
							)
						)
				
						W3DImportDlg.W3DFileOffset = meshStart + meshSize
					)
				)
			)

			fclose fStream
			return depsArray;
		)
				
		if isAggregate and finditem ChunksList 0x00000600 > 0 do
		(
			W3Dchunk.FindChunk fStream 0x00000600 fSOF fSize resetOffset:true
			W3Dchunk.FindChunk fStream 0x00000602 W3Dchunk.Start W3Dchunk.Size
			W3DAggregateInfo.ReadW3D fStream 

			local subobjectNames = W3DAggregateInfo.SubobjectNames
			for i = 1 to subobjectNames.count do
				if findItem depsArray subobjectNames[i] == 0 do append depsArray subobjectNames[i]

			fclose fStream
			return depsArray
		)

		if isAggregate and finditem ChunksList 0x00000700 > 0 do
		(
			W3Dchunk.FindChunk fStream 0x00000700 fSOF fSize resetOffset:true
			W3Dchunk.FindChunk fStream 0x00000705 W3Dchunk.Start W3Dchunk.Size
			local aggStart = W3Dchunk.Start
			local aggSize = W3Dchunk.Size

			if W3Dchunk.FindChunk fStream 0x00000703 aggStart aggSize do
			(
				W3DHLODArrayHeader.ReadW3D fStream
				for i = 1 to W3DHLODArrayHeader.ModelCount do
				(
					W3Dchunk.FindChunk fStream 0x00000704 aggStart aggSize 
					W3DHLodSubObject.ReadW3D fStream
					if findItem depsArray W3DHLodSubObject.Name == 0 do append depsArray W3DHLodSubObject.Name
				)
			)

			fclose fStream
			return depsArray
		)

		if not texturesOnly and finditem ChunksList 0x00000700 > 0 do
		(
			W3Dchunk.FindChunk fStream 0x00000700 fSOF fSize resetOffset:true
			local chunkStart = W3Dchunk.Start
			local chunkSize = W3Dchunk.Size

			if W3Dchunk.FindChunk fStream 0x00000701 chunkStart chunkSize do
			(
				W3DHLODHeader.ReadW3D fStream 

				for i = 1 to W3DHLODHeader.LodCount do
				(
					if W3Dchunk.FindChunk fStream 0x00000702 chunkStart chunkSize do
					(
						local lodArrayStart = W3Dchunk.Start
						local lodArraySize = W3Dchunk.Size

						if W3Dchunk.FindChunk fStream 0x00000703 lodArrayStart lodArraySize do
						(
							W3DHLODArrayHeader.ReadW3D fStream
							for j = 1 to W3DHLODArrayHeader.ModelCount do
							(
								W3Dchunk.FindChunk fStream 0x00000704 lodArrayStart lodArraySize 
								W3DHLodSubObject.ReadW3D fStream
								local sklName = W3DHLodSubObject.Container

								if  sklName != W3DHLODHeader.Name and sklName != "" do
								(
									local w3dName =(if trimType then sklName else sklName + ".w3d")
									if findItem depsArray w3dName == 0 do append depsArray w3dName
								)
							)
						)
					)
				)
			)
		)

		if not objectsOnly and finditem ChunksList 0x00000000 > 0 do
		(
			W3DImportDlg.W3DFileOffset = fSOF

			while W3Dchunk.FindChunk fStream 0x00000000 fSOF fSize do
			(
				local meshStart = W3Dchunk.Start
				local meshSize = W3Dchunk.Size

				if W3Dchunk.FindChunk fStream 0x00000030 meshStart meshSize resetOffset:true do
				(
					local texturesStart = W3Dchunk.Start
					local texturesSize = W3Dchunk.Size
					W3DImportDlg.W3DFileOffset = texturesStart

					while W3Dchunk.FindChunk fStream 0x00000031 texturesStart texturesSize do
					(
						local textStart = W3Dchunk.Start
						local textSize = W3Dchunk.Size

						if W3Dchunk.FindChunk fStream 0x00000032 textStart textSize resetOffset:true do
						(
							W3DTextureName.ReadW3D fStream
							if findItem depsArray W3DTextureName.Name == 0 do append depsArray W3DTextureName.Name
						)

						W3DImportDlg.W3DFileOffset = textStart + textSize 
					)
				)
				W3DImportDlg.W3DFileOffset = meshStart + meshSize
			)
		)

		fclose fStream
		return depsArray
	)




	fn removeFromDependencies depsArray checkArrays=
	(
		if depsArray.count == 0 do return #();

		local depFound = false
		for i = depsArray.count to 1 by -1 do
		(
			for a in checkArrays do if findItem a depsArray[i] > 0 do (depFound = true; exit;)
			if not depFound do
			(
				if DependenciesArray.count > depsArray[i] do
					for j = 1 to checkArrays.count do
						for k = 1 to checkArrays[j].count do
							if checkArrays[j][k] > depsArray[i] do checkArrays[j][k] -= 1

				deleteItem DependenciesArray depsArray[i]
				DependenciesList.selection = depsArray[i]
				DependenciesList.selected = ""
			)

			depFound = false
		)

		DependenciesList.selection = 0
		return #()
	)

	fn addToDependencies depsArray fInfo getDeps:false isAggregate:false=
	(
		if (local depID = findItem (for a in DependenciesArray collect(a.w3dName)) fInfo.w3dName) == 0 then
		(
			append DependenciesArray fInfo
			append depsArray (DependenciesArray.count)
		)
		else append depsArray depID

		if isAggregate do
		(
			local sknNames = (for a in SkinsArray collect(a[1]))
			local emitNames = (for a in EmittersArray collect(a[1]))
			local boxNames = (for a in BoxesArray collect(a[1]))
			local aggNames = (for a in AggregatesArray collect(a[1]))
			local soInfo
			local IDs = #()
			local soTypes = #()
			local soW3Dname = ""
			local sofName = "", sofSOF = 0, sofSize = 0
			local aggFound = #()
			local deps = #()
			local foundAggregate = #()

			local deps = ((local s = W3DImportDlg.W3D_FILE()).getDependencies fInfo IDs:#(0x600, 0x705))
			aggFound = (for o in deps where (i = findItem aggNames (filterString o ".")[1]) > 0 collect (#(o,i)))

			while aggFound.count > 0 do
			(
				for i = aggFound.count to 1 by -1 do
				(
					moreDeps = ((local s = W3DImportDlg.W3D_FILE()).getDependencies AggregatesArray[(aggFound[i][2])])
					deleteItem aggFound i
					if (tmp = (for o in moreDeps where (j = findItem aggNames (filterString o ".")[1]) > 0 collect (#(o,j))))[1][1] !="" do
					(
					)
				)
			)
					
			for o in subObjects.count do
			(
				if (local i = finditem emitNames o) > 0 do
				(
					soInfo = EmittersArray[3]
					if (bit.and EmittersArray[i][2] 64) == 64 then append IDs 0x500
					else if (bit.and EmittersArray[i][2] 128) == 128 then append IDs 0xa00
				)

				if (local i = finditem boxNames o) > 0 do
				(
					soInfo = BoxesArray[3]
					join IDs #(0x740, 0x741, 0x742)
				)

				if (local i = finditem aggNames o) > 0 do
				(
					soInfo = AggregatesArray[3]
					append IDs 0x600
				)

				if (local i = finditem sknNames o) > 0 do
				(
					soInfo = SkinsArray[3]
					join IDs #(0, 0x300, 0x420, 0x700, 0x741, 0x742, 0x900, 0xb00)
				)
			)
		)

/*
				if soW3Dname != "" do
				(
					if (local depID = findItem (for a in DependenciesArray collect(a[1])) soW3Dname) == 0 then
					(
						append DependenciesArray #(soW3Dname, "", 0, 0)
						append depsArray (DependenciesArray.count)
					)
					else if findItem depsArray depID == 0 do append depsArray depID

					local soDeps = W3DImportDlg.getFileDependencies #(sofName, sofSOF, sofSize) w3dType:soTypes

					for a in soDeps do
					(
						if (local depID = findItem (for b in DependenciesArray collect(b[1])) a) == 0 then
						(
							append DependenciesArray #(a, "", 0, 0)
							append depsArray (DependenciesArray.count)
						)
						else if findItem depsArray depID == 0 do append depsArray depID
					)
				)
			)
		)

		if getDeps do
		(
			local tmpArray = #()
			for a in (tmpArray = W3DImportDlg.getFileDependencies #(fName, fSOF, fSize) trimType:true) do
			(
				if (getFileNameType a) != ".tga" do a += ".w3d"
				if (local depID = findItem (for b in DependenciesArray collect(b[1])) a) == 0 then
				(
					append DependenciesArray #(a, "", 0, 0)
					append depsArray (DependenciesArray.count)
				)
				else if findItem depsArray depID == 0 do append depsArray depID
			)

			local sknNames = (for a in SkinsArray collect(a[1]))

			for a in tmpArray do
			(
				if (local sknID = findItem sknNames a) > 0 do
				(
					local skn = SkinsArray[sknID]
					for b in (W3DImportDlg.getFileDependencies #(skn[5], skn[6], skn[7]) texturesOnly:true) do
					(
						if (local depID = findItem (for c in DependenciesArray collect(c.w3dName)) b) == 0 then
						(
							append DependenciesArray (W3DInfo b, "", 0, 0)
							append depsArray (DependenciesArray.count)
						)
						else if findItem depsArray depID == 0 do append depsArray depID
					)
				)
			)
		)

*/
		return depsArray
	)

	fn checkSelectedAnimation val=
	(
		if val == curAnimation do return false;
		curAnimation = val
		curAnimsDeps = removeFromDependencies curAnimsDeps #(curAggregatesDeps, curSkinsDeps, curSkeletonsDeps)

		if val > 1 do curAnimsDeps = addToDependencies curAnimsDeps (w3dFilesList.getFileInfo SkeletonAnims[val][3])

		DependenciesList.items = (for a in DependenciesArray collect(a.w3dName))
		DependenciesList.selection = 0
	)

	fn checkSelectedAggregate val=
	(
		if val == curAggregate do return false;
		curAgg = val
		curAggDeps = removeFromDependencies curAggregatesDeps #(curAnimsDeps, curSkinsDeps, curSkeletonsDeps)

		if val > 1 do curAggDeps = addToDependencies curAggDeps (w3dFilesList.getFileInfo SkinsAggregates[val][3]) isAggregate:true

		DependenciesList.items = (for a in DependenciesArray collect(a.w3dName))
		DependenciesList.selection = 0
	)

	fn checkSelectedSkin val forceUpdate:false=
	(
		if val == curSkin and not forceUpdate do return false;
		curSkin = val

		SkinsAggregates = #(#("None", 0, "", 0, 0))
		if val > 1 do for a in AggregatesArray where a[2] == SkeletonSkins[val][3] do append SkinsAggregates a
		AggregatesList.items = (for a in SkinsAggregates collect(a[1]))

		curAggregatesDeps = removeFromDependencies curAggregatesDeps #(curAnimsDeps, curSkinsDeps, curSkeletonsDeps)
		curSkinsDeps = removeFromDependencies curSkinsDeps #(curAnimsDeps, curAggregatesDeps, curSkeletonsDeps)

		if val > 1 do curSkinsDeps = addToDependencies curSkinsDeps (w3dFilesList.getFileInfo SkeletonSkins[val][4]) getDeps:true

		DependenciesList.items = (for a in DependenciesArray collect(a.w3dName))
		DependenciesList.selection = 0

		curAggregate = 1
		AggregatesList.selection = 1
	)

	fn checkSelectedSkeleton val forceUpdate:false=
	(
		if val == curSkeleton and not forceUpdate do return false;
		curSkeleton = val

		SkeletonSkins = #(#("None", 0, "", 0, 0))
		SkeletonAnims = #(#("None", 0, "", 0, 0))
		for a in SkinsArray do if a[2] == val do append SkeletonSkins a
		for a in AnimationsArray do if a[2] == val do append SkeletonAnims a
		SkinsList.items = (for a in SkeletonSkins collect a[1])
		AnimationsList.items = (for a in SkeletonAnims collect a[1])

		DependenciesArray = #((w3dFilesList.getFileInfo SkeletonsArray[val][2]))
		curSkeletonsDeps = #(1)

		curAnimsDeps = #()
		curAnimation = 1
		AnimationsList.selection = 1
		curSkinsDeps = #()
		curSkin = 1
		SkinsList.selection = 1
		curAggregatesDeps = #()
		curAggregate = 1
		AggregatesList.selection = 1

		checkSelectedSkin 1 forceUpdate:true

		DependenciesList.items = (for a in DependenciesArray collect(a.w3dName))
		DependenciesList.selection = 0
	)

	fn UpdateLists val forceUpdate=
	(
		if val == curHierarchyPath and forceUpdate == false then return false;

		curHierarchyPath = val
		setFocus W3DHierarchyBuilderDlg

		SkeletonsList.items = #()
		SkeletonsList.selection = 0

		for i = (SkinsList.items).count to 0 by -1 do (SkinsList.selection = i; if i > 0 do SkinsList.selected = "")
		for i = (AnimationsList.items).count to 0 by -1 do (AnimationsList.selection = i; if i > 0 do AnimationsList.selected = "")
		for i = (AggregatesList.items).count to 0 by -1 do (AggregatesList.selection = i; if i > 0 do AggregatesList.selected = "")
		for i = (DependenciesList.items).count to 0 by -1 do (DependenciesList.selection = i; if i > 0 do DependenciesList.selected = "")

		SkeletonsArray = #()
		SkinsArray = #()
		AnimationsArray = #()
		AggregatesArray = #()
		EmittersArray = #()
		ModelsArray = #()
		BoxesArray = #()
		DependenciesArray = #()


		local curPath = W3DImporterInit.W3DFolders[curHierarchyPath]
		local fTypes = #("*.w3d")
		local mixToSkip = #("mixfile_sound_*", "mixfile_talktree_*", "Skirmish00")
		local datToSkip = #(#asset, #game, #game2, #Generals, #gi, #langdata, #patchget)
		local bigToSkip = #(#AmbientStreams, #Audio, #AudioEnglish, #AudioZH, #AudioEnglishZH, #Bases, #Data1, \
								#English, #EnglishZH, #gensec, #GensecZH, #INIZH, #ini, #Libraries, #lotrsec, #Maps, \
								#MapsZH, #Music, #MusicZH, #Shaders, #ShadersZH, #Speech, #SpeechZH, #SpeechEnglish, \
								#SpeechEnglishZH, #Terrain, #TerrainZH, #Textures, #TexturesZH, #Textures0, #Textures1, \
								#Textures2, #Textures3, #Textures4, #Window, #WindowZH)		

		W3DImportProgressDlg.Open()
		w3dFilesList.getFilesArray curPath fTypes mixSkip:mixToSkip datSkip:datToSkip bigSkip:bigToSkip
		W3DImportProgressDlg.resetProgress
		W3DImportProgressDlg.Stage.text = ("Getting hierarchy info for " + (w3dFilesList.filesArray.count as string) + " w3d files...")

		local w3dFile = W3DImportDlg.W3D_FILE()

		for i = 1 to w3dFilesList.filesArray.count do
		(
			W3DImportProgressDlg.updateProgress i w3dFilesList.filesArray.count

			if (local w3dInfo = w3dFile.getW3DInfo (w3dFilesList.getFileInfo i) rejectTypes:1536).count == 0 do continue

			if (bit.and w3dInfo[3] 1) == 1 do
			(
				local c = SkeletonsArray.count
				if c > 0 and SkeletonsArray[c][1] == w3dInfo[1] do w3dInfo[1] = w3dInfo[2] = (getFileNameFile w3dFilesList.filesArray[i][1])
				append SkeletonsArray #(w3dInfo[1], i)
			)
			if (bit.and w3dInfo[3] 2) == 2 or (bit.and w3dInfo[3] 8) == 8 or (bit.and w3dInfo[3] 32) == 32 do
				append SkinsArray #(w3dInfo[1], w3dInfo[2], w3dInfo[3], i)

			if (bit.and w3dInfo[3] 4) == 4 do
				append AnimationsArray #(w3dInfo[1], w3dInfo[2], i)

			if (bit.and w3dInfo[3] 16) == 16 do
				append AggregatesArray #(w3dInfo[1], w3dInfo[2], i)

			if (bit.and w3dInfo[3] 32) == 32 do
				append ModelsArray #(w3dInfo[1], w3dInfo[2], i)

			if (bit.and w3dInfo[3] 64) == 64 or (bit.and w3dInfo[3] 128) == 128 do
				append EmittersArray #(w3dInfo[1], w3dInfo[3], i)

			if (bit.and w3dInfo[3] 256) == 256 do
				append BoxesArray #(w3dInfo[1], w3dInfo[3], i)
		)

		w3dFile.closeW3D()

		W3DImportProgressDlg.resetProgress()
		W3DImportProgressDlg.Stage.text = ("Sorting...")

		qsort SkeletonsArray W3DImportDlg.compareArrays
		qsort SkinsArray W3DImportDlg.compareArrays
		qsort AnimationsArray W3DImportDlg.compareArrays
		qsort AggregatesArray W3DImportDlg.compareArrays

		local skeletonNames = #(), sknTypes = #(), sknNames = #()
		for a in SkeletonsArray do append skeletonNames a[1]
		for a in SkinsArray do (append sknNames a[1]; append sknTypes a[3])

		local numskn = SkinsArray.count
		local numanim = AnimationsArray.count
		for i = 1 to numskn do
		(
			W3DImportProgressDlg.updateProgress i (numskn + numanim)
/*
			if sknTypes[i] == 8 then
			(
				local skn = SkinsArray[i]
				for a in (W3DImportDlg.getFileDependencies #(skn[5], skn[6], skn[7]) objectsOnly:true trimType:true) do
				(
					if (local sknID = findItem sknNames a) > 0 do
					(
						sknTypes[sknID] = 0
						SkinsArray[sknID][3] = SkinsArray[i][1]
					)
				)

				SkinsArray[i][3] = SkinsArray[i][1]
			)
				
			else if (bit.and sknTypes[i] 2) == 2 then SkinsArray[i][3] = SkinsArray[i][1]
*/
			SkinsArray[i][2] = findItem skeletonNames SkinsArray[i][2]
		)
			
		for i = 1 to numanim do
		(
			W3DImportProgressDlg.updateProgress (i + numskn) (numskn + numanim)
			AnimationsArray[i][2] = findItem skeletonNames AnimationsArray[i][2]
		)

		W3DImportProgressDlg.Close()

		SkeletonsList.items = skeletonNames
		setFocus SkeletonsList

		if SkeletonsArray.count > 0 then
		(
			SkeletonsList.selection = 1
--			checkSelectedSkeleton 1 forceUpdate:true
		)
	)


	fn testAgg=
	(
		for i = 1 to (SkeletonsList.items).count do
		(
			SkeletonsList.selection = i
			checkSelectedSkeleton i

			for j = 1 to (SkinsList.items).count do
			(
				SkinsList.selection = j
				checkSelectedSkin j

				for k = 1 to (AggregatesList.items).count do
				(
					AggregatesList.selection = k
					checkSelectedAggregate k
				)
			)
		)
	)

	fn open=
	(
		createDialog W3DHierarchyBuilderDlg style:#(#style_titlebar, #style_sysmenu) \
			pos:[(CurrentScreenWidth / 2) - 350, (CurrentScreenHeight / 2) - 240]

		curHierarchyPath = W3DImporterInit.DefaultFolders
		HierarchyFolder.selection = curHierarchyPath
		w3dFilesList = W3DImportDlg.W3D_FILES_LIST()
	)

	on HierarchyFolder selected val do UpdateLists val false
	on SkeletonsList selected val do checkSelectedSkeleton val
	on SkinsList selected val do checkSelectedSkin val
	on AnimationsList selected val do checkSelectedAnimation val
	on AggregatesList selected val do checkSelectedAggregate val
--	on ImportButton pressed do testAgg()
)

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- MAIN W3D IMPORTER MENU
------------------------------------------------------------------------------------------------------- 

rcmenu W3DImportMenu 
( 
	subMenu "&File"
	(
		menuItem mi_i "&Import W3D"
		separator sep2
		menuItem mi_x "E&xit"
	) 

	subMenu "&Edit"
	(
		menuItem mi_p "&Preferences..."
	)

	subMenu "&Help"
	(
		menuItem mi_h "&W3D Importer References"
		separator sep3
		menuItem mi_a "&About W3D Importer"
	)

--	on mi_i picked do W3DImportDlg.ImportW3D()
	on mi_x picked do destroyDialog W3DImportDlg
	on mi_h picked do actionMan.executeAction 0 "40218"
	on mi_a picked do W3DImportAboutDlg.Open (getDialogPos W3DImportDlg)
	on mi_p picked do W3DPreferences.Open (getDialogPos W3DImportDlg)
) 

------------------------------------------------------------------------------------------------------- 
------------------------------------------------------------------------------------------------------- TOOLBAR BUTTON COMMAND FUNCTIONS
------------------------------------------------------------------------------------------------------- 

fn OpenW3DImporter=
(
	if W3DFlagsHelper.Opened != undefined do destroyDialog W3DFlagsHelper

	if W3DImporterInit.open() then
	(
		W3DImporterInit.init()
		W3DImporterInit.close()
	)

	else messageBox "W3D-Importer.ini not found!\n Make sure it is in ..\gmax\gamepacks\Westwood\RenX\RenX-WME\plugcfg\n\n"

	createDialog W3DImportDlg menu:W3DImportMenu style:#(#style_titlebar, #style_minimizebox, #style_sysmenu) \
		pos:[(CurrentScreenWidth / 2) - 359, (CurrentScreenHeight / 2) - 286]

	W3DImportDlg.Init()
	setFocus W3DImportDlg
)

fn OpenW3DTexturesBrowser=
(
	if W3DImporterInit.open() then
	(
		W3DImporterInit.init()
		W3DImporterInit.close()
	)

	else messageBox "W3D-Importer.ini not found!\n Make sure it is in ..\gmax\plugcfg\n\n"

	W3DTexturesBrowserDlg.open()
	setFocus W3DTexturesBrowserDlg
)

fn OpenW3DHierarchyBuilder=
(
	if W3DImporterInit.open() then
	(
		W3DImporterInit.init()
		W3DImporterInit.close()
	)

	else messageBox "W3D-Importer.ini not found!\n Make sure it is in ..\gmax\plugcfg\n\n"

	W3DHierarchyBuilderDlg.open()
	setFocus W3DHierarchyBuilderDlg
)

fn OpenW3DFlagsTool=
(
	W3DFlagsHelper.Open()
)

callbacks.addScript #filePostOpen "setW3DAppTitle()" id:#W3D_Editor
callbacks.addScript #PostImport "setW3DAppTitle()" id:#W3D_Editor
callbacks.addScript #systemPostNew "setW3DAppTitle()" id:#W3D_Editor
callbacks.addScript #systemPostReset "setW3DAppTitle()" id:#W3D_Editor

