1-- NW4C Menu Utilities (2011/02/15)
2-- Version 1.0.0
3-- (c)2010-2011 Nintendo
4
5struct nw4c_userData
6(
7	dataname = "",
8	type = String,
9	val = #(),
10	fn copyTo dst =
11	(
12		if (classof dst) != nw4c_userData do return false
13		dst.dataname = dataname
14		dst.type = type
15		dst.val = deepCopy val
16		return true
17	),
18	fn valueToString oneline:false =
19	(
20		local str = ""
21		for j = 1 to val.count do
22		(
23			if j != 1 do
24			(
25				str += if (not oneline) and (type == String) then "\n" else " "
26			)
27			str += (val[j] as string)
28		)
29		return str
30	),
31	fn valueCount =
32	(
33		local ret = 0
34		if type == String then
35		(
36			for v in val do
37			(
38				ret += v.count
39			)
40		)
41		else
42		(
43			ret = val.count
44		)
45		return ret
46	),
47	fn toString =
48	(
49		local str = dataname
50		str += "\""
51		str += case type of
52		(
53			Integer: "i"
54			Float: "f"
55			default: "s" -- string
56		)
57		str += " "
58		str += valueToString()
59		str += "\""
60		return str
61	),
62	fn fromString s =
63	(
64		local tokens = filterString s "\""
65		if tokens.count != 2 do return false
66		dataname = tokens[1]
67
68		local valStr = tokens[2]
69		case valStr[1] of
70		(
71			"i": type = Integer
72			"f": type = Float
73			default: type = String
74		)
75		val = #( )
76
77		local valTokens = #()
78
79		if type == String then
80		(
81			valTokens = filterString (substring valStr 3 -1) "\n"
82		)
83		else
84		(
85			valTokens = filterString (substring valStr 3 -1) " "
86		)
87
88		for i = 1 to valTokens.count do
89		(
90			local v = case type of
91			(
92				Integer: (valTokens[i] as Integer)
93				Float: (valTokens[i] as Float)
94				default: (valTokens[i])
95			)
96			if v != undefined do
97			(
98				append val v
99			)
100		)
101		return true
102	)
103)
104
105struct nw4c_userDataSet
106(
107	list = #(),
108	fn appendData data =
109	(
110		if (classof data) != nw4c_userData do return false
111		append list data
112	),
113	fn toString =
114	(
115		local ret = ""
116		if (classof list) != Array do return ""
117		for i = 1 to list.count do
118		(
119			local data = list[i]
120			if (classof data) != nw4c_userData do continue
121			if i != 1 do ret += " "
122			ret += data.toString()
123		)
124		return ret
125	),
126	fn fromString s =
127	(
128		if (classof s) != String do return false
129		list = #()
130		local p = 1
131		while p <= s.count do
132		(
133			while s[p] == " " and p < s.count do p += 1 -- �X�y�[�X���X�L�b�v
134			local ep = p
135			while s[ep] != "\"" and ep < s.count do ep += 1 -- �ŏ���"��T��
136			ep += 1
137			while s[ep] != "\"" and ep <= s.count do ep += 1 -- ���"��T��
138			if ep <= s.count do
139			(
140				local len = ep - p + 1
141				local d = nw4c_userData()
142				if (d.fromString (substring s p len) ) do
143				(
144					append list d
145				)
146			)
147			p = ep + 1
148		)
149		return true
150	),
151	fn getFromAttribute attr =
152	(
153		list = #()
154	),
155	fn setToAttribute attr =
156	(
157	)
158)
159
160struct nw4c_utils
161(
162	enableSaveToScene = true,
163
164	fn outComment fs str =
165	(
166		format "# %\n" str to:fs
167	),
168
169	fn outReturn fs=
170	(
171		format "\n" to:fs
172	),
173
174	fn outValue fs key v =
175	(
176		format "%=\"%\"\n" key (v as string) to:fs
177	),
178
179	fn outVersion fs key v =
180	(
181		local str = ""
182		for i = 1 to 3 do
183		(
184			local d = (mod v 10) as integer
185			v = (v - d) / 10
186			str = (d as string) + str
187			if i != 3 do str = "." + str
188		)
189		outValue fs key str
190	),
191
192	fn outQuantValue fs key v =
193	(
194		local str = case v of
195		(
196			3: "Byte"
197			2: "Short"
198			default: "Float"
199		)
200
201		outValue fs key str
202	),
203
204	fn QuantStrToInt str =
205	(
206		local val = toLower str
207		case val of
208		(
209			"byte": 3
210			"short": 2
211			default: 1
212		)
213	),
214
215	fn useNonUniformScale =
216	(
217		((systemTools.getEnvVariable "NW4C_USE_NON_UNIFORM_SCALE") == "1")
218	),
219
220	fn loadSettingFromFile filename isDefault:false =
221	(
222		local nw4c = nw4cmax
223		if nw4c == undefined do return false
224		if filename == undefined do return false
225		local fs = openFile filename mode:"rt"
226		if fs == undefined do
227		(
228			format "File Open Error(%)\n" filename
229			return false
230		)
231		-- read header
232		if (findString (readLine fs) "NW4C_Export settings") == undefined do return false
233		local str, key, val, ver = 0
234		local isEOF = false
235		while isEOF == false do
236		(
237			str = readLine fs
238			-- skip comment and null line
239			if (str.count < 1) or (str[1] == "#") do continue
240			local elem = filterString str "="
241			if (classof elem != Array) or elem.count != 2 do continue
242			key = elem[1]
243			val = substituteString elem[2] "\"" ""
244			--format "\"%\"=\"%\"\n" key val
245			case key of
246			(
247				"ExportTarget": (
248					nw4c.doesExportSelected = ((stricmp val "Selection") == 0)
249				)
250				"OutputFileName": nw4c.filename = val
251				"OutputFolder": nw4c.outFolder = val
252				"OutputMode": (
253					if (stricmp val "CreativeStudio") == 0 then
254					(
255						nw4c.UseCreativeStudio = true
256						nw4c.Use3DEditor = false
257					)
258					else if (stricmp val "3DEditor") == 0 then
259					(
260						nw4c.UseCreativeStudio = false
261						nw4c.Use3DEditor = true
262					)
263					else
264					(
265						nw4c.UseCreativeStudio = false
266						nw4c.Use3DEditor = false
267					)
268					nw4c.UseCreativeStudio = ((stricmp val "CreativeStudio") == 0)
269				)
270				"MergeCmdl": nw4c.UseMerge = val as booleanclass
271				"MergeCmdlPath": nw4c.MergeFilename = val
272				"CopyRelatedFiles": nw4c.CopyMergeRelatedFiles = val as booleanclass
273				"Magnify": nw4c.Magnify = val as float
274				"FrameRange": nw4c.doesExportAllFrames =  ((stricmp val "Range") != 0)
275				"StartFrame": nw4c.StartFrame = val as integer
276				"EndFrame": nw4c.EndFrame = val as integer
277				"UseFigureMode": nw4c.useFiguremode = val as booleanclass
278				"OutputCmdl": nw4c.doesExportModel = val as booleanclass
279				"OutputCtex": nw4c.doesExportTexture = val as booleanclass
280				"OutputCskla": nw4c.doesExportAnimation = val as booleanclass
281				"OutputCmata": nw4c.doesExportMtlAnim = val as booleanclass
282				"OutputCcam": nw4c.doesExportCamera = val as booleanclass
283				"OutputClgt": nw4c.doesExportLight = val as booleanclass
284				"OutputCenv": nw4c.doesExportEnv = val as booleanclass
285				"OutputCmdla": nw4c.doesExportModelAnim = val as booleanclass
286				"OutputCmcla": nw4c.doesExportMtlColorAnim = val as booleanclass
287				"OutputCmtpa": nw4c.doesExportMtlTexPatternAnim = val as booleanclass
288				"OutputCmtsa": nw4c.doesExportMtlTexSRTAnim = val as booleanclass
289
290				"CompressNode": (
291					nw4c.CompressNode = case val of
292					(
293						"Cull": 2
294						"CullUninfluential": 3
295						"UniteCompressible": 4
296						"UniteAll": 5
297						default: 1
298					)
299				)
300				"CompressMaterial": ()--nw4c.
301				"OptimizePrimitive": nw4c.OptimizePrimitive = val as booleanclass
302				"ConvertToModel": ( -- 0.5.0���狓�����ς�����̂ŁA����ȑO�̃t���O�͖���
303					--format "version %\n" ver
304					if ver < 130 then
305					(
306						--print "old file is load.\n convert to model flag is ignored."
307						nw4c.DisableModelSimplification = true
308					)
309					else
310					(
311						nw4c.DisableModelSimplification = not (val as booleanclass)
312					)
313				)
314				"QuantizePos": nw4c.QuantPos = QuantStrToInt val
315				"QuantizeNrm": nw4c.QuantNormal = QuantStrToInt val
316				"QuantizeTex": nw4c.QuantTex = QuantStrToInt val
317				"NonUniformScale": ( --
318					if useNonUniformScale() do
319					(
320						nw4c.NonUniformScale = val as booleanclass
321					)
322				)
323				"MaxReservedUniformRegisters": nw4c.ReservedUniformRegister = val as integer
324				"MeshVisibilityMode":  nw4c.VisibilityBindByName = ((stricmp val "BindByName") == 0)
325				"AdjustSkinning": nw4c.SkinningMode = if (val as booleanclass) then 2 else 1
326
327				"BakeAllAnim": ()
328				"FramePrecision": (
329					local fval = val as float
330					if fval > 0.0 do
331					(
332						local ival = (1.0 / fval) as integer
333						nw4c.AnimPrecision = case of
334						(
335							(ival <= 1): 1
336							(ival <= 2): 2
337							(ival <= 5): 5
338							default: 10
339						)
340					)
341				 )
342				"LoopAnim": nw4c.IsLoop = val as booleanclass
343				"FrameFormat": nw4c.IsFrameFormat = val as booleanclass
344				"BinPrecisionScale": ()--nw4c.PrecisionScale = val as float
345				"BinPrecisionRotate": ()--nw4c.PrecisionRotate = val as float
346				"BinPrecisionTranslate": ()--nw4c.PrecisionTrans = val as float
347				"ScaleQuantizeQuality": nw4c.ScaleQuality = val as integer
348				"RotateQuantizeQuality": nw4c.RotateQuality = val as integer
349				"TranslateQuantizeQuality": nw4c.TransQuality = val as integer
350
351				"ToleranceScale": nw4c.ToleranceScale = val as float
352				"ToleranceRotate": nw4c.ToleranceRotate = val as float
353				"ToleranceTranslate": nw4c.ToleranceTrans = val as float
354				"ToleranceUVScale": nw4c.ToleranceUVScale = val as float
355				"ToleranceUVRotate": nw4c.ToleranceUVRotate = val as float
356				"ToleranceUVTranslate": nw4c.ToleranceUVTrans = val as float
357				"ToleranceColor": nw4c.ToleranceColor= val as float
358
359				"3dsmax_SaveToScene": (
360					 --if isDefault do enableSaveToScene = val as booleanclass
361				 )
362				 "SettingsVersion": (
363					ver = (substituteString val "." "") as integer
364				 )
365				 "GeneratorName": ()
366				 "GeneratorVersion": ()
367				 "Date": ()
368				 default: format "WARNING: unknown key found in c3es(%=%)\n" key val
369			)
370			--detect eof
371			if eof fs do
372			(
373				isEOF = true
374			)
375		)
376
377		return true
378	),
379
380	fn saveSettingToFile filename isDefault:false =
381	(
382		local nw4c = nw4cmax
383		if nw4c == undefined do return false
384		if filename == undefined do return false
385		local fs = openFile filename mode:"wt"
386		if fs == undefined do
387		(
388			format "File Open Error(%)\n" filename
389			return false
390		)
391		outComment fs "NW4C_Export settings"
392		local ver = nw4c.GetVersion()
393		outVersion fs "SettingsVersion" 130
394		local str = "3ds Max "
395		append str (((maxVersion())[1] / 1000 + 1998) as string)
396		append str " NW4C_Export"
397		outValue fs "GeneratorName" str
398		outVersion fs "GeneratorVersion" ver
399		local dt = getLocalTime()
400		local ss = stringStream ""
401		format "%-%-%T%:%:%" dt[1] dt[2] dt[4] dt[5] dt[6] dt[7]  to:ss
402		outValue fs "Date" (ss as string)
403		if isDefault do
404		(
405			--outValue fs "3dsmax_SaveToScene" enableSaveToScene
406		)
407		outReturn fs
408		--
409		outComment fs "Output Options"
410		outValue fs "ExportTarget" (if nw4c.doesExportSelected then "Selection" else "All")
411		outValue fs "OutputFileName" nw4c.filename
412		outValue fs "OutputMode" (
413			if nw4c.UseCreativeStudio then
414			(
415				"CreativeStudio"
416			)
417			else if nw4c.Use3DEditor then
418			(
419				"3DEditor"
420			)
421			else
422			(
423				"File"
424			)
425		)
426		outValue fs "OutputFolder" nw4c.outFolder
427		outValue fs "MergeCmdl" nw4c.UseMerge
428		outValue fs "MergeCmdlPath" nw4c.MergeFilename
429		outValue fs "CopyRelatedFiles" nw4c.CopyMergeRelatedFiles
430		outReturn fs
431		--
432		outComment fs "General Options"
433		outValue fs "Magnify" nw4c.Magnify
434		outValue fs "FrameRange" (if nw4c.doesExportAllFrames then "All" else "Range")
435		outValue fs "StartFrame" nw4c.StartFrame
436		outValue fs "EndFrame" nw4c.EndFrame
437		outValue fs "UseFigureMode" nw4c.useFiguremode
438		outReturn fs
439		--
440		outComment fs "Output File Selection"
441		outValue fs "OutputCmdl" nw4c.doesExportModel
442		outValue fs "OutputCtex" nw4c.doesExportTexture
443		outValue fs "OutputCskla" nw4c.doesExportAnimation
444		outValue fs "OutputCmata" nw4c.doesExportMtlAnim
445		outValue fs "OutputCcam" nw4c.doesExportCamera
446		outValue fs "OutputClgt" nw4c.doesExportLight
447		outValue fs "OutputCenv" nw4c.doesExportEnv
448		outValue fs "OutputCmdla" nw4c.doesExportModelAnim
449		outValue fs "OutputCmcla" nw4c.doesExportMtlColorAnim
450		outValue fs "OutputCmtpa" nw4c.doesExportMtlTexPatternAnim
451		outValue fs "OutputCmtsa" nw4c.doesExportMtlTexSRTAnim
452		outReturn fs
453		--
454		outComment fs "Optimization Options"
455		outValue fs "CompressNode" ( case nw4c.CompressNode of
456			(
457				2: "Cull"
458				3: "CullUninfluential"
459				4: "UniteCompressible"
460				5: "UniteAll"
461				default: "None"
462			)
463		)
464		outValue fs "CompressMaterial" nw4c.OptimizeMaterial
465		outValue fs "OptimizePrimitive" nw4c.OptimizePrimitive
466		outValue fs "ConvertToModel" (not nw4c.DisableModelSimplification)
467		outReturn fs
468		--
469		outComment fs "Quantization Options"
470		outQuantValue fs "QuantizePos" nw4c.QuantPos
471		outQuantValue fs "QuantizeNrm" nw4c.QuantNormal
472		outQuantValue fs "QuantizeTex" nw4c.QuantTex
473		outReturn fs
474		--
475		outComment fs "Model Options"
476		if useNonUniformScale() do outValue fs "NonUniformScale" nw4c.NonUniformScale
477		outValue fs "MaxReservedUniformRegisters" nw4c.ReservedUniformRegister
478		outValue fs "MeshVisibilityMode" ( if nw4c.VisibilityBindByName then "BindByName" else "BindByIndex")
479
480
481		outValue fs "AdjustSkinning" (nw4c.SkinningMode == 2)
482
483		outReturn fs
484		--
485		outComment fs "Animation Options"
486		outValue fs "BakeAllAnim" true
487		outValue fs "FramePrecision" (1.0 / nw4c.AnimPrecision)
488		outValue fs "LoopAnim" nw4c.IsLoop
489		outValue fs "FrameFormat" nw4c.IsFrameFormat
490		--outValue fs "BinPrecisionScale" nw4c.PrecisionScale
491		--outValue fs "BinPrecisionRotate" nw4c.PrecisionRotate
492		--outValue fs "BinPrecisionTranslate" nw4c.PrecisionTrans
493		outValue fs	"ScaleQuantizeQuality"  nw4c.ScaleQuality
494		outValue fs	"RotateQuantizeQuality"  nw4c.RotateQuality
495		outValue fs	"TranslateQuantizeQuality"  nw4c.TransQuality
496		outReturn fs
497		--
498		outComment fs "Tolerance Options"
499		outValue fs "ToleranceScale" nw4c.ToleranceScale
500		outValue fs "ToleranceRotate" nw4c.ToleranceRotate
501		outValue fs "ToleranceTranslate" nw4c.ToleranceTrans
502		outValue fs "ToleranceUVScale" nw4c.ToleranceUVScale
503		outValue fs "ToleranceUVRotate" nw4c.ToleranceUVRotate
504		outValue fs "ToleranceUVTranslate" nw4c.ToleranceUVTrans
505		outValue fs "ToleranceColor" nw4c.ToleranceColor
506
507		close fs
508		return true
509	),
510
511	fn loadSettingConfig =
512	(
513		local fname = GetDir #plugcfg
514		append fname "\\nw4cmax.ini"
515		local val = getINISetting fname "nw4c_exporter" "enableSaveToScene"
516		enableSaveToScene = if val == "false" then false else true
517	),
518
519	fn saveSettingConfig =
520	(
521		local fname = GetDir #plugcfg
522		append fname "\\nw4cmax.ini"
523		setINISetting fname "nw4c_exporter" "enableSaveToScene" (enableSaveToScene as string)
524	),
525
526	fn loadSettingDefault =
527	(
528		local fname = GetDir #plugcfg
529		append fname "\\nw4cmax.c3es"
530		if doesFileExist fname then
531		(
532			loadSettingFromFile fname isDefault:true
533			loadSettingConfig()
534		)
535		else
536		(
537			false
538		)
539	),
540
541	fn saveSettingDefault =
542	(
543		local fname = GetDir #plugcfg
544		append fname "\\nw4cmax.c3es"
545		saveSettingToFile fname isDefault:true
546		saveSettingConfig()
547	)
548)
549
550-- common user data setting
551nw4cEditUserDataRollout_Value = undefined
552nw4cEditUserDataRollout_ValueSet = undefined
553
554rollout nw4cEditUserDataRollout "NW4C Edit User Data" width:320 height:320
555(
556	editText editName "Name" align:#left
557	radioButtons rdoType "Type"  labels:#("String", "Integer", "Float") columns:3 align:#left
558	--label lblString "String" align:#left enabled:false
559	--editText editString "" align:#left
560	label lblNumber "String or Number : (One value per line)" align:#left
561	editText editNumber "" height: 200 align:#left
562	label lbl3 "" across:3
563	button btnOK "Ok" width:80
564	button btnCancel "Cancel" width:80
565
566	fn isValidName n =
567	(
568		if (classof n) != String do return false
569		local c, f = true
570		for i = 1 to n.count while f do
571		(
572			c = n[i]
573			f = false
574			f = f or ("A" <= c and c <= "Z") or ("a" <= c and c <= "z")
575			f = f or ("0" <= c and c <= "9")
576			f = f or (c == "-") or (c == "_") or (c == ".")
577		)
578		if (not f) do
579		(
580			messagebox ("invalid character used in name(" + c + ")")
581			return false
582		)
583		-- find same name
584		local list = nw4cEditUserDataRollout_ValueSet.list
585		for d in list do
586		(
587			if d != nw4cEditUserDataRollout_Value and d.dataname == n do -- �����f�[�^�ւ̎Q�Ƃ͏���
588			(
589				messagebox ("Can't use same name")
590				return false
591			)
592		)
593		return true
594	)
595
596	fn isValidString s =
597	(
598		if (classof s) != String do return false
599		local c, f = true
600		for i = 1 to s.count while f do
601		(
602			c = s[i]
603			f = (c == "<") or (c == ">") or (c == "&") or (c == "'") or (c == "\"")
604			if f do
605			(
606				messagebox ("invalid character used in String(" + c + ")")
607				return false
608			)
609		)
610		return true
611	)
612
613	fn updateView =
614	(
615		if 	(classof nw4cEditUserDataRollout_Value) == nw4c_userData and \
616			(classof nw4cEditUserDataRollout_ValueSet) == nw4c_userDataSet do
617		(
618			local data = nw4cEditUserDataRollout_Value
619			editName.text = data.dataname
620			rdoType.state = case data.type of
621			(
622				Integer: 2
623				Float: 3
624				default: 1 -- string
625			)
626/*			if data.type == String then
627			(
628				editString.text  = if (classof data.val[1]) == String then data.val[1] else ""
629			)
630			else
631*/
632			(
633				local str = ""
634				for i = 1 to data.val.count do
635				(
636					str += (data.val[i] as String) + "\n"
637				)
638				editNumber.text = str
639			)
640		)
641	)
642
643	on nw4cEditUserDataRollout open do
644	(
645		if 	(classof nw4cEditUserDataRollout_Value) == nw4c_userData and \
646			(classof nw4cEditUserDataRollout_ValueSet) == nw4c_userDataSet then
647		(
648			updateView()
649		)
650		else
651		(
652			messagebox "value error"
653			DestroyDialog nw4cEditUserDataRollout
654		)
655	)
656
657	on btnOK pressed do
658	(
659		if (classof nw4cEditUserDataRollout_Value) == nw4c_userData do
660		(
661			local data = nw4c_userData()
662			data.type = case rdoType.state of
663			(
664				2: Integer
665				3: Float
666				default: String
667			)
668			if editName.text.count == 0 do
669			(
670				messagebox "Name is Empty"
671				return()
672			)
673			if (not (isValidName editName.text)) do
674			(
675				return()
676			)
677			data.dataname = editName.text
678
679			local vs = filterString  editNumber.text "\n"
680			if vs.count == 0 do
681			(
682				messagebox "Number is Empty"
683				return()
684			)
685
686			for i = 1 to vs.count do
687			(
688				local v = case data.type of
689				(
690					Integer: (vs[i] as Integer)
691					Float: (vs[i] as Float)
692					default: (vs[i] as String)
693				)
694				if v == undefined do
695				(
696					local mes = "Value is not valid(" + vs[i] + ")"
697					messagebox mes
698					return()
699				)
700				append data.val v
701			)
702			if data.val.count == 0 do
703			(
704				messagebox "Number is Empty"
705				return()
706			)
707			data.copyTo nw4cEditUserDataRollout_Value
708		)
709		DestroyDialog nw4cEditUserDataRollout
710	)
711
712	on btnCancel pressed do
713	(
714		nw4cEditUserDataRollout_Value = undefined
715		DestroyDialog nw4cEditUserDataRollout
716	)
717	on rdoType changed val do
718	(
719/*
720		editString.enabled = (val == 1)
721		lblString.enabled = (val == 1)
722		editNumber.enabled = (val != 1)
723		lblNumber.enabled = (val != 1)
724*/
725		)
726)
727