- Fixed a small bug.

- Fixed a small bug.

git-svn-id: 28d9401aa571d5108e51b194aae6f24ca5964c06@29094 8cc4aa7f-3514-0410-904f-f2cc9021211c

------------------------------------------------------------
-- Author: Luca Pancallo <pancallo@netscape.net>
--
-- Copyright (C) 2007 Atomic Blue (info@planeshift.it,
-- http://www.atomicblue.org , http://www.planeshift.it)
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation (version 2 of the License)
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
--
------------------------------------------------------------
-- Version 01

macroScript Export_Sprite_CS
category:"PlaneShift"
internalcategory:"PlaneShift"
ButtonText:"Export Sprite to CS"
tooltip:"Export Sprite to CS" Icon:#("Maxscript",1)
(

rollout Test1 "Export Sprite" width:238 height:128
(
	edittext edt3 "" pos:[17,32] width:192 height:21
	label lbl1 "Export Sprite To:" pos:[21,7] width:142 height:20
	button btn2 "Export!" pos:[39,72] width:152 height:24

		-- parameters for scaling and relocation
		global xscale = 1.0
		global yscale = 1.0
		global zscale = 1.0

		global xrelocate = 0
		global yrelocate = 0
		global zrelocate = 0

		fn OutputGenMeshFactory obj outFile debug auto =
        (
			factoryName = obj.name

			-------------------
			-- support for LOD.
			-- it has to check all objects listed and export each as a nested meshfact
			-------------------
			lodlow = getUserProp obj "LODLOW"
			if (lodlow!=undefined) then (
				format "FOUND LOD OBJECT: %" factoryName

  					-- search low detail obj
				lodobjects = #()
				if (lodlow=="NULL") then
					append lodobjects "null"
				else
					append lodobjects (getNodeByName lodlow)

  					-- search med detail obj
				lodmed = getUserProp obj "LODMED"
				if (lodmed=="NULL") then
					append lodobjects "null"
				else
					append lodobjects (getNodeByName lodmed)

  					-- search high detail obj
				append lodobjects obj

			-------------------------
			-- no LOD for this object
			-------------------------
			) else (
				lodobjects = #()
				append lodobjects obj
			)

  					-- export low, med and high version
			if (lodobjects.count!=1) then
			(
				format "<meshfact name=\"%\">\n" factoryName to:outFile
				-- get proper nullmesh bbox size
				rmin = [-1,-1,-1]
				rmax = [1,1,1]
				for k=1 to lodobjects.count do
				(
					if (lodobjects[k]!="null") then
					(
						tempmin = lodobjects[k].min - lodobjects[k].center
						tempmax = lodobjects[k].max - lodobjects[k].center
						if (tempmin.x<rmin.x) then rmin.x=tempmin.x
						if (tempmin.y<rmin.y) then rmin.y=tempmin.y
						if (tempmin.z<rmin.z) then rmin.z=tempmin.z
						if (tempmax.x>rmax.x) then rmax.x=tempmax.x
						if (tempmax.y>rmax.y) then rmax.y=tempmax.y
						if (tempmax.z>rmax.z) then rmax.z=tempmax.z
					)
				)
				rmin = (rmin * xscale) + xrelocate
				rmax = (rmax * xscale) + xrelocate
				format "<nullmesh><min x=\"%\" y=\"%\" z=\"%\" /><max x=\"%\" y=\"%\" z=\"%\" /></nullmesh>\n" rmin.x rmin.z rmin.y rmax.x rmax.z rmax.y to:outFile
				format "<staticlod><distance varm=\"LodM\" vara=\"LodA\" /></staticlod>\n" to:outFile
			)

			for k=1 to lodobjects.count do
			(

				--check simple colldet setting
				colldet = getUserProp obj "COLLDET"

		   		-- output nullmesh
				if (lodobjects[k]=="null") then
				(
					format "  <meshfact name=\"%_%\">\n" factoryName (k-1) to:outFile
					format "  <lodlevel>%</lodlevel>\n" (k-1) to:outFile
					format "  <nullmesh><min x=\"-0.1\" y=\"-0.1\" z=\"-0.1\" /><max x=\"0.1\" y=\"0.1\" z=\"0.1\" /></nullmesh>\n" to:outFile
					format "  </meshfact>\n\n" to:outFile
					continue;
				)

				obj = lodobjects[k]

				-- output normalmeshfact
				-- meshfact name changes for hierarchy
				if (lodlow!=undefined) then
					format "  <meshfact name=\"%_%\">\n" factoryName (k-1) to:outFile
				else
					format "  <meshfact name=\"%\">\n" factoryName to:outFile

				if (lodobjects.count!=1) then
					format "<lodlevel>%</lodlevel>\n" (k-1) to:outFile
				format "  <plugin>crystalspace.mesh.loader.factory.genmesh</plugin><params><numvt>%</numvt>\n" (getNumTVerts obj) to:outFile

				-- just for LOD hierarchical objects material must be speficied in the factory
				if (lodlow!=undefined) then (
					m = obj.mat;
					if ((classOf m)==Multimaterial) then (
						matUsed = getFaceMatID obj 1
						m = obj.mat[matUsed];
					)
					format "      <material>%</material>\n" (getMatFilename m) to:outFile
				)

				-- check texture
				if (getNumTVerts obj==0) then
				(
					message = "Export aborted: No UV maps assigned to genmesh object: " + factoryName
					messageBox message
					close outFile
					return 1
				)

				-- checks if model has left-oriented system or not
				face = getface obj 1
				v1= getvert obj face[1]
				v2 = getvert obj face[2]
				v3 = getvert obj face[3]

				vect1 = v1-v2
				vect2 = v3-v2
				normal1 = cross vect1 vect2
				facenorm = normal1/(length normal1)
				maxnorm = getfacenormal obj 1
				flipModel = false

				dotProd = dot facenorm maxnorm
				if (dotProd>0) then (
					flipModel = true
				)

			   if (flipModel) then (
			    format "\n GenMesh Factory Object needs flipping: %\n" factoryName
			   )

				vertTInfo = #(getNumTVerts obj)
				vertTInfo[1] = undefined
				normalsVert = #()

				isSky = false
				if (findString obj.name "_sky_" !=undefined) then
				 isSky = true

				-- cycle on all Faces of the object to get Tverts x,y,z positions
				for i=1 to obj.numfaces do
				(
					-- get face
					Tface = getTVFace obj i
					face = getFace obj i

					-- check smooth group of the face
					smoothgroup = getFaceSmoothGroup obj i

					-- get its 3 vertices
					for h=1 to 3 do (
				    	curVert=getVert obj face[h]
						if (curVert==undefined) then
							format "\n\nUNDEF: %\n\n" Tface[h]
						if (debug) then
							format " face: % curVert %: %\n" i Tface[h] curVert

						-- if the value is different we have a problem on Welded UV
						if (vertTInfo[Tface[h]]!=undefined and vertTInfo[Tface[h]]!=curVert) then (
							message = "PROBLEM on object " + factoryName + ".\n UV should not be welded on vertex " + (Tface[h] as String)
							messageBox message
							close outFile
							return 1
						)
						vertTInfo[Tface[h]]=curVert

						-- get normal for sky (TODO: double check, seems not right)
						if (isSky) then (
							normalsVert[Tface[h]]=getNormal obj face[h]
						-- get normal in case of smoothing groups
                        ) else if (smoothgroup!=0) then (
							-- get average normal
							faces = meshop.getFacesUsingVert obj face[h] as array
							normal = [0,0,0]
							facescount = 0
							for j in faces do (
							    if (getFaceSmoothGroup obj j==smoothgroup) then
									normal += (getFaceNormal obj j)
									facescount+=1
							)
							normal = normal/facescount
							normalsVert[Tface[h]]=normal
						-- get normal in case no smooth group present
						) else (
							--normalsVert[Tface[h]]=getNormal obj face[h]
							normal = meshop.getFaceRNormals obj i
							normalsVert[Tface[h]]=normal[1]
						)
					)
				)

				-- cycle on all TVerts of the object
				for i =1 to (getNumTVerts obj) do
				(
					-- get its 3 vertices as a point3
					-- export in XZY format
				    vert=vertTInfo[i]
					if (vert==undefined) then (
						message = "PROBLEM on object " + factoryName + ": UV mapping seems to be messed up. Please UnWrap it then collapse it.";
						messageBox message
						close outFile
						return 1
					)
					xvert = (vert.x * xscale) + xrelocate
					yvert = (vert.y * yscale) + yrelocate
					zvert = (vert.z * zscale) + zrelocate

					Tvert = getTVert obj i

					-- if it's an autogenerated genmesh then relocate to 0,0,0
					if (auto==1) then (
						xvert = xvert - obj.pos.x
						yvert = yvert - obj.pos.y
						zvert = zvert - obj.pos.z
					)

					format "      <v x=\"%\" y=\"%\" z=\"%\" u=\"%\" v=\"%\" /> \n" xvert zvert yvert Tvert[1] (1-Tvert[2]) i to:outFile
				)

				-- write all normals
				for i =1 to (getNumTVerts obj) do
				(
					Tvert = getTVert obj i
					normalvert = normalsVert[i]
					normalvert = normalize(normalvert)
					format "      <n x=\"%\" y=\"%\" z=\"%\" /> \n" normalvert.x normalvert.z normalvert.y to:outFile
				)

				-- cycle on all faces of object and split by material
				facesmaterial=#()
				facesmaterialfaces=#()
                -- if standard material, then 1 submesh only
				if ((classOf obj.mat)==Standardmaterial) then (
				    append facesmaterial (getMatFilename (obj.mat))
					facesmaterialfaces[1]=#()
					for i =1 to obj.numFaces do
					(
						append facesmaterialfaces[1] i
					)
				) else (
					for i =1 to obj.numFaces do
					(
					    textid = getFaceMatID obj i
						if (textid > obj.mat.count) then (
						  format "ERROR!!! Object % uses more material ID than the materials defined. \n" obj.name
						)
						--format "% % \n" i textid
						m = obj.mat[textid]
	   					mname = getMatFilename(m)
						if (findItem facesmaterial mname==0) then (
							append facesmaterial mname
						)
						pos = findItem facesmaterial mname
						if (facesmaterialfaces[pos]==undefined) then
						   facesmaterialfaces[pos]=#()
					    append facesmaterialfaces[pos] i
					)
				)
				format "\n facesmaterial: % \n" facesmaterial
				format "\n facesmaterialid: % \n" facesmaterialfaces

				-- write one submesh for each material
				for i =1 to facesmaterial.count do
				(
					mname = facesmaterial[i];

					format "    <submesh name=\"%\">\n" ("submesh"+i as String) to:outFile
                    format "    <material>%</material>\n" mname to:outFile
                    format "    <indexbuffer components=\"1\" type=\"uint\" indices=\"yes\">\n" to:outFile

                    -- cycle on all faces using same material
                    for j=1 to facesmaterialfaces[i].count do
					(
						currentfaceset = facesmaterialfaces[i]
						faceVerts=getTVface obj currentfaceset[j]
						a = (faceVerts[1]-1) as Integer

						if (flipModel) then (
							b = (faceVerts[2]-1) as Integer
							c = (faceVerts[3]-1) as Integer
						) else (
							b = (faceVerts[3]-1) as Integer
							c = (faceVerts[2]-1) as Integer
						)

						-- exclude collision detection on low lod versions
						if (k!=lodobjects.count) then (
							format "    <e c0=\"%\" /><e c0=\"%\" /><e c0=\"%\" />\n" a b c to:outFile
							--if (colldet=="no") then format "<colldet>no</colldet>" to:outFile
						) else (
							--if (colldet=="no") then format "<t v1=\"%\" v2=\"%\" v3=\"%\"><colldet>no</colldet></t>"  a b c to:outFile
							format "    <e c0=\"%\" /><e c0=\"%\" /><e c0=\"%\" />\n" a b c to:outFile
						)
					)
					format "    </indexbuffer></submesh>\n" to:outFile
			    )

				-- check for smooth setting
				-- temporary disabled
				--smooth = getUserProp obj "SMOOTH"
				--if (smooth=="yes") then
				--	format "      <autonormals/>\n" to:outFile

				format "    </params>\n" to:outFile

				-- check for no lighting setting
				lighting = getUserProp obj "LIGHTING"

				--check simple colldet setting
				colldet = getUserProp obj "COLLDET"

				-- check for viscull setting
				viscull = getUserProp obj "VISCULL"

				-- check for culleronly setting
				culleronly = getUserProp obj "CULLERONLY"

				-- check player barrier setting
				playerbarrier = getUserProp obj "PLAYERBARRIER"

                occluder = false
				-- check for culleronly setting
				culleronly = getUserProp obj "CULLERONLY"

				-- check player barrier setting
				playerbarrier = getUserProp obj "PLAYERBARRIER"

			    -- output name of object and some info
				if (findString obj.name "_occ_" !=undefined) then (
					occluder = true
				)

				istrasparent=false
				-- check if object is a range alpha trasparent
				rangetrasp = getUserProp obj "RANGETRASP"
				if (rangetrasp=="yes") then (
				  istrasparent=true
				)

				-- check if object is a binary alpha trasparent
				trasp = getUserProp obj "TRASPARENT"
				if (trasp=="yes") then (
				  istrasparent=true
				)

				-- handles transparent objects
				if (istrasparent) then (
				  format "      <priority>alpha</priority>\n" to:outFile
				  format "      <ztest />\n" to:outFile
				)
			    -- handles sky objects
				else if (findString obj.name "_sky_" !=undefined) then (
				  format "      <priority>sky</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)
			    -- handles zfill objects
				else if (findString obj.name "_s_" !=undefined) then (
				  format "      <priority>object</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)
				else if (culleronly=="yes" or playerbarrier=="yes" or (occluder and (classOf obj)!=Box)) then (
					format "      <mesh>\n" to:outFile
				) else if (occluder and (classOf obj)==Box) then (
					format "      <box>\n" to:outFile
				) else (
				  format "      <priority>object</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)

				-- check for no shadow setting
				noshadows = getUserProp obj "NOSHADOWS"
				if (noshadows=="yes") then
					format "      <noshadows />\n" to:outFile

				if (colldet=="no") then format "<trimesh><id>colldet</id></trimesh>\n" to:outFile

				-- check for no shadow setting
				-- NO MORE WORKING??
				noshadows = getUserProp obj "NOSHADOWS"
				if (noshadows=="yes") then
					format "      <noshadows />\n" to:outFile

				-- check if object is a range alpha trasparent
				rangetrasp = getUserProp obj "RANGETRASP"
				if (rangetrasp=="yes") then (
				  format "      <ztest/><priority>alpha</priority>\n" to:outFile
				)

				-- check if object uses a binary alpha texture
			    if ((classOf obj.mat)==Standardmaterial) then (
					if (obj.mat.mapEnables[7]) then (
					  format "      <trimesh><id>viscull</id></trimesh>\n" to:outFile
					  format "      <trimesh><default /><id>colldet</id></trimesh>\n" to:outFile
					)
				) else (
					if (obj.mat[1].mapEnables[7]) then (
					  format "      <trimesh><id>viscull</id></trimesh>\n" to:outFile
					  format "      <trimesh><default /><id>colldet</id></trimesh>\n" to:outFile
					)
				)

				format "    </meshfact>\n" to:outFile

			) -- end for each lodobject

			if (lodobjects.count!=1) then
				format "  </meshfact>\n" to:outFile

        )

	on Test1 open do
	(
	   if(selection[1]!=undefined) then
	   (
	     name = selection[1].name
	     edt3.text = "d:\\Luca\\"+name+".spr"
	   )

	)
	on btn2 pressed do
	(

		-- ////////////////////////
		-- Variables used in the program
		-- ////////////////////////

		-- get filename
		filename = edt3.text

		-- output file
		outFile = createFile filename

		-- set debug output
		debug=false

		-- Define verbose output (that takes more space and memory)
		verboseMode = true

		-- functions declaration
		global tokenize
		global OutputGenMeshFactory
		global getMatFilename
		global lowercase

		-- Tokenize utility function
		fn tokenize instring sep =
		(
		   outarray = #()
		   temp=copy instring
		   i = 1
		   while (true) do (
		   	index = findstring temp sep
			if (index==undefined) then
			(
				outarray[i]=temp
				exit
			) else (
				outarray[i] = substring temp 1 (index-1)
				temp = substring temp (index+1) -1
			)
			i = i +1
		   )
		   outarray
		)

		-- get filename from a material
		fn getMatFilename m =
		(
		    if (m==undefined) then
				image="MATERIALNOTDEFINED"
			else (
			    mat = m.maps[2]
				if (mat!=undefined) then
				(
					image = mat.filename
					indx = tokenize image "\\"
					image = indx[indx.count]
				) else
					image="MATERIALNOTDEFINED"

				image = lowercase(image)
			)
		)

		-- LowerCase utility function
		fn lowercase instring =
		(
		   local upper, lower, outstring
		   upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		   lower="abcdefghijklmnopqrstuvwxyz"

		   outstring=copy instring

		   for i=1 to outstring.count do
		   (  j=findString upper outstring[i]
		      if (j != undefined) do outstring[i]=lower[j]
		   )

		   outstring
		)

		-- ////////////////////////
		-- Main: program starts here
		-- ////////////////////////

			-- identify main sprite object
			obj=selection[1]
			objectname = obj.name

		    -- output name of object and some info
			format "\n\nFound Object Name: % Faces: %\n" objectname obj.numfaces

	    OutputGenMeshFactory obj outFile debug 1

		close outFile
		message = "ALL DONE!"

		messageBox message

	)
)
gw = newRolloutFloater "Export Sprite" 300 410
addRollout Test1 gw

)

---------------------------------------------------------------------------------------
--  Documentation
--
--
-- Faces that need UV Unwield:
-- This means that some UV coords are shared on multiple vertexes
-- Go in the UVUnwrap function and Unweld all the vertexes of the face found
-------------------

------------------------------------------------------------
-- Author: Luca Pancallo <pancallo@netscape.net>
--
-- Copyright (C) 2007 Atomic Blue (info@planeshift.it,
-- http://www.atomicblue.org , http://www.planeshift.it)
--
-- This program is free software; you can redistribute it and/or
-- modify it under the terms of the GNU General Public License
-- as published by the Free Software Foundation (version 2 of the License)
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
--
------------------------------------------------------------
-- Version 01

macroScript Export_Sprite_CS
category:"PlaneShift"
internalcategory:"PlaneShift"
ButtonText:"Export Sprite CS"
tooltip:"Export Sprite CS" Icon:#("Maxscript",1)
(

rollout Test1 "Export Sprite" width:238 height:128
(
	edittext edt3 "" pos:[17,32] width:192 height:21
	label lbl1 "Export Sprite To:" pos:[21,7] width:142 height:20
	button btn2 "Export!" pos:[39,72] width:152 height:24

		-- parameters for scaling and relocation
		global xscale = 1.0
		global yscale = 1.0
		global zscale = 1.0

		global xrelocate = 0
		global yrelocate = 0
		global zrelocate = 0

		fn OutputGenMeshFactory obj outFile debug auto =
        (
			factoryName = obj.name

			-------------------
			-- support for LOD.
			-- it has to check all objects listed and export each as a nested meshfact
			-------------------
			lodlow = getUserProp obj "LODLOW"
			if (lodlow!=undefined) then (
				format "FOUND LOD OBJECT: %" factoryName

  					-- search low detail obj
				lodobjects = #()
				if (lodlow=="NULL") then
					append lodobjects "null"
				else
					append lodobjects (getNodeByName lodlow)

  					-- search med detail obj
				lodmed = getUserProp obj "LODMED"
				if (lodmed=="NULL") then
					append lodobjects "null"
				else
					append lodobjects (getNodeByName lodmed)

  					-- search high detail obj
				append lodobjects obj

			-------------------------
			-- no LOD for this object
			-------------------------
			) else (
				lodobjects = #()
				append lodobjects obj
			)

  					-- export low, med and high version
			if (lodobjects.count!=1) then
			(
				format "<meshfact name=\"%\">\n" factoryName to:outFile
				-- get proper nullmesh bbox size
				rmin = [-1,-1,-1]
				rmax = [1,1,1]
				for k=1 to lodobjects.count do
				(
					if (lodobjects[k]!="null") then
					(
						tempmin = lodobjects[k].min - lodobjects[k].center
						tempmax = lodobjects[k].max - lodobjects[k].center
						if (tempmin.x<rmin.x) then rmin.x=tempmin.x
						if (tempmin.y<rmin.y) then rmin.y=tempmin.y
						if (tempmin.z<rmin.z) then rmin.z=tempmin.z
						if (tempmax.x>rmax.x) then rmax.x=tempmax.x
						if (tempmax.y>rmax.y) then rmax.y=tempmax.y
						if (tempmax.z>rmax.z) then rmax.z=tempmax.z
					)
				)
				rmin = (rmin * xscale) + xrelocate
				rmax = (rmax * xscale) + xrelocate
				format "<nullmesh><min x=\"%\" y=\"%\" z=\"%\" /><max x=\"%\" y=\"%\" z=\"%\" /></nullmesh>\n" rmin.x rmin.z rmin.y rmax.x rmax.z rmax.y to:outFile
				format "<staticlod><distance varm=\"LodM\" vara=\"LodA\" /></staticlod>\n" to:outFile
			)

			for k=1 to lodobjects.count do
			(

				--check simple colldet setting
				colldet = getUserProp obj "COLLDET"

		   		-- output nullmesh
				if (lodobjects[k]=="null") then
				(
					format "  <meshfact name=\"%_%\">\n" factoryName (k-1) to:outFile
					format "  <lodlevel>%</lodlevel>\n" (k-1) to:outFile
					format "  <nullmesh><min x=\"-0.1\" y=\"-0.1\" z=\"-0.1\" /><max x=\"0.1\" y=\"0.1\" z=\"0.1\" /></nullmesh>\n" to:outFile
					format "  </meshfact>\n\n" to:outFile
					continue;
				)

				obj = lodobjects[k]

				-- output normalmeshfact
				-- meshfact name changes for hierarchy
				if (lodlow!=undefined) then
					format "  <meshfact name=\"%_%\">\n" factoryName (k-1) to:outFile
				else
					format "  <meshfact name=\"%\">\n" factoryName to:outFile

				if (lodobjects.count!=1) then
					format "<lodlevel>%</lodlevel>\n" (k-1) to:outFile
				format "  <plugin>crystalspace.mesh.loader.factory.genmesh</plugin><params><numvt>%</numvt>\n" (getNumTVerts obj) to:outFile

				-- just for LOD hierarchical objects material must be speficied in the factory
				if (lodlow!=undefined) then (
					m = obj.mat;
					if ((classOf m)==Multimaterial) then (
						matUsed = getFaceMatID obj 1
						m = obj.mat[matUsed];
					)
					format "      <material>%</material>\n" (getMatFilename m) to:outFile
				)

				-- check texture
				if (getNumTVerts obj==0) then
				(
					message = "Export aborted: No UV maps assigned to genmesh object: " + factoryName
					messageBox message
					close outFile
					return 1
				)

				-- checks if model has left-oriented system or not
				face = getface obj 1
				v1= getvert obj face[1]
				v2 = getvert obj face[2]
				v3 = getvert obj face[3]

				vect1 = v1-v2
				vect2 = v3-v2
				normal1 = cross vect1 vect2
				facenorm = normal1/(length normal1)
				maxnorm = getfacenormal obj 1
				flipModel = false

				dotProd = dot facenorm maxnorm
				if (dotProd>0) then (
					flipModel = true
				)

			   if (flipModel) then (
			    format "\n GenMesh Factory Object needs flipping: %\n" factoryName
			   )

				vertTInfo = #(getNumTVerts obj)
				vertTInfo[1] = undefined
				normalsVert = #()

				isSky = false
				if (findString obj.name "_sky_" !=undefined) then
				 isSky = true

				-- cycle on all Faces of the object to get Tverts x,y,z positions
				for i=1 to obj.numfaces do
				(
					-- get face
					Tface = getTVFace obj i
					face = getFace obj i

					-- check smooth group of the face
					smoothgroup = getFaceSmoothGroup obj i

					-- get its 3 vertices
					for h=1 to 3 do (
				    	curVert=getVert obj face[h]
						if (curVert==undefined) then
							format "\n\nUNDEF: %\n\n" Tface[h]
						if (debug) then
							format " face: % curVert %: %\n" i Tface[h] curVert

						-- if the value is different we have a problem on Welded UV
						if (vertTInfo[Tface[h]]!=undefined and vertTInfo[Tface[h]]!=curVert) then (
							message = "PROBLEM on object " + factoryName + ".\n UV should not be welded on vertex " + (Tface[h] as String)
							messageBox message
							close outFile
							return 1
						)
						vertTInfo[Tface[h]]=curVert

						-- get normal for sky (TODO: double check, seems not right)
						if (isSky) then (
							normalsVert[Tface[h]]=getNormal obj face[h]
						-- get normal in case of smoothing groups
                        ) else if (smoothgroup!=0) then (
							-- get average normal
							faces = meshop.getFacesUsingVert obj face[h] as array
							normal = [0,0,0]
							facescount = 0
							for j in faces do (
							    if (getFaceSmoothGroup obj j==smoothgroup) then
									normal += (getFaceNormal obj j)
									facescount+=1
							)
							normal = normal/facescount
							normalsVert[Tface[h]]=normal
						-- get normal in case no smooth group present
						) else (
							--normalsVert[Tface[h]]=getNormal obj face[h]
							normal = meshop.getFaceRNormals obj i
							normalsVert[Tface[h]]=normal[1]
						)
					)
				)

				-- cycle on all TVerts of the object
				for i =1 to (getNumTVerts obj) do
				(
					-- get its 3 vertices as a point3
					-- export in XZY format
				    vert=vertTInfo[i]
					if (vert==undefined) then (
						message = "PROBLEM on object " + factoryName + ": UV mapping seems to be messed up. Please UnWrap it then collapse it.";
						messageBox message
						close outFile
						return 1
					)
					xvert = (vert.x * xscale) + xrelocate
					yvert = (vert.y * yscale) + yrelocate
					zvert = (vert.z * zscale) + zrelocate

					Tvert = getTVert obj i

					-- if it's an autogenerated genmesh then relocate to 0,0,0
					if (auto==1) then (
						xvert = xvert - obj.pos.x
						yvert = yvert - obj.pos.y
						zvert = zvert - obj.pos.z
					)

					format "      <v x=\"%\" y=\"%\" z=\"%\" u=\"%\" v=\"%\" /> \n" xvert zvert yvert Tvert[1] (1-Tvert[2]) i to:outFile
				)

				-- write all normals
				for i =1 to (getNumTVerts obj) do
				(
					Tvert = getTVert obj i
					normalvert = normalsVert[i]
					normalvert = normalize(normalvert)
					format "      <n x=\"%\" y=\"%\" z=\"%\" /> \n" normalvert.x normalvert.z normalvert.y to:outFile
				)

				-- cycle on all faces of object and split by material
				facesmaterial=#()
				facesmaterialfaces=#()
                -- if standard material, then 1 submesh only
				if ((classOf obj.mat)==Standardmaterial) then (
				    append facesmaterial (getMatFilename (obj.mat))
					facesmaterialfaces[1]=#()
					for i =1 to obj.numFaces do
					(
						append facesmaterialfaces[1] i
					)
				) else (
					for i =1 to obj.numFaces do
					(
					    textid = getFaceMatID obj i
						if (textid > obj.mat.count) then (
						  format "ERROR!!! Object % uses more material ID than the materials defined. \n" obj.name
						)
						--format "% % \n" i textid
						m = obj.mat[textid]
	   					mname = getMatFilename(m)
						if (findItem facesmaterial mname==0) then (
							append facesmaterial mname
						)
						pos = findItem facesmaterial mname
						if (facesmaterialfaces[pos]==undefined) then
						   facesmaterialfaces[pos]=#()
					    append facesmaterialfaces[pos] i
					)
				)
				format "\n facesmaterial: % \n" facesmaterial
				format "\n facesmaterialid: % \n" facesmaterialfaces

				-- write one submesh for each material
				for i =1 to facesmaterial.count do
				(
					mname = facesmaterial[i];

					format "    <submesh name=\"%\">\n" ("submesh"+i as String) to:outFile
                    format "    <material>%</material>\n" mname to:outFile
                    format "    <indexbuffer components=\"1\" type=\"uint\" indices=\"yes\">\n" to:outFile

                    -- cycle on all faces using same material
                    for j=1 to facesmaterialfaces[i].count do
					(
						currentfaceset = facesmaterialfaces[i]
						faceVerts=getTVface obj currentfaceset[j]
						a = (faceVerts[1]-1) as Integer

						if (flipModel) then (
							b = (faceVerts[2]-1) as Integer
							c = (faceVerts[3]-1) as Integer
						) else (
							b = (faceVerts[3]-1) as Integer
							c = (faceVerts[2]-1) as Integer
						)

						-- exclude collision detection on low lod versions
						if (k!=lodobjects.count) then (
							format "    <e c0=\"%\" /><e c0=\"%\" /><e c0=\"%\" />\n" a b c to:outFile
							--if (colldet=="no") then format "<colldet>no</colldet>" to:outFile
						) else (
							--if (colldet=="no") then format "<t v1=\"%\" v2=\"%\" v3=\"%\"><colldet>no</colldet></t>"  a b c to:outFile
							format "    <e c0=\"%\" /><e c0=\"%\" /><e c0=\"%\" />\n" a b c to:outFile
						)
					)
					format "    </indexbuffer></submesh>\n" to:outFile
			    )

				-- check for smooth setting
				-- temporary disabled
				--smooth = getUserProp obj "SMOOTH"
				--if (smooth=="yes") then
				--	format "      <autonormals/>\n" to:outFile

				format "    </params>\n" to:outFile

				-- check for no lighting setting
				lighting = getUserProp obj "LIGHTING"

				--check simple colldet setting
				colldet = getUserProp obj "COLLDET"

				-- check for viscull setting
				viscull = getUserProp obj "VISCULL"

				-- check for culleronly setting
				culleronly = getUserProp obj "CULLERONLY"

				-- check player barrier setting
				playerbarrier = getUserProp obj "PLAYERBARRIER"

                occluder = false
				-- check for culleronly setting
				culleronly = getUserProp obj "CULLERONLY"

				-- check player barrier setting
				playerbarrier = getUserProp obj "PLAYERBARRIER"

			    -- output name of object and some info
				if (findString obj.name "_occ_" !=undefined) then (
					occluder = true
				)

				istrasparent=false
				-- check if object is a range alpha trasparent
				rangetrasp = getUserProp obj "RANGETRASP"
				if (rangetrasp=="yes") then (
				  istrasparent=true
				)

				-- check if object is a binary alpha trasparent
				trasp = getUserProp obj "TRASPARENT"
				if (trasp=="yes") then (
				  istrasparent=true
				)

				-- handles transparent objects
				if (istrasparent) then (
				  format "      <priority>alpha</priority>\n" to:outFile
				  format "      <ztest />\n" to:outFile
				)
			    -- handles sky objects
				else if (findString obj.name "_sky_" !=undefined) then (
				  format "      <priority>sky</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)
			    -- handles zfill objects
				else if (findString obj.name "_s_" !=undefined) then (
				  format "      <priority>object</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)
				else if (culleronly=="yes" or playerbarrier=="yes" or (occluder and (classOf obj)!=Box)) then (
					format "      <mesh>\n" to:outFile
				) else if (occluder and (classOf obj)==Box) then (
					format "      <box>\n" to:outFile
				) else (
				  format "      <priority>object</priority>\n" to:outFile
				  format "      <zuse />\n" to:outFile
				)

				-- check for no shadow setting
				noshadows = getUserProp obj "NOSHADOWS"
				if (noshadows=="yes") then
					format "      <noshadows />\n" to:outFile

				if (colldet=="no") then format "<trimesh><id>colldet</id></trimesh>\n" to:outFile

				-- check for no shadow setting
				-- NO MORE WORKING??
				noshadows = getUserProp obj "NOSHADOWS"
				if (noshadows=="yes") then
					format "      <noshadows />\n" to:outFile

				-- check if object is a range alpha trasparent
				rangetrasp = getUserProp obj "RANGETRASP"
				if (rangetrasp=="yes") then (
				  format "      <ztest/><priority>alpha</priority>\n" to:outFile
				)

				-- check if object uses a binary alpha texture
			    if ((classOf obj.mat)==Standardmaterial) then (
					if (obj.mat.mapEnables[7]) then (
					  format "      <trimesh><id>viscull</id></trimesh>\n" to:outFile
					  format "      <trimesh><default /><id>colldet</id></trimesh>\n" to:outFile
					)
				) else (
					if (obj.mat[1].mapEnables[7]) then (
					  format "      <trimesh><id>viscull</id></trimesh>\n" to:outFile
					  format "      <trimesh><default /><id>colldet</id></trimesh>\n" to:outFile
					)
				)

				format "    </meshfact>\n" to:outFile

			) -- end for each lodobject

			if (lodobjects.count!=1) then
				format "  </meshfact>\n" to:outFile

        )

	on Test1 open do
	(
	   name = selection[1].name
	   edt3.text = "d:\\Luca\\"+name+".spr"

	)
	on btn2 pressed do
	(

		-- ////////////////////////
		-- Variables used in the program
		-- ////////////////////////

		-- get filename
		filename = edt3.text

		-- output file
		outFile = createFile filename

		-- set debug output
		debug=false

		-- Define verbose output (that takes more space and memory)
		verboseMode = true

		-- functions declaration
		global tokenize
		global OutputGenMeshFactory
		global getMatFilename
		global lowercase

		-- Tokenize utility function
		fn tokenize instring sep =
		(
		   outarray = #()
		   temp=copy instring
		   i = 1
		   while (true) do (
		   	index = findstring temp sep
			if (index==undefined) then
			(
				outarray[i]=temp
				exit
			) else (
				outarray[i] = substring temp 1 (index-1)
				temp = substring temp (index+1) -1
			)
			i = i +1
		   )
		   outarray
		)

		-- get filename from a material
		fn getMatFilename m =
		(
		    if (m==undefined) then
				image="MATERIALNOTDEFINED"
			else (
			    mat = m.maps[2]
				if (mat!=undefined) then
				(
					image = mat.filename
					indx = tokenize image "\\"
					image = indx[indx.count]
				) else
					image="MATERIALNOTDEFINED"

				image = lowercase(image)
			)
		)

		-- LowerCase utility function
		fn lowercase instring =
		(
		   local upper, lower, outstring
		   upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
		   lower="abcdefghijklmnopqrstuvwxyz"

		   outstring=copy instring

		   for i=1 to outstring.count do
		   (  j=findString upper outstring[i]
		      if (j != undefined) do outstring[i]=lower[j]
		   )

		   outstring
		)

		-- ////////////////////////
		-- Main: program starts here
		-- ////////////////////////

			-- identify main sprite object
			obj=selection[1]
			objectname = obj.name

		    -- output name of object and some info
			format "\n\nFound Object Name: % Faces: %\n" objectname obj.numfaces

	    OutputGenMeshFactory obj outFile debug 1

		close outFile
		message = "ALL DONE!"

		messageBox message

	)
)
gw = newRolloutFloater "Export Sprite" 300 410
addRollout Test1 gw

)

---------------------------------------------------------------------------------------
--  Documentation
--
--
-- Faces that need UV Unwield:
-- This means that some UV coords are shared on multiple vertexes
-- Go in the UVUnwrap function and Unweld all the vertexes of the face found
-------------------


-add metadata method now works when multiple objects are selected

function CreateAlembicMetadataModifier selectedObject = (

	if selectedObject != undefined then (
		--only allow one modifier
		if selectedObject.modifiers["alembic_metadata"] == undefined then (

			AlembicMetaDataModifier = EmptyModifier()
			AlembicMetaDataModifier.name = "alembic_metadata"
			addmodifier selectedObject AlembicMetaDataModifier

			AlembicMetadataCA = attributes AlembicMetadata
			(
				parameters AlembicMetadataPRM rollout:AlembicMetadataRLT
				(
					name0 type:#string ui:eName0 default:""
					value0 type:#string ui:eValue0 default:""
					name1 type:#string ui:eName1 default:""
					value1 type:#string ui:eValue1 default:""
					name2 type:#string ui:eName2 default:""
					value2 type:#string ui:eValue2 default:""
					name3 type:#string ui:eName3 default:""
					value3 type:#string ui:eValue3 default:""
					name4 type:#string ui:eName4 default:""
					value4 type:#string ui:eValue4 default:""
					name5 type:#string ui:eName5 default:""
					value5 type:#string ui:eValue5 default:""
					name6 type:#string ui:eName6 default:""
					value6 type:#string ui:eValue6 default:""
					name7 type:#string ui:eName7 default:""
					value7 type:#string ui:eValue7 default:""
					name8 type:#string ui:eName8 default:""
					value8 type:#string ui:eValue8 default:""
					name9 type:#string ui:eName9 default:""
					value9 type:#string ui:eValue9 default:""
				)

				rollout AlembicMetadataRLT "alembic_metadata"
				(
					edittext eName0 "n0" fieldWidth:120 labelOnTop:false
					edittext eValue0 "v0" fieldWidth:120 labelOnTop:false
					edittext eName1 "n1" fieldWidth:120 labelOnTop:false
					edittext eValue1 "v1" fieldWidth:120 labelOnTop:false
					edittext eName2 "n2" fieldWidth:120 labelOnTop:false
					edittext eValue2 "v2" fieldWidth:120 labelOnTop:false
					edittext eName3 "n3" fieldWidth:120 labelOnTop:false
					edittext eValue3 "v3" fieldWidth:120 labelOnTop:false
					edittext eName4 "n4" fieldWidth:120 labelOnTop:false
					edittext eValue4 "v4" fieldWidth:120 labelOnTop:false
					edittext eName5 "n5" fieldWidth:120 labelOnTop:false
					edittext eValue5 "v5" fieldWidth:120 labelOnTop:false
					edittext eName6 "n6" fieldWidth:120 labelOnTop:false
					edittext eValue6 "v6" fieldWidth:120 labelOnTop:false
					edittext eName7 "n7" fieldWidth:120 labelOnTop:false
					edittext eValue7 "v7" fieldWidth:120 labelOnTop:false
					edittext eName8 "n8" fieldWidth:120 labelOnTop:false
					edittext eValue8 "v8" fieldWidth:120 labelOnTop:false
					edittext eName9 "n9" fieldWidth:120 labelOnTop:false
					edittext eValue9 "v9" fieldWidth:120 labelOnTop:false
				)
			)

			custattributes.add selectedObject.modifiers["alembic_metadata"] AlembicMetadataCA baseobject:false
		)
	)
)

function InitAlembicMetadataModifier selectedObject dname0 dvalue0 dname1 dvalue1 dname2 dvalue2 dname3 dvalue3 dname4 dvalue4 dname5 dvalue5 dname6 dvalue6 dname7 dvalue7 dname8 dvalue8 dname9 dvalue9 = (

	if selectedObject != undefined then
	(
		selectedObject.modifiers["alembic_metadata"].name0 = dname0;
		selectedObject.modifiers["alembic_metadata"].value0 = dvalue0;
		selectedObject.modifiers["alembic_metadata"].name1 = dname1;
		selectedObject.modifiers["alembic_metadata"].value1 = dvalue1;
		selectedObject.modifiers["alembic_metadata"].name2 = dname2;
		selectedObject.modifiers["alembic_metadata"].value2 = dvalue2;
		selectedObject.modifiers["alembic_metadata"].name3 = dname3;
		selectedObject.modifiers["alembic_metadata"].value3 = dvalue3;
		selectedObject.modifiers["alembic_metadata"].name4 = dname4;
		selectedObject.modifiers["alembic_metadata"].value4 = dvalue4;
		selectedObject.modifiers["alembic_metadata"].name5 = dname5;
		selectedObject.modifiers["alembic_metadata"].value5 = dvalue5;
		selectedObject.modifiers["alembic_metadata"].name6 = dname6;
		selectedObject.modifiers["alembic_metadata"].value6 = dvalue6;
		selectedObject.modifiers["alembic_metadata"].name7 = dname7;
		selectedObject.modifiers["alembic_metadata"].value7 = dvalue7;
		selectedObject.modifiers["alembic_metadata"].name8 = dname8;
		selectedObject.modifiers["alembic_metadata"].value8 = dvalue8;
		selectedObject.modifiers["alembic_metadata"].name9 = dname9;
		selectedObject.modifiers["alembic_metadata"].value9 = dvalue9;
	)
)

---------------------------------------------------------------------------------------------------------
-- MacroScript to link the menu items to MAXScript functions

macroScript AlembicCreateMetadataModifier
    category:"Alembic"
    buttonText:"Add Alembic Metadata..."
    tooltip:"Add Alembic Metadata Display Modifier To Current Selection..."
(
    on execute do
    (
    	for i = 1 to selection.count do
    	(
    		CreateAlembicMetadataModifier selection[i]
    	)
    )
)

function CreateAlembicMetadataModifier selectedObject = (

	if selectedObject != undefined then (
		--only allow one modifier
		if selectedObject.modifiers["alembic_metadata"] == undefined then (

			AlembicMetaDataModifier = EmptyModifier()
			AlembicMetaDataModifier.name = "alembic_metadata"
			addmodifier selectedObject AlembicMetaDataModifier

			AlembicMetadataCA = attributes AlembicMetadata
			(
				parameters AlembicMetadataPRM rollout:AlembicMetadataRLT
				(
					name0 type:#string ui:eName0 default:""
					value0 type:#string ui:eValue0 default:""
					name1 type:#string ui:eName1 default:""
					value1 type:#string ui:eValue1 default:""
					name2 type:#string ui:eName2 default:""
					value2 type:#string ui:eValue2 default:""
					name3 type:#string ui:eName3 default:""
					value3 type:#string ui:eValue3 default:""
					name4 type:#string ui:eName4 default:""
					value4 type:#string ui:eValue4 default:""
					name5 type:#string ui:eName5 default:""
					value5 type:#string ui:eValue5 default:""
					name6 type:#string ui:eName6 default:""
					value6 type:#string ui:eValue6 default:""
					name7 type:#string ui:eName7 default:""
					value7 type:#string ui:eValue7 default:""
					name8 type:#string ui:eName8 default:""
					value8 type:#string ui:eValue8 default:""
					name9 type:#string ui:eName9 default:""
					value9 type:#string ui:eValue9 default:""
				)

				rollout AlembicMetadataRLT "alembic_metadata"
				(
					edittext eName0 "n0" fieldWidth:120 labelOnTop:false
					edittext eValue0 "v0" fieldWidth:120 labelOnTop:false
					edittext eName1 "n1" fieldWidth:120 labelOnTop:false
					edittext eValue1 "v1" fieldWidth:120 labelOnTop:false
					edittext eName2 "n2" fieldWidth:120 labelOnTop:false
					edittext eValue2 "v2" fieldWidth:120 labelOnTop:false
					edittext eName3 "n3" fieldWidth:120 labelOnTop:false
					edittext eValue3 "v3" fieldWidth:120 labelOnTop:false
					edittext eName4 "n4" fieldWidth:120 labelOnTop:false
					edittext eValue4 "v4" fieldWidth:120 labelOnTop:false
					edittext eName5 "n5" fieldWidth:120 labelOnTop:false
					edittext eValue5 "v5" fieldWidth:120 labelOnTop:false
					edittext eName6 "n6" fieldWidth:120 labelOnTop:false
					edittext eValue6 "v6" fieldWidth:120 labelOnTop:false
					edittext eName7 "n7" fieldWidth:120 labelOnTop:false
					edittext eValue7 "v7" fieldWidth:120 labelOnTop:false
					edittext eName8 "n8" fieldWidth:120 labelOnTop:false
					edittext eValue8 "v8" fieldWidth:120 labelOnTop:false
					edittext eName9 "n9" fieldWidth:120 labelOnTop:false
					edittext eValue9 "v9" fieldWidth:120 labelOnTop:false
				)
			)

			custattributes.add selectedObject.modifiers["alembic_metadata"] AlembicMetadataCA baseobject:false
		)
	)
)

function InitAlembicMetadataModifier selectedObject dname0 dvalue0 dname1 dvalue1 dname2 dvalue2 dname3 dvalue3 dname4 dvalue4 dname5 dvalue5 dname6 dvalue6 dname7 dvalue7 dname8 dvalue8 dname9 dvalue9 = (

	if selectedObject != undefined then
	(
		selectedObject.modifiers["alembic_metadata"].name0 = dname0;
		selectedObject.modifiers["alembic_metadata"].value0 = dvalue0;
		selectedObject.modifiers["alembic_metadata"].name1 = dname1;
		selectedObject.modifiers["alembic_metadata"].value1 = dvalue1;
		selectedObject.modifiers["alembic_metadata"].name2 = dname2;
		selectedObject.modifiers["alembic_metadata"].value2 = dvalue2;
		selectedObject.modifiers["alembic_metadata"].name3 = dname3;
		selectedObject.modifiers["alembic_metadata"].value3 = dvalue3;
		selectedObject.modifiers["alembic_metadata"].name4 = dname4;
		selectedObject.modifiers["alembic_metadata"].value4 = dvalue4;
		selectedObject.modifiers["alembic_metadata"].name5 = dname5;
		selectedObject.modifiers["alembic_metadata"].value5 = dvalue5;
		selectedObject.modifiers["alembic_metadata"].name6 = dname6;
		selectedObject.modifiers["alembic_metadata"].value6 = dvalue6;
		selectedObject.modifiers["alembic_metadata"].name7 = dname7;
		selectedObject.modifiers["alembic_metadata"].value7 = dvalue7;
		selectedObject.modifiers["alembic_metadata"].name8 = dname8;
		selectedObject.modifiers["alembic_metadata"].value8 = dvalue8;
		selectedObject.modifiers["alembic_metadata"].name9 = dname9;
		selectedObject.modifiers["alembic_metadata"].value9 = dvalue9;
	)
)

---------------------------------------------------------------------------------------------------------
-- MacroScript to link the menu items to MAXScript functions

macroScript AlembicCreateMetadataModifier
    category:"Alembic"
    buttonText:"Add Alembic Metadata..."
    tooltip:"Add Alembic Metadata Display Modifier To Current Selection..."
(
    on execute do
    (

        CreateAlembicMetadataModifier $
    )
)


left out "+" by mistake

left out "+" by mistake

plugin Helper AlembicTimeControl
    name:"Alembic Time Control"
    classID:#(0x4eb65d6, 0x7c454597)
    category:"Alembic"
    extends:dummy
(
    local lastSize=0, meshObj = undefined

    parameters pblock rollout:params
    (
        current type:#float ui:current animatable:true default:0
        offset type:#float ui:offset animatable:false default:0
        factor type:#float ui:factor animatable:false default:1

        cacheStart type:#float default:0 ui:uiCacheStart animatable:off
        cacheEnd type:#float default:animationrange.end ui:uiCacheEnd animatable:off
        frameOffset type:#float default:0 ui:uiFrameOffset animatable:off
        loop type:#Boolean default:false ui:uiLoop animatable:off

        time type:#float ui:uiTime animatable:true default:1

        gScale type:#integer ui:gScaleSp animatable:false default:100

        on current set val do this.OffsetCache()
        on offset set val do this.OffsetCache()
        on factor set val do this.OffsetCache()
        on frameOffset set val do this.OffsetCache()
        on cacheStart set val do this.OffsetCache()
        on cacheEnd set val do this.OffsetCache()
        on loop set val do this.OffsetCache()
    )

    rollout params "Alembic"
    (
        spinner current "Current Time: " range:[-10000,10000,0]
        spinner factor "Time Scale: " range:[-10000,10000,1]
        spinner offset "Time Offset: " range:[-10000,10000,0] scale: 0.1
        spinner uiFrameOffset "Frame Offset: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,8]

        spinner uiCacheStart "Cache Start: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,8]
        spinner uiCacheEnd "Cache End: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,0]
        checkbox uiLoop "Loop Cache: " align:#right offset:[2,6]

        spinner uiTime "Final Time: " range:[-10000,10000,0]
        spinner gScaleSp "Gizmo Scale: " range:[10, 1e9, 100] offset:[0,10] type:#integer

        on gScaleSp changed val do
        (
            classInstances = (getClassInstances AlembicTimeControl)
            for i in classInstances do
                for j in (refs.dependents i) do
                    if classOf j ==  AlembicTimeControl do
                        j.scale = [val*.01,val*.01,val*.01]
        )
    )

    fn OffsetCache =
    (
        current.controller = float_expression()
	    current.controller.setExpression "S"

        time.controller = float_expression()

        local frameRange = (cacheEnd - cacheStart) / framerate
        local tScale = factor as string
        local timeOffset = ((frameOffset/framerate as float) + offset) as string

        local cStart = (cacheStart / framerate as float) as string
        if Loop then
        (
            fRange = frameRange as string
            fStart = (frameRange as string) as string

            str = "if(S*" + tScale + "+" + timeOffset + ">=0," + \
                    "mod (S*" + tScale + "+" + timeOffset + "," + fRange + ") + " + cStart + \
                    ",mod (S*" + tScale + "+" + timeOffset + "," + fRange + ") + " + cStart + "+ " + fStart + ")"

        )else(
            str = "(S*" + tScale + "+" + timeOffset + "+" + cStart + ")"
        )

        time.controller.SetExpression str
        time.controller.Update()
    )

    on getDisplayMesh do
    (
        if (meshObj == undefined) do
        (
            meshObj =  createInstance AlembicNull
            lastSize = gScale
        )

        meshObj.mesh
    )

    on useWireColor do
    (
        false
    )

    tool create
    (
        on mousePoint click do
        (
            #stop
        )

    )
)

plugin Helper AlembicTimeControl
    name:"Alembic Time Control"
    classID:#(0x4eb65d6, 0x7c454597)
    category:"Alembic"
    extends:dummy
(
    local lastSize=0, meshObj = undefined

    parameters pblock rollout:params
    (
        current type:#float ui:current animatable:true default:0
        offset type:#float ui:offset animatable:false default:0
        factor type:#float ui:factor animatable:false default:1

        cacheStart type:#float default:0 ui:uiCacheStart animatable:off
        cacheEnd type:#float default:animationrange.end ui:uiCacheEnd animatable:off
        frameOffset type:#float default:0 ui:uiFrameOffset animatable:off
        loop type:#Boolean default:false ui:uiLoop animatable:off

        time type:#float ui:uiTime animatable:true default:1

        gScale type:#integer ui:gScaleSp animatable:false default:100

        on current set val do this.OffsetCache()
        on offset set val do this.OffsetCache()
        on factor set val do this.OffsetCache()
        on frameOffset set val do this.OffsetCache()
        on cacheStart set val do this.OffsetCache()
        on cacheEnd set val do this.OffsetCache()
        on loop set val do this.OffsetCache()
    )

    rollout params "Alembic"
    (
        spinner current "Current Time: " range:[-10000,10000,0]
        spinner factor "Time Scale: " range:[-10000,10000,1]
        spinner offset "Time Offset: " range:[-10000,10000,0] scale: 0.1
        spinner uiFrameOffset "Frame Offset: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,8]

        spinner uiCacheStart "Cache Start: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,8]
        spinner uiCacheEnd "Cache End: " fieldwidth:50 range:[-1e9,1e9,0] type:#float align:#right offset:[0,0]
        checkbox uiLoop "Loop Cache: " align:#right offset:[2,6]

        spinner uiTime "Final Time: " range:[-10000,10000,0]
        spinner gScaleSp "Gizmo Scale: " range:[10, 1e9, 100] offset:[0,10] type:#integer

        on gScaleSp changed val do
        (
            classInstances = (getClassInstances AlembicTimeControl)
            for i in classInstances do
                for j in (refs.dependents i) do
                    if classOf j ==  AlembicTimeControl do
                        j.scale = [val*.01,val*.01,val*.01]
        )
    )

    fn OffsetCache =
    (
        current.controller = float_expression()
	    current.controller.setExpression "S"

        time.controller = float_expression()

        local frameRange = (cacheEnd - cacheStart) / framerate
        local tScale = factor as string
        local timeOffset = ((frameOffset/framerate as float) + offset) as string

        local cStart = (cacheStart / framerate as float) as string
        if Loop then
        (
            fRange = frameRange as string
            fStart = (frameRange as string) as string

            str = "if(S*" + tScale + "+" + timeOffset + ">=0," + \
                    "mod (S*" + tScale + "+" + timeOffset + "," + fRange + ") + " + cStart + \
                    ",mod (S*" + tScale + "+" + timeOffset + "," + fRange + ") + " + cStart + "+ " + fStart + ")"

        )else(
            str = "(S*" + tScale + "+" + timeOffset + cStart + ")"
        )

        time.controller.SetExpression str
        time.controller.Update()
    )

    on getDisplayMesh do
    (
        if (meshObj == undefined) do
        (
            meshObj =  createInstance AlembicNull
            lastSize = gScale
        )

        meshObj.mesh
    )

    on useWireColor do
    (
        false
    )

    tool create
    (
        on mousePoint click do
        (
            #stop
        )

    )
)