Fixed TPM import and export maxscripts (version 02 and 124y)

Creating new content for Trespasser!

Moderators: TresCom Support Team, TresCom Board Managers, TresCom Developers

User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Fixed TPM import and export maxscripts (version 02 and 124y)

Post by machf »

OK, I took a quick look at the old TPM import script and tried a few things to fix the rotation problems, finally I found a way to do it. It may look sub-optimal, but it works.

Code: Select all

-- TPMImport script.
-- This is a horrible mish-mash of code from lots of places
-- Plain mesh import should work fine
-- There are lots of problems when creating MAX Skins/Joints/Bones

-- Known problems:
-- - Rotation order not checked
-- - Scaling mesh instance stuffs up the skin
-- - Skin ends up with many extra weights that I don't assign, automatically added when bones created?
--   (they seem to always be zero though, so not too bad)
-- Pushing the Skin.always_deform button twice nicely resets the reference position of the verts,
-- but setting it in a script doesn't! ARGHHHHHHHHHHH!!!

utility ImportTPM "TPM Import"
(
	local currentPath
	
	--------------------
	-- User Interface --
	--------------------
	group "About"
	(
		label lab1 "TPM Import v0.2 alpha"
		hyperLink addy "by Andres James" align:#center address:"mailto:tresutils@yahoo.com" color:(color 0 0 170) hoverColor:(color 170 0 0)
		label lab2 "Modified by M.A.Ch.F."

		button dlgTPMImportHelp "HELP"
	)

	on dlgTPMImportHelp pressed do (
		local helpStr = "
TPM Import lets you import Trespasser Model (.TPM) files, for example those exported by TresEd.

Usage:
Hit the \"Import TPM\" button and select the file to import. If you have any problems,
or if you intend to make extensive use of this script, please completely read this
dialog and the included readme.txt file.

Tips and Caveats:
- All meshes exported by TresEd should work.
- In theory a dino can be imported, edited, exported, and imported back into
  Trespasser with GeomAdd. I've tested changing vertex and tvert positions, but
  I haven't tried modifying which bone a vertex is attached to.
- Bumpmaps have not been tested
- For 'skin' types, a Skin modifier is added to the mesh, using bones named
  '$J%NN' where % is the mesh name, and NN is the bone number.
  NOTE: Following the Trespasser convention, bone numbers start at zero, as
  do the bone indicies in the vertex definitions.
  
IMPORTANT NOTES ABOUT IMPORTING JOINTS/BONES
- You must not scale the imported object (ie. use Import Scale = 1.0)
- Before the skin modifier (ie. joints/bones) will correctly act on a mesh you must
  do the following: Open the Modifier panel and select the \"Skin\" modifier. In the
  \"Advance Params\" rollout deselect \"Always Deform\" then select it again.
- Some bone parameters are stored in the User Properties text buffer and can
  only be modified there. eg. Anim00, Anim01, Ratio, and RotationRatio.
- Bone hierarchy is not set up ie. bones have no parents/children.
- Loading a mesh with bones can be MUCH slower than loading a plain mesh, be patient.
"
		messageBox helpStr title:"TPM Import Help"
	)
	
	local gImportScale = 1.0
		
	group "Import"
	(
		checkbox resetCheck "Reset MAX scene" checked:false disabled:true
		spinner spnImportScale "Import scale" range:[0.0000001,100,gImportScale]
		button importTPMButton "Import TPM..." toolTip:""
		--button testImportTPMButton "My test fn..." toolTip:""
	)

	on spnImportScale changed val do (
		gImportScale = val
	)

	--------------------
	-- Misc Functions --
	--------------------

fn IsInstance objA objB = (
	(isKindOf objA node) AND
	(isKindOf objB node) AND
	(objA.baseObject == objB.baseObject)
)

fn GetInstances obj = (
	local objs

	local bObj = obj.baseObject
	local rObjs = refs.dependents bObj
	objs = for rObj in rObjs where ( (isKindOf rObj node) AND
									(bObj == rObj.baseObject) AND
									(obj != rObj) ) collect rObj
	return objs
)
	--------------------------
	-- TPM Import Functions --
	--------------------------

	-- Load a texture file
	fn GetTexture name = (
		local bmpFilename = name
		
		local texMap = sceneMaterials[bmpFilename]
		if texMap != undefined then
		(
			if (classof texMap) != BitmapTexture then
			(
				texMap = undefined
			) else
			(
				return texMap
			)
		)
		
		try
		(
			--print currentpath
			--print bmpfilename
			local bmp = openBitMap (currentPath + bmpFilename)
			texMap = BitmapTexture bitmap:bmp name:bmpFileName
		) catch
		(
			return undefined
		)
		texMap
	)
	
	-- Set parent of bone b to be bone p
	fn SetBoneParent b p = (
		-- Want to re-align bone so finishes at parent, not working...
		--p.dir = b.pos - p.pos
		--p.length = 20 --distance p.pos b.pos
		skinops.setendpoint
		b.parent = p
	)
	fn SetBoneParent2 ms b p  = (
		-- Why won't this work!!!!
		local pos = skinops.getStartPoint ms (p as integer)
		skinops.setendpoint ms (b as integer) pos
		--b.parent = p
	)


	-- given mesh, array of bones for mesh, and bone number for each vertex, setup bones and a Skin modifier
	-- bone numbers and boneVerts start at '1'
	fn SetupBones m bones boneVerts = (
		-- Skin stuff only works if the modifer panel is open, and mesh is selected
		max modify mode
		select m
		ms = Skin()
		ms.rigid_vertices = true
		addModifier m ms
		
		-- Hack to try mark bone parents, should be in seperate script as they're different for each dino type
		local gpar = #( [4,3],[3,2],[2,1],[1,0], [15,14],[14,13],[13,12], [19,18],[18,17],[17,16],[14,16], [7,6],[8,7],[9,7],[23,7],[26,7])
		--for i=1 to gpar.count do
			--SetBoneParent bones[gpar[i][1]+1] bones[gpar[i][2]+1]

		-- Add bones to mesh, using update flag '-1' for last bone
		for i=1 to bones.count-1 do
			skinops.addbone ms bones[i] 0
		if bones.count > 0 then
			skinops.addbone ms bones[bones.count] -1
		update m -- do we need this?

		--for i=1 to gpar.count do
			--SetBoneParent2 ms (gpar[i][1]+1) (gpar[i][2]+1)
		
		-- Add vertex weights
		for i=1 to m.verts.count do (
			skinops.setVertexWeights ms i boneverts[i] 1
		)
		update m -- do we need this?
	)
	
	-- Return list of bones for given mesh, searching through the given object list
	-- Bone name is of form "$J%NN" Where % is the mesh name, and NN is a number
	-- If zeroIsValid is false, bone number 'k' is returned in list position 'k' as expected.
	-- If zeroIsValid is true, then 00 is a valid bone number, and bone number 'k' is
	-- returned in position 'k+1' in the list (because MAX lists can only start at 1...)
	fn FindBones m objs zeroIsValid:false = (
		-- Find bones for given mesh, 
		format "FindBones\n"
		local tempBones = #()
		local startIndex = 1
		if zeroIsValid == true then startIndex = 0
		for j=startIndex to 40 do (
			local n = (j as string)
			if j < 10 then
				n = "0" + (j as string)
			local boneName = "$J" + m.name + n
			local b = (for b in objs where b.name == boneName collect b)[1]
			if b != undefined then (
				tempBones[j+1-startIndex] = b
				format "Found %\n" b.name
			)
		)
		return tempBones
	)
	
	fn ImportTPM O_File = (
		
		if O_File == undefined then
		(
			print "File not found"
			return false
		)
		format "Importing '%'...\n" O_File
		currentPath = getFilenamePath O_File
			
		I_Stream = openFile O_File mode:"r"

		local verts = #()
		local tverts = #()
		local faces = #()
		local tvfaces = #()
		local boneverts = #()
		local faceMats = #()

		local meshName = "DefaultMeshName"
		local meshMats = #()
		local usedMeshes = #() -- keep track of which meshes we've created instances of already
		
		local instName
		local instPos, instRot, instScale
		
		local matName = undefined
		local matDiffuseMap = undefined
		local matOpacityMap = undefined
		local matBumpMap = undefined
		local materials = #()
		local materialNames = #()
		
		local bones = #()
		local bonePosition
		local boneName
		
		local userProps = ""
		
		local parseMode = "root"
		local unknownMode = false
		local doneSkinWarning = false
		
		while ((eof I_Stream) == false) do
		(
			Cur_Line = readLine I_Stream
			stringArray = filterString Cur_Line " =()<>,\""
			--LineToken = read_token Cur_Line
			LineToken = stringArray[1]

			-- Skip empty lines and comments
			if (LineToken == undefined) then continue
			if (LineToken == "") then continue
			if (substring LineToken 1 2 == "//") then continue

			if unknownMode == true then ( -- Skip interior of unknown blocks
				if LineToken == "}" then (
					unknownMode = false
				)
			) else
			if parseMode == "root" then (
				userProps = ""
				case LineToken of
				(
					"fileinfo": (
						unknownMode = true
					)
					"bone": (
						parseMode = "bone"
						boneName = stringArray[2]
						bonePosition = [0,0,0]
					)
					"j": ( --@HACK, TresEd only supports bones (joints) in old format
						boneName = stringArray[2]
						x = (stringArray[3] as float)
						y = (stringArray[4] as float)
						z = (stringArray[5] as float)
						local size = gImportScale * 0.1
						local bone = BoneSys.createBone [0,0,0] [size,0,0] [0,0,1];
						bone.name = boneName
						bone.width = size
						bone.height = size
						bone.pos = [x, y, z] * gImportScale
						append bones bone
						format "bone % % % %\n" boneName x y z
					)
					"material": (
						parseMode = "material"
						matName = stringArray[2]
						matDiffuseMap = undefined
						matOpacityMap = undefined
						matBumpMap = undefined
					)
					"mesh": (
						parseMode = "mesh"
						meshName = stringArray[2]
						verts = #()
						faces = #()
						tverts = #()
						tvfaces = #()
						faceMats = #()
						meshMats = #()
						boneverts = #()
					)
					"skin": (
						parseMode = "skin"
						meshName = stringArray[2]
						verts = #()
						faces = #()
						tverts = #()
						tvfaces = #()
						faceMats = #()
						meshMats = #()
						boneverts = #()
					)
					"instance": (
						parseMode = "instance"
						instName = stringArray[2]
						meshName = instName
						instPos = [0,0,0]
						instRot = [0,0,0]
						instScale = [1,1,1]
					)
					"{": ()
					"}":(
						unknownMode = false
					)
					default: (
						if unknownMode == false then (
							format "Unknown root element %\n" LineToken 
						)
						unknownMode = true
					)
				)
			) else
			if parseMode == "bone" then ( -- untested
				case LineToken of
				(
					"position": (
						x = (stringArray[2] as float)
						y = (stringArray[3] as float)
						z = (stringArray[4] as float)
						bonePosition = [x, y, z] * gImportScale
						--format "bonepos % % %\n" x y z
					)
					"}": (
						parseMode = "root"
						local size = gImportScale * 0.1
						local bone = BoneSys.createBone [0,0,0] [size,0,0] [0,0,1];
						bone.name = boneName
						bone.width = size
						bone.height = size
						bone.pos = [x, y, z] * gImportScale
						setuserpropbuffer bone userProps
						append bones bone
						format "bone % % % %\n" boneName x y z
					)
					"Anim00": ( userProps += Cur_Line + "\n" )
					"Anim01": ( userProps += Cur_Line + "\n" )
					"Ratio": ( userProps += Cur_Line + "\n" )
					"RotationRatio": ( userProps += Cur_Line + "\n" )
					"rotation": ( userProps += Cur_Line + "\n" )
				)
			) else
			if parseMode == "material" then (
				case LineToken of
				(
					"colormap": (
						matDiffuseMap = fileNameFromPath stringArray[2]
						--format "diffusemap %\n" matDiffuseMap
					)
					"opacitymap": (
						matOpacityMap = fileNameFromPath stringArray[2]
					)
					"bumpmap": (
						matBumpMap = fileNameFromPath stringArray[2]
					)
					"}": (
						parseMode = "root"
						local mat =  standard name:matName showInViewport:true
						if matDiffuseMap != undefined then (
							local texmap = GetTexture matDiffuseMap
							if texmap != undefined then (
								mat.maps[2] = texmap
								mat.mapEnables[2] = true
								showTextureMap mat texmap true
							) else
								format "Warning: Can't find texture map file %\n" matDiffuseMap
						)
						if matOpacityMap != undefined then (
							local texmap = GetTexture matOpacityMap
							if texmap != undefined then (
								mat.maps[7] = texmap
								mat.mapEnables[7] = true
								showTextureMap mat texmap true
							) else
								format "Warning: Can't find opacity map fimle %\n" matOpacityMap
						)
						if matBumpMap != undefined then (
							local texmap = GetTexture matBumpMap
							if texmap != undefined then (
								mat.maps[9] = texmap
								mat.mapEnables[9] = true
								showTextureMap mat texmap true
							) else
								format "Warning: Can't find bump map file %\n" matBumpMap
						)
						showTextureMap mat on
						append materialNames matName
						append materials mat
						format "material %\n" matName
					)
				)
			) else
			if parseMode == "mesh" or parseMode == "skin" then (
				case LineToken of
				(
					"m":
					(
						-- Find material in global list
						local index = findItem materialNames stringArray[2]
						if index != 0 then
						(
							--format "material %\n" stringArray[2]
							append meshMats materials[index]
						) else (
							format "material % not found, substituted default\n" stringArray[2]
							local tempmat = standard name:stringArray[2]
							append meshMats tempmat
						)
					)
					"v":
					(
						x = (stringArray[2] as float)
						y = (stringArray[3] as float)
						z = (stringArray[4] as float)
						append verts ([x, y, z] * gImportScale)
						local b = undefined
						if stringArray[5] != undefined then b = (stringArray[5] as integer)
						if (parseMode=="skin") then (
							if b == undefined then (
								format "missing bone index\n"
								b = 0
							)
							if b < 0 then (
								format "unknown bone index %\n" b
								b = 0
							)
							b = b + 1 -- because TPM bones and bone indicies start at zero
							append boneverts b
						)
						--format "vertex % % %\n" x y z
					)
					"t":
					(
						x = (stringArray[2] as float)
						y = (stringArray[3] as float)
						append tverts [x, y, 0]
						--format "tvert % %\n" x y
					)
					"f":
					(
						a = (stringArray[2] as integer)
						b = (stringArray[3] as integer)
						c = (stringArray[4] as integer)
						append faces [a, b, c]
						a2 = (stringArray[5] as integer)
						b2 = (stringArray[6] as integer)
						c2 = (stringArray[7] as integer)
						append tvfaces [a2, b2, c2]
						m = (stringArray[11] as integer)
						append faceMats m
						--format "face (% % %) (% % %) %\n" a b c a2 b2 c2 m
					)
					"}": (
						if parseMode == "skin" then
							format "skin %\n" meshName
						else
							format "mesh %\n" meshName
						--@TODO what if no meshMats?
						local material = multiMaterial numsubs:meshMats.count name:meshName
						for i = 1 to meshMats.count do (
							--format "mat: %\n" meshMats[i].name
							material[i] = meshMats[i]
						)
						-- Make an editable mesh
						local ss = 1
						--local ss = 2.47791 --@HACK for raptorC
						local m = mesh name:meshName position:[0, 0, 0] scale:[ss, ss, ss] \
							faces:faces vertices:verts material:material
						--update m
						setNumTVerts m tverts.count false
						for i = 1 to tverts.count do settvert m i tverts[i]
						buildTVFaces m false
						for i = 1 to tvfaces.count do settvface m i tvfaces[i]
						-- Assign material ID's NB. materials must be already defined
						for i = 1 to faces.count do
						(
							local matID = 1
							--local matSlot = 1
							--matID = material.materialIDList[matSlot]
							setFaceMatID m i faceMats[i]
						)
						update m
						
						-- Setup Bones
						if parseMode == "skin" then (
							if doneSkinWarning == false then (
								messageBox "NOTE: Importing skins can take a VERY long time" title:"TPM Skin import"
								doneSkinWarning = true
							)
							local meshBones = FindBones m bones zeroIsValid:true
							-- Make sure all bones are defined or SetupBones will complain
							if meshBones != undefined then (
								format "Found % bones\n" meshBones.count
								SetupBones m meshBones boneVerts
							)
						)
						parseMode = "root"
					)
				)
			) else
			if parseMode == "instance" then (
				case LineToken of
				(
					"position": (
						instPos = ([(stringArray[2] as float), (stringArray[3] as float), (stringArray[4] as float)] * gImportScale)
					)
					"rotation": (
						instRot = ([(stringArray[2] as float), (stringArray[3] as float), (stringArray[4] as float)])
					)
					"scale": (
						local s = (stringArray[2] as float)
						instScale = [s, s, s]
					)
					"mesh": (
						meshName = stringArray[2]
					)
					"}": (
						parseMode = "root"
						-- find mesh
						local bmesh = undefined
						for m in objects where m.name==meshName do bmesh = m
						if bmesh != undefined then (
							local doneBefore = false
							 -- save 'mesh' object so we can delete it later (as we now have at least one instance of it)
							for o in usedMeshes where o.name==meshName do
								doneBefore = true
							if doneBefore == false then
								append usedMeshes bmesh
							-- create new instance
							local inst = instance bmesh
							inst.name = instName
							inst.pos = instPos
							inst.rotation = quat 0 0 0 1
							inst.scale = instScale
							--local euler = eulerAngles instRot.x instRot.y instRot.z
							--@HACK MAX says rotations are right-handed, but seems to rotate in the left-handed way...
							--Perhaps things just aren't being done in the world coordinate system.
							--local euler = eulerAngles -instRot.x -instRot.y -instRot.z
							--rotate inst (eulerToQuat euler order:1) -- rotate using Euler angles
							local euler = eulerAngles -instRot.x 0 0
							rotate inst (eulerToQuat euler order:1) -- rotate using Euler angles
							local euler = eulerAngles 0 -instRot.y 0
							rotate inst (eulerToQuat euler order:1) -- rotate using Euler angles
							local euler = eulerAngles 0 0 -instRot.z
							rotate inst (eulerToQuat euler order:1) -- rotate using Euler angles
							format "instance % mesh:%" instName meshName
							format " pos:% rot:% scl:%\n" instPos instRot instScale
						) else (
							format "NOTE: Mesh % for instance % not found.\n" meshName instName
						)
					)
				)
			) -- endif parseMode
			
		) -- endif while !eof
			
		close i_stream
		-- remove the extra meshes that we now have instances of
		for m in usedMeshes do (
			delete m
		)
		
		max views redraw
	)
	
	--------------------------
	-- Main Import Function --
	--------------------------
	fn ResetMAX = (
		resetMAXFile #noprompt
		max utility mode
	)

	on importTPMButton pressed do
	(

		O_File = getOpenFileName "Import TPM" types:"TPM Files (*.tpm)|*.tpm|All Files (*.*)|*.*"
		if O_File != undefined then (
			if resetCheck.checked then
				ResetMAX()
			ImportTPM O_File
		)
	)
	on testImportTPMButton pressed do
	(
		ResetMAX()
		ImportTPM "D:/Andres/Temp/bonetest.tpm"
		--ImportTPM "D:/Andres/Temp/test.txt"
		--ImportTPM "D:/Andres/Temp/crate.tpm"
		max utility mode
		if false then (
			for o in objects do (
				local bob = ""
				format "name: % % %\n" o o.name (classof o)
				if (classof o) == Editable_Mesh then (
					format " name:% %\n" o.name (classof o.mesh)
					--format " mesh:%\n" o.mesh.name
					format " pos:%\n" o.pos
				)
			)
		)
	)


)
Just copy and paste this to a text file, save it as "tpmimport2.ms". It's the original script with only a few modifications, in case you're wondering.

Now I'll have to look at how to fix the export script so that rotations match the ones from TresEd and the fixed import script...
Last edited by machf on Thu Jan 10, 2008 3:47 pm, edited 1 time in total.
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Post by machf »

Well, apparently this will do for the export script:

Code: Select all

-- TPM Exporter
--  Version 1.2.4
--  by Martijn Buijs, Andres James
--  Copyright © TresCom, 2007

-- Version History:
-- 1.2.4
--  * added workaround for "getfacernormals" bug in 3dsmax 4
-- 1.2.3
--  * tool now sits in a floating tool window
--  * script no longer crashes if file is not accessable
--  * smoothing groups are now properly exported
--  * fix scale option now actually works
--  * pivot offset is now properly handled (but not pivot rotation)
-- 1.2.2
--  * added export "Selection Only" option
--  * added several warnings
--  * fixed crash on hidden submaterials
--  * fixed several stability issues related to materials
--  * only materials of exported meshes are written to file
--  * non standard materials are now ignored
--  * disabled (unchecked) material maps are no longer exported
--  * cleaned up code and added comments

-- To do:
--  * create flipped triangles copies for twosided materials (optional)
--  * export mirrored objects correctly

-- clean up
clearlistener()

-- file handle
global filename
global fileobj

-- options
global opt_scalefix = false

-- material redundancy list
global matlist = #()
global matlistnum = 0

-- warnings
global warn_notobj = false
global warn_mirror = false
global warn_twoside = false

-- write material
fn WriteMaterial mat =
(
 -- check if material is already exported
 for i=1 to matlistnum do
 (
  if matlist[i] == mat do return false
 )

 -- write material
 format "\nmaterial \"%\"\n{\n" mat.name to: fileobj
 if (classOf(mat.diffusemap) == BitmapTexture) AND (mat.diffusemapenable == true) do
 (
  format " colormap = \"%\"\n" mat.diffusemap.filename to: fileobj
 )
 if (classOf(mat.opacitymap) == BitmapTexture) AND (mat.opacitymapenable == true) do
 (
  format " opacitymap = \"%\"\n" mat.opacitymap.filename to: fileobj
 )
 format "}\n" to: fileobj
 
 -- add to redundancy list
 matlistnum = matlistnum+1
 matlist[matlistnum] = mat
 
 -- warnings
 if mat.twosided do warn_twoside = true
)

-- write bones
fn WriteBoneChildren obj =
(
 local i
 if obj.children.count > 0 do
 (
  for i=1 to obj.children.count do
  (
   format " j = \"%\"" obj.children[i].name to: fileobj
   format ",(%,%,%)" obj.children[i].pos.x obj.children[i].pos.y obj.children[i].pos.z to: fileobj
   format ",(-90,-90,-90),(90,90,90),\"%\"\n" obj.name to: fileobj
   WriteBoneChildren obj.children[i]
  )
 )
)

-- write bonesystem
fn WriteBonesys obj =
(
 if obj.parent == undefined do
 (
  format "\nbonesys \"%\"\n{\n" obj.name to: fileobj
  format " r = \"%\",(%,%,%)\n" obj.name obj.pos.x obj.pos.y obj.pos.z to: fileobj
  WriteBoneChildren obj
  format "}\n" to: fileobj
 )
)


-- adds float3 to list
fn addToList list v =
(
 if (v == undefined) do return list.count --bugfix
 
 for i=1 to list.count do
 (
  if list[i].x == v.x do (
   if list[i].y == v.y do (
    if list[i].z == v.z do (
     return i
    )
   )
  )
 )
 append list v
 return list.count
)


-- write mesh
fn WriteMesh obj =
(
 local op = obj.objectoffsetpos
 local os = obj.scale
 
 -- write mesh materials
 case classof(obj.mat) of
 (
  UndefinedClass:()
  StandardMaterial:
  (
   WriteMaterial obj.mat
  )
  MultiMaterial:
  (
   for i=1 to obj.mat.numsubs do
   (
    if classof(obj.mat[i]) == StandardMaterial do
    (
     WriteMaterial obj.mat[i]
    )
   )
  )
 )
 
 local isskin = false
 local boneVerts = #()
 local i
 local k
 if classof(obj.modifiers[1]) == Skin then
 (
  isskin = true
  local myskin = obj.modifiers[1]
  
  -- skin stuff only works if the modifer panel is open and mesh is selected
  max modify mode
  select obj
  
  -- collect up bone indicies for each vertex
  for i=1 to skinOps.getNumberVertices myskin do
  (
   local maxb = 0 -- best bone so far
   local maxw = 0.0 -- best weight so far
   -- Trespasser only supports singly weighted verticies, so choose bone with greatest influence on vertex
   for k=1 to (skinops.getVertexWeightCount myskin i) do
   (
    if (skinops.getVertexWeight myskin i k) > maxw then
    (
     maxw = (skinops.getVertexWeight myskin i k)
     maxb = (skinops.getVertexWeightBoneID myskin i k)
    )
    append boneVerts maxb -- TODO: should be error if not attached to any bone?
   )
  )
  format "\nskin \"%\"\n{\n" obj.name to: fileobj
 ) else (
  format "\nmesh \"%\"\n{\n" obj.name to: fileobj
 )
 
 -- standard material
 case classof(obj.mat) of
 (
  StandardMaterial:
  (
   format " m = \"%\"\n" obj.mat.name to: fileobj
  )
  MultiMaterial:
  (
   for i=1 to obj.mat.numsubs do
   (
    if classof(obj.mat[i]) == StandardMaterial then
    (
     format " m = \"%\"\n" obj.mat[i].name to: fileobj
    ) else (
     format " m = \"dummy\"\n" to: fileobj
    )
   )
  )
 )
 
 -- write vertices
 local v
 for i=1 to obj.numverts do
 (
  in coordsys local v = (getvert obj i)
  
  if opt_scalefix do
  (
   v = (v + op) * os
  )
  
  if isskin == true then
  (
   format " v = (%,%,%),%\n" v.x v.y v.z (boneVerts[i]-1) to: fileobj -- write extra bone index
  ) else (
   format " v = (%,%,%)\n" v.x v.y v.z to: fileobj
  )
 )
 
 -- write texcoords
 local t
 if obj.numtverts != 0 then
 (
  for i=1 to obj.numtverts do
  (
   t = (gettvert obj i)
   format " t = (%,%)\n" t.x t.y to: fileobj
  )
 ) else (
  format " t = (0,0)\n" to: fileobj
 )
 
 -- write normals
 local normlist = #()
 local fnlist = #()
 for i=1 to obj.numfaces do
 (
  if (getfacesmoothgroup obj i) == 0 then
  (
   in coordsys local frn = getfacenormal obj i
   n1 = addToList normlist frn
   n2 = n1
   n3 = n1
  ) else (
   in coordsys local frn = (meshop.getfacernormals obj i)
   
   -- start bug workaround: sometimes frn does not have three elements in 3dsmax 4 (mxs bug)
   if frn.count != 3 do 
   (
    in coordsys local frn[1] = getfacenormal obj i
	frn[2] = frn[1]
	frn[3] = frn[1]
   )
   -- end bug workaround
   
   n1 = addToList normlist frn[1]
   n2 = addToList normlist frn[2]
   n3 = addToList normlist frn[3] 
  )
  append fnlist #(n1,n2,n3)
 )
 for i=1 to normlist.count do
 (
  format " n = (%,%,%)\n" normlist[i].x normlist[i].y normlist[i].z to: fileobj
 )
 normlist = #()
 
 -- write faces
 for i=1 to obj.numfaces do
 (
 
  -- face vertex pointers
  v = (getface obj i)
  if obj.numtverts != 0 do
  (
   t = (gettvface obj i)
  )
  n = (getface obj i)
  f = (getfacematid obj i)
  format " f = (%,%,%)" (v.x as integer) (v.y as integer) (v.z as integer) to: fileobj
  
  -- face texcoord indices
  if obj.numtverts == 0 then
  (
   -- no texcoords, so lets point texcoord indices to this dummy coord
   format ",(1,1,1)" to: fileobj
  ) else (
   format ",(%,%,%)" (t.x as integer) (t.y as integer) (t.z as integer) to: fileobj
  )
  
  -- face normal indices
  format ",(%,%,%)" (fnlist[i][1] as integer) (fnlist[i][2] as integer) (fnlist[i][3] as integer) to: fileobj
  
  -- material indices
  case classof(obj.material) of
  (
   UndefinedClass:
   (
    -- no material on mesh
    format ",0\n" to: fileobj
   )
   StandardMaterial:
   (
    -- single material for entire mesh
    format ",1\n" to: fileobj
   )
   MultiMaterial:
   (
    -- submaterials, per face
    format ",%\n" (getfacematid obj i as integer) to: fileobj
   )
  )
 )
 
 -- clean up
 fnlist = #()
 
 -- end of mesh chunk
 format "}\n" to: fileobj
)

-- write instance
fn WriteInstance obj =
(
 format "\ninstance \"%\"\n{\n" obj.name to: fileobj
 
 -- mesh binding
 format " mesh = \"%\"\n" obj.name to: fileobj
 
 -- position
 format " position = (%,%,%)\n" obj.pos.x obj.pos.y obj.pos.z to: fileobj
 
 -- rotation
-- local ea = quatToEuler obj.rotation order:1 
 local eax = obj.rotation.x_rotation
 local eay = obj.rotation.y_rotation
 local eaz = obj.rotation.z_rotation
 -- TODO: check which order is correct
 -- euler angles seem to be -ve what they should be, probably stuffing up the rotation order too, should check
-- format " rotation = (%,%,%)\n" ea.x ea.y ea.z to: fileobj
 format " rotation = (%,%,%)\n" eax eay eaz to: fileobj
 
 -- scale
 if opt_scalefix then
 (
  format " scale = 1\n" to: fileobj
 ) else (
  format " scale = %\n" obj.scale.x to: fileobj
 )
 
 -- end of instance chunk
 format "}\n" to: fileobj
)

utility TpmExp "TPM Exporter"
(
 group "About"
 (
  label lab1 "TPM Exporter"
  label lab2 "Version 1.2.4y"
  label lab3 "by Martijn Buijs, Andres James"
  label lab4 "Modified by M.A.Ch.F."
  label lab5 "Copyright © TresCom, 2008"
 )
 group "Options"
 (
  checkbox chkScaleFix "Fix Scale" checked: false
 )
 group "Export"
 (
  checkbox chkSelected "Selection Only" checked: false
  checkbox chkSkipHidden "Skip Hidden Objects" checked: true
  checkbox chkSkipFrozen "Skip Frozen Objects" checked: true
  button cmdExport "Export Scene..." width: 140
 )
 on cmdExport pressed do
 (
  local j
  local b
  
  -- options
  opt_scalefix = chkScaleFix.checked
  
  -- reset material redundancy list
  matlist = #()
  matlistnum = 0
  
  -- reset warning flags
  warn_notobj = false
  warn_mirror = false
  warn_twoside = false
  
  -- save file dialog
  filename = getSaveFileName caption:"Export Scene" types:"Trespasser Models (*.tpm)|*.tpm|All Files (*.*)|*.*"
  if filename == undefined then
  (
   return false
  )
  
  fileobj = createfile filename
  if fileobj == undefined do
  (
   messagebox "Could not create file!"
   return false
  )
   
  -- print file header
  format "// Trespasser Model File (.tpm)\n" to: fileobj
  format "\nfileinfo\n{\n" to: fileobj
  format " formatversion = 1.0.1\n" to: fileobj
  format " name = \"%\"\n" maxFileName to: fileobj
  format " version = 1.2.2\n" to: fileobj
  format " source = \"%\"\n" maxFileName to: fileobj
  format " date = %\n" localTime to: fileobj
  format " comments = \"\"\n" to: fileobj
  format "}\n" to: fileobj
   
  -- write objects
  local obj
  for j=1 to $objects.count do
  (
   obj = $objects[j]
  
   -- skip hidden
   if chkSkipHidden.checked == true do
   (
    if obj.ishidden do continue
   )
   
   -- skip frozen
   if chkSkipFrozen.checked == true do
   (
    if obj.isFrozen do continue
   )
   
   -- skip unselected
   if chkSelected.checked == true do
   (
    if not obj.isSelected do continue
   )
   
   -- write data block
   case classof(obj) of
   (
    
    -- print bonesys (max 2.5)
    Bone:
    (
     WriteBonesys obj
    )
   
    -- write bonesys (max 3.0 and up)
    BoneGeometry:
    (
     format "\nbone \"%\"\n{\n" obj.name to: fileobj
     format " position = (%,%,%)\n" obj.pos.x obj.pos.y obj.pos.z to: fileobj
     local userProps = getuserpropbuffer obj
     if userProps != undefined AND userProps != "" do
     (
      format "%" userProps to: fileobj
     )
     format"}\n" to: fileobj
    )
    
    -- write mesh
    Editable_mesh:
    (
     WriteMesh obj
     WriteInstance obj
    )
    
    -- silently ignore
    OmniLight:()
    FreeSpot:()
    TargetSpot:()
    DirectionalLight:()
    TargetDirectionalLight:()
     
    -- other objects
    default:
    (
     warn_notobj = true
     messagebox obj.name
    )
    
   )
   
   -- warnings
   if obj.scale.x < 0 do warn_mirror = true
   if obj.scale.y < 0 do warn_mirror = true
   if obj.scale.z < 0 do warn_mirror = true
   
  )
  
  -- close file
  close fileobj
  
  -- clean up material redundancy list
  matlist = #()
  matlistnum = 0
  
  -- warnings
  local errstr = ""
  if warn_notobj do  errstr = errstr + "* not all scene objects could be exported\n"
  if warn_mirror do  errstr = errstr + "* some objects are mirrored, this may lead to object orientation problems\n"
  if warn_twoside do errstr = errstr + "* some materials are two sided, these are not preserved\n"
  if errstr.count > 0 do messagebox ("Warning:\n" + errstr)
   
  -- success confirmation
  messagebox "Scene exported successfully."
  
 )
)



-- END OF FILE


Again, copy and paste to a text file, save as "tpmexp124y.ms". And yes, it's just the last available export script with a few modifications. Try it and let me know if eveything is OK.

If you have TPM files which were previously exported from MAX or Gmax, import them with the old import script, and re-export them with the new export script, that should fix them. If your files were exported with TresEd, you don't need to change them, just use the new import and export scripts to work with them on MAX or Gmax.
Last edited by machf on Thu Jan 10, 2008 3:45 pm, edited 2 times in total.
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Post by machf »

And here's a modified version of the exporter for use with Gmax:

Code: Select all

-- TPM Exporter
--  Version 1.2.4
--  by Martijn Buijs, Andres James
--  Copyright © TresCom, 2007

-- Version History:
-- 1.2.4
--  * added workaround for "getfacernormals" bug in 3dsmax 4
-- 1.2.3
--  * tool now sits in a floating tool window
--  * script no longer crashes if file is not accessable
--  * smoothing groups are now properly exported
--  * fix scale option now actually works
--  * pivot offset is now properly handled (but not pivot rotation)
-- 1.2.2
--  * added export "Selection Only" option
--  * added several warnings
--  * fixed crash on hidden submaterials
--  * fixed several stability issues related to materials
--  * only materials of exported meshes are written to file
--  * non standard materials are now ignored
--  * disabled (unchecked) material maps are no longer exported
--  * cleaned up code and added comments

-- To do:
--  * create flipped triangles copies for twosided materials (optional)
--  * export mirrored objects correctly

-- clean up
clearlistener()

-- options
global opt_scalefix = false

-- material redundancy list
global matlist = #()
global matlistnum = 0

-- warnings
global warn_notobj = false
global warn_mirror = false
global warn_twoside = false

-- write material
fn WriteMaterial mat =
(
 -- check if material is already exported
 for i=1 to matlistnum do
 (
  if matlist[i] == mat do return false
 )

 -- write material
 format "\nmaterial \"%\"\n{\n" mat.name
 if (classOf(mat.diffusemap) == BitmapTexture) AND (mat.diffusemapenable == true) do
 (
  format " colormap = \"%\"\n" mat.diffusemap.filename
 )
 if (classOf(mat.opacitymap) == BitmapTexture) AND (mat.opacitymapenable == true) do
 (
  format " opacitymap = \"%\"\n" mat.opacitymap.filename
 )
 format "}\n"
 
 -- add to redundancy list
 matlistnum = matlistnum+1
 matlist[matlistnum] = mat
 
 -- warnings
 if mat.twosided do warn_twoside = true
)

-- write bones
fn WriteBoneChildren obj =
(
 local i
 if obj.children.count > 0 do
 (
  for i=1 to obj.children.count do
  (
   format " j = \"%\"" obj.children[i].name
   format ",(%,%,%)" obj.children[i].pos.x obj.children[i].pos.y obj.children[i].pos.z
   format ",(-90,-90,-90),(90,90,90),\"%\"\n" obj.name
   WriteBoneChildren obj.children[i]
  )
 )
)

-- write bonesystem
fn WriteBonesys obj =
(
 if obj.parent == undefined do
 (
  format "\nbonesys \"%\"\n{\n" obj.name
  format " r = \"%\",(%,%,%)\n" obj.name obj.pos.x obj.pos.y obj.pos.z
  WriteBoneChildren obj
  format "}\n"
 )
)


-- adds float3 to list
fn addToList list v =
(
 if (v == undefined) do return list.count --bugfix
 
 for i=1 to list.count do
 (
  if list[i].x == v.x do (
   if list[i].y == v.y do (
    if list[i].z == v.z do (
     return i
    )
   )
  )
 )
 append list v
 return list.count
)


-- write mesh
fn WriteMesh obj =
(
 local op = obj.objectoffsetpos
 local os = obj.scale
 
 -- write mesh materials
 case classof(obj.mat) of
 (
  UndefinedClass:()
  StandardMaterial:
  (
   WriteMaterial obj.mat
  )
  MultiMaterial:
  (
   for i=1 to obj.mat.numsubs do
   (
    if classof(obj.mat[i]) == StandardMaterial do
    (
     WriteMaterial obj.mat[i]
    )
   )
  )
 )
 
 local isskin = false
 local boneVerts = #()
 local i
 local k
 if classof(obj.modifiers[1]) == Skin then
 (
  isskin = true
  local myskin = obj.modifiers[1]
  
  -- skin stuff only works if the modifer panel is open and mesh is selected
  max modify mode
  select obj
  
  -- collect up bone indicies for each vertex
  for i=1 to skinOps.getNumberVertices myskin do
  (
   local maxb = 0 -- best bone so far
   local maxw = 0.0 -- best weight so far
   -- Trespasser only supports singly weighted verticies, so choose bone with greatest influence on vertex
   for k=1 to (skinops.getVertexWeightCount myskin i) do
   (
    if (skinops.getVertexWeight myskin i k) > maxw then
    (
     maxw = (skinops.getVertexWeight myskin i k)
     maxb = (skinops.getVertexWeightBoneID myskin i k)
    )
    append boneVerts maxb -- TODO: should be error if not attached to any bone?
   )
  )
  format "\nskin \"%\"\n{\n" obj.name
 ) else (
  format "\nmesh \"%\"\n{\n" obj.name
 )
 
 -- standard material
 case classof(obj.mat) of
 (
  StandardMaterial:
  (
   format " m = \"%\"\n" obj.mat.name
  )
  MultiMaterial:
  (
   for i=1 to obj.mat.numsubs do
   (
    if classof(obj.mat[i]) == StandardMaterial then
    (
     format " m = \"%\"\n" obj.mat[i].name
    ) else (
     format " m = \"dummy\"\n"
    )
   )
  )
 )
 
 -- write vertices
 local v
 for i=1 to obj.numverts do
 (
  in coordsys local v = (getvert obj i)
  
  if opt_scalefix do
  (
   v = (v + op) * os
  )
  
  if isskin == true then
  (
   format " v = (%,%,%),%\n" v.x v.y v.z (boneVerts[i]-1) -- write extra bone index
  ) else (
   format " v = (%,%,%)\n" v.x v.y v.z
  )
 )
 
 -- write texcoords
 local t
 if obj.numtverts != 0 then
 (
  for i=1 to obj.numtverts do
  (
   t = (gettvert obj i)
   format " t = (%,%)\n" t.x t.y
  )
 ) else (
  format " t = (0,0)\n"
 )
 
 -- write normals
 local normlist = #()
 local fnlist = #()
 for i=1 to obj.numfaces do
 (
  if (getfacesmoothgroup obj i) == 0 then
  (
   in coordsys local frn = getfacenormal obj i
   n1 = addToList normlist frn
   n2 = n1
   n3 = n1
  ) else (
   in coordsys local frn = (meshop.getfacernormals obj i)
   
   -- start bug workaround: sometimes frn does not have three elements in 3dsmax 4 (mxs bug)
   if frn.count != 3 do 
   (
    in coordsys local frn[1] = getfacenormal obj i
	frn[2] = frn[1]
	frn[3] = frn[1]
   )
   -- end bug workaround
   
   n1 = addToList normlist frn[1]
   n2 = addToList normlist frn[2]
   n3 = addToList normlist frn[3] 
  )
  append fnlist #(n1,n2,n3)
 )
 for i=1 to normlist.count do
 (
  format " n = (%,%,%)\n" normlist[i].x normlist[i].y normlist[i].z
 )
 normlist = #()
 
 -- write faces
 for i=1 to obj.numfaces do
 (
 
  -- face vertex pointers
  v = (getface obj i)
  if obj.numtverts != 0 do
  (
   t = (gettvface obj i)
  )
  n = (getface obj i)
  f = (getfacematid obj i)
  format " f = (%,%,%)" (v.x as integer) (v.y as integer) (v.z as integer)
  
  -- face texcoord indices
  if obj.numtverts == 0 then
  (
   -- no texcoords, so lets point texcoord indices to this dummy coord
   format ",(1,1,1)"
  ) else (
   format ",(%,%,%)" (t.x as integer) (t.y as integer) (t.z as integer)
  )
  
  -- face normal indices
  format ",(%,%,%)" (fnlist[i][1] as integer) (fnlist[i][2] as integer) (fnlist[i][3] as integer)
  
  -- material indices
  case classof(obj.material) of
  (
   UndefinedClass:
   (
    -- no material on mesh
    format ",0\n"
   )
   StandardMaterial:
   (
    -- single material for entire mesh
    format ",1\n"
   )
   MultiMaterial:
   (
    -- submaterials, per face
    format ",%\n" (getfacematid obj i as integer)
   )
  )
 )
 
 -- clean up
 fnlist = #()
 
 -- end of mesh chunk
 format "}\n"
)

-- write instance
fn WriteInstance obj =
(
 format "\ninstance \"%\"\n{\n" obj.name
 
 -- mesh binding
 format " mesh = \"%\"\n" obj.name
 
 -- position
 format " position = (%,%,%)\n" obj.pos.x obj.pos.y obj.pos.z
 
 -- rotation
-- local ea = quatToEuler obj.rotation order:1 
 local eax = obj.rotation.x_rotation
 local eay = obj.rotation.y_rotation
 local eaz = obj.rotation.z_rotation
 -- TODO: check which order is correct
 -- euler angles seem to be -ve what they should be, probably stuffing up the rotation order too, should check
-- format " rotation = (%,%,%)\n" ea.x ea.y ea.z
 format " rotation = (%,%,%)\n" eax eay eaz
 
 -- scale
 if opt_scalefix then
 (
  format " scale = 1\n"
 ) else (
  format " scale = %\n" obj.scale.x
 )
 
 -- end of instance chunk
 format "}\n"
)

utility TpmExp "TPM Exporter"
(
 group "About"
 (
  label lab1 "TPM Exporter"
  label lab2 "Version 1.2.4y"
  label lab3 "by Martijn Buijs, Andres James"
  label lab4 "Modified by M.A.Ch.F."
  label lab5 "Copyright © TresCom, 2008"
 )
 group "Options"
 (
  checkbox chkScaleFix "Fix Scale" checked: false
 )
 group "Export"
 (
  checkbox chkSelected "Selection Only" checked: false
  checkbox chkSkipHidden "Skip Hidden Objects" checked: true
  checkbox chkSkipFrozen "Skip Frozen Objects" checked: true
  button cmdExport "Export Scene..." width: 140
 )
 on cmdExport pressed do
 (
  local j
  local b
  
  -- options
  opt_scalefix = chkScaleFix.checked
  
  -- reset material redundancy list
  matlist = #()
  matlistnum = 0
  
  -- reset warning flags
  warn_notobj = false
  warn_mirror = false
  warn_twoside = false
  
  -- print file header
  format "// Trespasser Model File (.tpm)\n"
  format "\nfileinfo\n{\n"
  format " formatversion = 1.0.1\n"
  format " name = \"%\"\n" maxFileName
  format " version = 1.2.2\n"
  format " source = \"%\"\n" maxFileName
  format " date = %\n" localTime
  format " comments = \"\"\n"
  format "}\n"
   
  -- write objects
  local obj
  for j=1 to $objects.count do
  (
   obj = $objects[j]
  
   -- skip hidden
   if chkSkipHidden.checked == true do
   (
    if obj.ishidden do continue
   )
   
   -- skip frozen
   if chkSkipFrozen.checked == true do
   (
    if obj.isFrozen do continue
   )
   
   -- skip unselected
   if chkSelected.checked == true do
   (
    if not obj.isSelected do continue
   )
   
   -- write data block
   case classof(obj) of
   (
    
    -- print bonesys (max 2.5)
    Bone:
    (
     WriteBonesys obj
    )
   
    -- write bonesys (max 3.0 and up)
    BoneGeometry:
    (
     format "\nbone \"%\"\n{\n" obj.name
     format " position = (%,%,%)\n" obj.pos.x obj.pos.y obj.pos.z
     local userProps = getuserpropbuffer obj
     if userProps != undefined AND userProps != "" do
     (
      format "%" userProps
     )
     format"}\n"
    )
    
    -- write mesh
    Editable_mesh:
    (
     WriteMesh obj
     WriteInstance obj
    )
    
    -- silently ignore
    OmniLight:()
    FreeSpot:()
    TargetSpot:()
    DirectionalLight:()
    TargetDirectionalLight:()
     
    -- other objects
    default:
    (
     warn_notobj = true
     messagebox obj.name
    )
    
   )
   
   -- warnings
   if obj.scale.x < 0 do warn_mirror = true
   if obj.scale.y < 0 do warn_mirror = true
   if obj.scale.z < 0 do warn_mirror = true
   
  )
  
  -- clean up material redundancy list
  matlist = #()
  matlistnum = 0
  
  -- warnings
  local errstr = ""
  if warn_notobj do  errstr = errstr + "* not all scene objects could be exported\n"
  if warn_mirror do  errstr = errstr + "* some objects are mirrored, this may lead to object orientation problems\n"
  if warn_twoside do errstr = errstr + "* some materials are two sided, these are not preserved\n"
  if errstr.count > 0 do messagebox ("Warning:\n" + errstr)
   
  -- success confirmation
  messagebox "Scene exported successfully."
  
 )
)



-- END OF FILE


Again, copy and paste the code to a text file, and save it as "tpmexp124y-gmax.ms".

This works as the old exporter, it generates output to the listener, you then need to copy/paste to an empty text file and save as .tpm.
Last edited by machf on Thu Jan 10, 2008 3:44 pm, edited 2 times in total.
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
Draconisaurus
T-Rex Killer
T-Rex Killer
Posts: 14046
Joined: Mon Dec 06, 2004 5:21 pm
Antispam: No
Location: Isla Sorna
Contact:

Post by Draconisaurus »

Hmmm, nice. I'll report any funky behavior if I see it.
Slugger
-=TresCom Developer=-
-=TresCom Developer=-
Posts: 4720
Joined: Sat Jun 12, 2004 6:52 pm
Antispam: No
Location: Atlanta

Post by Slugger »

Nice work, machf. Can use the Gmax one...but how do I use it?
0066521C: 'Cannot create local swap file - Is Trespasser installed??',0Ah,0
"Cold lino was the driving force behind world power!"
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Post by machf »

Just like the old one... when you hit "Export", it will send the output to the Maxscript Listener window. Gmax will only allow you to copy/paste 10K at a time, but you can overcome that limitation with a small app called GMaxSLGRAB, which will allow you to save the contents of the Listener directly to a file.

If you mean you don't know how to load a MaxScript... well, place it into the "scripts" folder (inside the "startup" sub-folder so that it loads automatically, better), then you click on the "Utilities" tab (little hammer) on the right-hand panel, click on "Maxscript" and select the TPM Exporter from the "Utilities" list box (if it's not there, because you didn't place it in the "Startup" sub-folder to load automatically, click on "Run Script", and open the maxscript file, that will add it to the list box).
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Post by machf »

Just made another quick fix on the export scripts (hence the change from 1.2.4x to 1.2.4y), there was a misplaced line that caused a very annoying error wihen exporting rigged meshes, you'd get as many

Code: Select all


skin "(mesh name here)"
{
lines as vertices the mesh had, instead of a single line at the start of the mesh... now it's working OK, the corresponding line had to be moved down by a line (it was incorrectly nested inside a loop).

Can someone make this thread a sticky?
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by machf »

Looking at the .TPM import maxscript, I've realized that normals info isn't processed when reading the file (it's just skipped), that probably being the reason why after makig changes to some meshes in MAX/Gmax and exporting them back for re-import into a level using GeomAdd, they don't look as they should anymore...

I'm going to see what I can do to fix that, but I can't promise anything yet...
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
TheIdiot
T-Rex
T-Rex
Posts: 4345
Joined: Thu Feb 20, 2014 9:13 pm
Location: Canada, eh?

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by TheIdiot »

Thanks for looking into that Import script, machf. The normals thing is the main reason why importing TPMs into Max isn't a great idea at the moment.

EDIT: Ah, and I stickied the thread for you as well. :)
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by machf »

TheIdiot wrote:Thanks for looking into that Import script, machf. The normals thing is the main reason why importing TPMs into Max isn't a great idea at the moment.

EDIT: Ah, and I stickied the thread for you as well. :)
You realize that was something I asked 10 years ago?
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
TheIdiot
T-Rex
T-Rex
Posts: 4345
Joined: Thu Feb 20, 2014 9:13 pm
Location: Canada, eh?

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by TheIdiot »

You realize that was something I asked 10 years ago?
:| Didn't check the time on that post...haha. At least it finally got stickied. If you're looking into updating the scripts, I think it's worth keeping stickied for now.
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by machf »

TheIdiot wrote:
You realize that was something I asked 10 years ago?
:| Didn't check the time on that post...haha. At least it finally got stickied.
It must be a record... ;)
If you're looking into updating the scripts, I think it's worth keeping stickied for now.
Unfortunately, I made some tests, and it's a nightmare... it looks like the way the normals are being exported in the TPM script, there's no 1:1 match with the number of faces in the mesh. So, reading them back with the TPM import script is giving occasional errors. I don't know if the same happens with the TPM files exported from within TresEd...
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
Draconisaurus
T-Rex Killer
T-Rex Killer
Posts: 14046
Joined: Mon Dec 06, 2004 5:21 pm
Antispam: No
Location: Isla Sorna
Contact:

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by Draconisaurus »

Be sure to experiment using something simple like a crate...
User avatar
machf
T-Rex Killer
T-Rex Killer
Posts: 12368
Joined: Thu Apr 24, 2003 11:20 pm
Location: Lima, Peru
Contact:

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by machf »

That was the first thing I used, and even then...

I need to inspect the export script in more detail.

EDIT: Oh, crap. It looks like the exporter isn't storing face normals proper, but vertex normals for each of the three vertices in each face instead. No wonder the counts don't match. And I foresee that trying to restore them to their original settings is going to be a nightmare...

EDIT2: while the TPM export script is storing vertex normals, TresEd appears to export proper face normals instead (or whatever they are). So, I'll rewrite the export scripts to write face normals too, and update their formatversion value from 1.0.1 to 1.0.2 to match TresEd's... that will also solve the problems with the TPM import script.
Visit The Carnivores Saga - a forum devoted to modding Action Forms' Carnivores, Carnivores 2 and Carnivores: Ice Age games
Tres WIP: updated T-Script Reference and File Formats documents
Sound name listings for the Demo (build 117), Retail (build 116), Beta 103, Beta 99, Beta 97, Beta 96, Build 55, PC Gamer Alpha (build 32) and E3 1998 Alpha (build 22) TPA files
User avatar
TheIdiot
T-Rex
T-Rex
Posts: 4345
Joined: Thu Feb 20, 2014 9:13 pm
Location: Canada, eh?

Re: Fixed TPM import and export maxscripts (version 02 and 1

Post by TheIdiot »

Also, forgot to bring this up: machf, there seems to be a problem with the import script which causes all verticies to break, resulting in each face becoming a separate element of the mesh. This can easily be fixed by selecting all vertices and welding them back together, but then the smoothing groups are all completely destroyed. I think this might be part of the normals error you're working on fixing.
Post Reply