-
Notifications
You must be signed in to change notification settings - Fork 0
/
ActorXImporter.ms
2371 lines (2079 loc) · 62.9 KB
/
ActorXImporter.ms
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
ActorX mesh (psk) and animation (psa) importer for 3ds Max
Created: September 18 2009
Author: Konstantin Nosov (aka Gildor)
Web page: http://www.gildor.org/projects/unactorx
Revision History:
13.10.2019 v1.38
- implemented loading of vertex colors
28.08.2019 v1.37
- implemented loading of PNG textures
19.05.2018 v1.36
- using case-insensitive comparison when finding bones in scene for animation
06.12.2017 v1.35
- an attempt to make smoothing groups working
- renamed "recurse" option to "look in subfolders" to be less confising to new users
16.10.2017 v1.34
- added possibility to select and open multiple psk files at time
21.07.2015 v1.33
- saving bind pose information inside bone objects, this information will survive saving scene
to a max file
18.07.2015 v1.32
- allowing psa import to work with any mesh, i.e. without previously imported psk file
14.07.2015 v1.31
- trying to detect and repair bad vertex weights for imported psk file
01.02.2015 v1.30
- added animation import option "import at slider position"
- integrated patch by Ayrshi (http://www.gildor.org/smf/index.php/topic,1925.0.html) intended to
improve mesh normals
02.12.2014 v1.29
- ActorX Imported now could be bound to toolbar, keyboard or menu - use "Customize user interface",
category "Gildor Tools", and then use "ActorX Importer" as you like
- reordered controls, separated some options to own rollouts for easy reordering etc
- preserving dialog position, scroll position and rollout "open" state during 3ds Max session (until
Max closed)
28.11.2014 v1.28
- added "mesh translation" options to settings
- "advanced settings" are not stored to the ini file anymore
16.12.2013 v1.27
- added option "Don't conjugate root bone"
10.06.2012 v1.26
- stability improvements
more info: MaxScript documentation, "Do not use return, break, exit or continue"
02.06.2012 v1.25
- fixed Max 2013 support; fix made by sunnydavis, check
http://www.gildor.org/smf/index.php/topic,1408.0.html for details
18.02.2012 v1.24
- fixed parsing psa config file with spaces in track names
07.02.2012 v1.23
- support for extra UV sets stored in standard psk format (ActorX 2010)
23.01.2012 v1.22
- fixed automatic loading of DDS textures for materials
06.12.2011 v1.21
- fixed "translation mode" checkbox to work with psa without config file
01.12.2011 v1.20
- implemented loading of DDS textures
26.11.2011 v1.19
- implemented support for loading pskx files with more than 64k vertices
- added option to control behaviour of animation with rotation-only tracks: you can let AnimSet
to decide which bones will use animated translation, you can force to use translation from the
animation (old, pre-1.18 behaviour) or force to not use animated translation at all; the option
is located in "Animation import" group
09.11.2011 v1.18
- implemented support for animation tracks without translation keys
- reading extended psa information from the .config file, removed psax ANIMFLAGS section support
06.11.2011 v1.17
- eliminated error messages when loading psk or psa file with unknown section name (SCALEKEYS etc)
- implemented support for pskx with 2 or more UV channels
03.05.2011 v1.16
- improved animation cleanup
01.01.2011 v1.15
- workaround for loading animation with the root bone name different than mesh root bone
- removed "Load confirmation" setting (not needed anymore because of functional "batch export")
29.12.2010 v1.14
- added "Batch export" tool
22.12.2010 v1.13
- mesh rotation formula is now identical to used in UnrealEd
- added "Clear scene" tool
15.12.2010 v1.12
- added mesh rotation settings
- added protection from errors appeared when updating this script while 3ds Max is running
09.09.2010 v1.11
- added "reorient bones" option
23.07.2010 v1.10
- implemented extended ActorX format (pskx and psax) support
- "tools" rollout with options to restore mesh bindpose and remove animations
24.04.2010 v1.09
- applying normalmap using correct technique (previously was a bumpmap)
14.04.2010 v1.08
- fixed loading of psk files with root bone parent set to -1 (usually it is 0)
20.02.2010 v1.07
- added "Load confirmation" setting to display message box after completion of operation
- added "Reposition existing bones" option
- fixed error when loading .mat files with missing textures
12.12.2009 v1.06
- fixed merging meshes on a single skeleton when previously loaded mesh is not in bind
pose
- improved compatibility with Epic's ActorX Exporter (dropping trailing spaces from
bone names)
18.09.2009 v1.05
- implemented materal loading
- fixing duplicate bone names
29.09.2009 v1.04
- implemented support for loading non-skeletal (static) meshes
26.09.2009 v1.03
- fixed bug with interpolation between first two animation keyframes
- option to fix animation looping (duplicate first animation frame after last frame)
- added button to load all animations from psa file
- progress bar for loading animation with "cancel" capabilities
- option to not load mesh skin (load skeleton only)
- storing last used directory separately for psk and psa
25.09.2009 v1.02
- added option to scale mesh and animations when loading
- added options for texture search (path, recursive search)
- added option to ask for missing texture files when mesh is loading
24.09.2009 v1.01
- fixed bug in a vertex weighting code
- saving settings to ActorXImporter.ini (Max 9 and higher)
- saving last used psk/psa directory
- settings to change bone size for a new mesh
22.09.2009 v1.00
- first public release
*/
/*
TODO:
- option to create separate materials, not submaterials
- do not create material when it is already exists - but how to find whether I need to get loaded material
or create a new one?
*/
/*
NOTES:
- setBoneEnable false 0:
This call is required. Without it, we will have numerous problems with imported skeleton. Note that FBX
importer will enable "bones" mode, however we can't use it in Max. Why "bone" mode could be useful: hiding
bones could not hide the skeleton when bones are off, and works well when they are on. Why "bone" mode should
be disabled - otherwise we've got problems with rotation/moving of particular bones, they behave like
connected objects. Also saw a bug with imported animation with "force AnimSet translation" - mesh could became
bronen in parts, but began to behave well when unlinked child bone of bad bone and relinked it back. So it's
easier to disable bone mode than to fight against all the bugs.
*/
-- constant used to detect ActorX Importer updates during single 3ds Max session
global AX_IMPORTER_VERSION = 138
g_axProfile = false
-------------------------------------------------------------------------------
-- Global variables
-------------------------------------------------------------------------------
global g_seeThru
global g_skelOnly
global g_updateTime
global g_playAnim
global g_animAtSlider
global g_animTransMode -- 1 = from AnimSet, 2 = force mesh translation, 3 = force AnimSet translation
global g_fixLooping
global g_lastDir1
global g_lastDir2
global g_texDir
global g_texRecurse
global g_texMissAction
global g_boneSize
global g_reposBones
global g_rotY
global g_rotP
global g_rotR
global g_transX
global g_transY
global g_transZ
global g_meshScale
global g_reorientBones
global g_dontConjugateRoot
global Anims -- array of AnimInfoBinary
-------------------------------------------------------------------------------
-- Default settings
-------------------------------------------------------------------------------
fn axDefaultSettings =
(
-- defaults settings
g_seeThru = false
g_skelOnly = false
g_updateTime = true
g_playAnim = false
g_animAtSlider = false
g_animTransMode = 1
g_fixLooping = false
g_lastDir1 = ""
g_lastDir2 = ""
g_texDir = ""
g_texRecurse = true
g_texMissAction = 1
g_boneSize = 0.5
g_reposBones = true
g_rotY = 0
g_rotP = 0
g_rotR = 0
g_transX = 0
g_transY = 0
g_transZ = 0
g_meshScale = 1.0
g_reorientBones = false
g_dontConjugateRoot = false
)
-------------------------------------------------------------------------------
-- Configuration
-------------------------------------------------------------------------------
configFile = undefined
if getSourceFileName != undefined then -- checking Max version (Max9+) ...
(
local s = getSourceFileName()
configFile = (getFilenamePath s) + (getFilenameFile s) + ".ini"
)
else
(
-- workaround for Max 8 and older
configFile = (getDir #scripts) + "\ActorXImporter.ini"
)
tmp_v = undefined -- global variable, helper for axDoSetting() (required for execute() ...)
g_isLoading = true -- axDoSetting() mode
fn axDoSetting name var =
(
local default = execute var -- value has the same type as var
if g_isLoading then
(
try
(
-- loading value
tmp_v = getINISetting configFile "Main" name -- get from ini as string
if (tmp_v != "") and (tmp_v != "undefined") then
(
local type = classOf default
-- format "reading % (%) = %\n" var type tmp_v
if (not isKindOf default String) then
execute (var + "=tmp_v as " + (type as string))
else
execute (var + "=tmp_v") -- no conversion
)
)
catch
(
format "Reading %: %\n" name (getCurrentException())
)
)
else
(
-- saving value
setINISetting configFile "Main" name (default as string)
)
)
fn axSerializeSettings isLoading =
(
if configFile == undefined then return undefined -- could happen with old 3ds Max, where getSourceFileName() doesn't exist
if isLoading then
(
if not doesFileExist configFile then return undefined -- no config file
)
g_isLoading = isLoading
-- read/write settings
axDoSetting "LastUsedDir" "g_lastDir1"
axDoSetting "LastUsedDir2" "g_lastDir2"
axDoSetting "TexturesDir" "g_texDir"
axDoSetting "TexRecurse" "g_texRecurse"
axDoSetting "TexMissAction" "g_texMissAction"
axDoSetting "AutoPlayAnim" "g_playAnim"
axDoSetting "AnimAtSlider" "g_animAtSlider"
axDoSetting "AnimTransMode" "g_animTransMode"
axDoSetting "UpdateTime" "g_updateTime"
axDoSetting "FixLoopAnim" "g_fixLooping"
axDoSetting "SeeThru" "g_seeThru"
axDoSetting "SkelOnly" "g_skelOnly"
axDoSetting "BoneSize" "g_boneSize"
axDoSetting "ReposBones" "g_reposBones"
axDoSetting "MeshYaw" "g_rotY"
axDoSetting "MeshPitch" "g_rotP"
axDoSetting "MeshRoll" "g_rotR"
axDoSetting "MeshX" "g_transX"
axDoSetting "MeshY" "g_transY"
axDoSetting "MeshZ" "g_transZ"
axDoSetting "MeshScale" "g_meshScale"
-- axDoSetting "ReorientBones" "g_reorientBones"
-- axDoSetting "DontConjRoot" "g_dontConjugateRoot"
)
-------------------------------------------------------------------------------
-- Service functions
-------------------------------------------------------------------------------
fn ErrorMessage text =
(
local msg = ("ERROR: " + text + "\n")
format "%\n" msg
messageBox msg
throw msg
)
fn TrimSpaces text =
(
trimLeft(trimRight(text))
)
fn IsEndOfFile bstream =
(
local savePos = ftell bstream
fseek bstream 0 #seek_end -- compute file size
local fileSize = ftell bstream
fseek bstream savePos #seek_set
(savePos >= fileSize)
)
fn ReadFixedString bstream fixedLen =
(
local str = ""
local length = 0
local finished = false
for i = 1 to fixedLen do
(
local c = ReadByte bstream #unsigned
if c == 0 then finished = true -- end of line char
if not finished then -- has end of line before - skip remaining chars
(
-- not "finished" string
str += bit.intAsChar(c) -- append a character
if c != 32 then length = i -- position of last non-space char
)
)
substring str 1 length -- return first "length" chars
)
fn ReadVector2 bstream =
(
local v = point2 0 0
v.x = ReadFloat bstream
v.y = ReadFloat bstream
v
)
fn ReadFVector bstream =
(
local v = point3 0 0 0
v.x = ReadFloat bstream
v.y = ReadFloat bstream
v.z = ReadFloat bstream
v
)
fn ReadFQuat bstream =
(
local q = quat 0 0 0 0
q.x = ReadFloat bstream
q.y = ReadFloat bstream
q.z = ReadFloat bstream
q.w = ReadFloat bstream
q
)
-- Function used to determine bone length
fn axFindFirstChild boneArray boneIndex =
(
local res = undefined, notfound = true
for i = 1 to boneArray.count while notfound do
(
if (i != boneIndex) then
(
bn = boneArray[i]
if bn.ParentIndex == boneIndex-1 then
(
res = bn
notfound = false
)
)
)
res
)
fn axFixBoneNames boneArray =
(
-- Find and correct duplicate names
for i = 1 to (boneArray.count-1) do
(
local n = boneArray[i].Name
local dupCount = 1
for j = (i+1) to boneArray.count do
(
local n2 = boneArray[j].Name
if n == n2 then
(
dupCount += 1
n2 = n + "_" + (dupCount as string)
format "Duplicate bone name \"%\", renamed to \"%\"\n" n n2
boneArray[j].Name = n2
)
)
)
)
fn axFindFile path filename recurse:false =
(
local res = undefined
local check = path + "\\" + filename
if doesFileExist check then
(
res = check
)
else if recurse then
(
local dirs = getDirectories (path + "/*")
local notfound = true
for dir in dirs while notfound do
(
res = axFindFile dir filename recurse:true
if res != undefined then
(
notfound = false -- break the loop
)
)
)
res
)
fn axGetRootMatrix =
(
local angles = eulerAngles g_rotR -g_rotP -g_rotY
local m = angles as matrix3
m.translation = [g_transX, g_transY, g_transZ]
m
)
-- Reference: https://forums.autodesk.com/t5/3ds-max-programming/getopenfilename-for-multiple-files/td-p/4097903
fn getMultiOpenFilenames caption: "Open" filename: "" types: "All Files (*.*)|*.*" default: 1 =
(
local dlg = DotNetObject "System.Windows.Forms.OpenFileDialog"
dlg.multiSelect = true
dlg.title = caption
local p = getFilenamePath filename
if doesFileExist p then
dlg.initialDirectory = p
-- MAXScript getOpenFilename uses trailing |;
-- OpenFileDialog filter does not.
if types == "|" then
dlg.filter = (substring types 1 (types.count - 1))
else
dlg.filter = types
dlg.filterIndex = default
local result = dlg.ShowDialog()
if (result.Equals result.OK) then
dlg.filenames
else
undefined
)
g_axProfileBeginTime = 0
fn axBeginProfile =
(
g_axProfileBeginTime = timeStamp()
)
fn axProfilePoint title debug:false =
(
if (not debug or g_axProfile) then
(
local current = timeStamp()
local delta = current - g_axProfileBeginTime
g_axProfileBeginTime = current
format "% took % s\n" title (delta/1000.0)
)
)
-------------------------------------------------------------------------------
-- ActorX data structures
-------------------------------------------------------------------------------
struct VChunkHeader
(
ChunkID,
TypeFlag,
DataSize,
DataCount
)
fn ReadChunkHeader bstream =
(
local hdr = VChunkHeader ()
hdr.ChunkID = ReadFixedString bstream 20
hdr.TypeFlag = ReadLong bstream #unsigned
hdr.DataSize = ReadLong bstream #unsigned
hdr.DataCount = ReadLong bstream #unsigned
-- format "Read chunk header: %\n" hdr
hdr
)
struct VVertex
(
PointIndex,
U, V,
MatIndex,
Reserved,
Pad
)
fn ReadVVertex bstream =
(
local v = VVertex ()
local pad
v.PointIndex = ReadShort bstream #unsigned
pad = ReadShort bstream
v.U = ReadFloat bstream
v.V = ReadFloat bstream
v.MatIndex = ReadByte bstream #unsigned
v.Reserved = ReadByte bstream #unsigned
v.Pad = ReadShort bstream #unsigned
v
)
fn ReadVVertex32 bstream =
(
local v = VVertex ()
v.PointIndex = ReadLong bstream #unsigned -- short -> long, no "pad"
v.U = ReadFloat bstream
v.V = ReadFloat bstream
v.MatIndex = ReadByte bstream #unsigned
v.Reserved = ReadByte bstream #unsigned
v.Pad = ReadShort bstream #unsigned
v
)
struct VTriangle
(
Wedge0, Wedge1, Wedge2,
MatIndex,
AuxMatIndex,
SmoothingGroups
)
fn ReadVTriangle bstream =
(
local v = VTriangle ()
v.Wedge0 = ReadShort bstream #unsigned
v.Wedge1 = ReadShort bstream #unsigned
v.Wedge2 = ReadShort bstream #unsigned
v.MatIndex = ReadByte bstream #unsigned
v.AuxMatIndex = ReadByte bstream #unsigned
v.SmoothingGroups = ReadLong bstream #unsigned
v
)
fn ReadVTriangle32 bstream =
(
local v = VTriangle ()
v.Wedge0 = ReadLong bstream #unsigned -- short -> long
v.Wedge1 = ReadLong bstream #unsigned -- ...
v.Wedge2 = ReadLong bstream #unsigned -- ...
v.MatIndex = ReadByte bstream #unsigned
v.AuxMatIndex = ReadByte bstream #unsigned
v.SmoothingGroups = ReadLong bstream #unsigned
v
)
struct VMaterial
(
MaterialName,
TextureIndex,
PolyFlags,
AuxMaterial,
AuxFlags,
LodBias,
LodStyle
)
fn ReadVMaterial bstream =
(
local m = VMaterial ()
m.MaterialName = ReadFixedString bstream 64
m.TextureIndex = ReadLong bstream #unsigned
m.PolyFlags = ReadLong bstream #unsigned
m.AuxMaterial = ReadLong bstream #unsigned
m.AuxFlags = ReadLong bstream #unsigned
m.LodBias = ReadLong bstream
m.LodStyle = ReadLong bstream
m
)
struct VColor
(
R, G, B, A
)
fn ReadVColor bstream =
(
local c = VColor ()
c.R = ReadByte bstream #unsigned
c.G = ReadByte bstream #unsigned
c.B = ReadByte bstream #unsigned
c.A = ReadByte bstream #unsigned
c
)
struct VBone
(
Name,
Flags,
NumChildren,
ParentIndex,
-- VJointPos
Orientation,
Position,
Length,
Size,
-- Computed data
Matrix
)
fn ReadVBone bstream =
(
local b = VBone ()
b.Name = ReadFixedString bstream 64
b.Flags = ReadLong bstream #unsigned
b.NumChildren = ReadLong bstream
b.ParentIndex = ReadLong bstream
b.Orientation = ReadFQuat bstream
b.Position = ReadFVector bstream
b.Length = ReadFloat bstream
b.Size = ReadFVector bstream
b
)
struct VRawBoneInfluence
(
Weight,
PointIndex,
BoneIndex
)
fn ReadVRawBoneInfluence bstream =
(
local v = VRawBoneInfluence ()
v.Weight = ReadFloat bstream
v.PointIndex = ReadLong bstream #unsigned
v.BoneIndex = ReadLong bstream #unsigned
v
)
fn InfluenceSort v1 v2 =
(
-- we just need to get influences sorted by vertex index
local cmp = v1.PointIndex - v2.PointIndex
-- add bone index sorting for sort stability
if (cmp == 0) then cmp = v1.BoneIndex - v2.BoneIndex
cmp
)
struct AnimInfoBinary
(
Name,
Group,
TotalBones,
RootInclude,
KeyCompressionStyle,
KeyQuotum,
KeyReduction,
TrackTime,
AnimRate,
StartBone,
FirstRawFrame,
NumRawFrames
)
fn ReadAnimInfoBinary bstream =
(
v = AnimInfoBinary ()
v.Name = ReadFixedString bstream 64
v.Group = ReadFixedString bstream 64
v.TotalBones = ReadLong bstream
v.RootInclude = ReadLong bstream
v.KeyCompressionStyle = ReadLong bstream
v.KeyQuotum = ReadLong bstream
v.KeyReduction = ReadFloat bstream
v.TrackTime = ReadFloat bstream
v.AnimRate = ReadFloat bstream
v.StartBone = ReadLong bstream
v.FirstRawFrame = ReadLong bstream
v.NumRawFrames = ReadLong bstream
v
)
struct VQuatAnimKey
(
Position,
Orientation,
Time
)
fn ReadVQuatAnimKey bstream =
(
local k = VQuatAnimKey ()
k.Position = ReadFVector bstream
k.Orientation = ReadFQuat bstream
k.Time = ReadFloat bstream
k
)
-------------------------------------------------------------------------------
-- Bone attributes
-------------------------------------------------------------------------------
AXBoneCustomDataDef = attributes AXBoneCustomData
attribID:#(0xF3DD7FCD, 0x4DB58449)
(
parameters BindPose
(
AX_RelMatrix type: #matrix3 -- matrix relative to parent bone
AX_WorldMatrix type: #matrix3 -- world matrix
)
)
-------------------------------------------------------------------------------
-- Loading materials
-------------------------------------------------------------------------------
fn axFindTexture texDir baseName =
(
-- DDS
foundTex = axFindFile texDir (baseName + ".dds") recurse:g_texRecurse
if foundTex == undefined then
(
-- TGA
foundTex = axFindFile texDir (baseName + ".tga") recurse:g_texRecurse
if foundTex == undefined then
(
-- PNG
foundTex = axFindFile texDir (baseName + ".png") recurse:g_texRecurse
)
)
foundTex
)
fn axImportMaterial matName texDir =
(
local subMat = standardMaterial name:matName
local texFilename
local foundTex
-- try to file material file
texFilename = matName + ".mat"
foundTex = axFindFile texDir texFilename recurse:g_texRecurse
if foundTex != undefined then
(
texFilename = foundTex
format "Loading material %\n" texFilename
local matFile = openFile texFilename
while eof matFile == false do
(
local line = readline matFile
local tok = filterString line " ="
-- format "[%] = [%]\n" tok[1] tok[2]
local parm = tok[1]
local file = tok[2]
foundTex = axFindTexture texDir file
if foundTex == undefined then continue
local bitmap = bitmapTexture name:foundTex fileName:foundTex
if parm == "Normal" then
(
local normalMap = normal_bump name:foundTex normal_map:bitmap
subMat.bumpMap = normalMap
subMat.bumpMapAmount = 100 -- amount is set to 30 by default
)
else
(
if parm == "Diffuse" then subMat.diffuseMap = bitmap
if parm == "Specular" then subMat.specularMap = bitmap
if parm == "SpecPower" then subMat.specularLevelMap = bitmap
if parm == "Opacity" then subMat.opacityMap = bitmap
if parm == "Emissive" then subMat.selfIllumMap = bitmap
)
)
close matFile
return subMat
)
-- no material file found, try simple texture
-- get texture filename
texFilename = matName
foundTex = axFindTexture texDir matName
if foundTex != undefined then
(
texFilename = foundTex
)
else
(
if g_texMissAction == 2 then -- ask
(
local check = getOpenFileName caption:("Get texture for material " + matName) \
types:"Texture files (*.tga,*.dds,*.png)|*.tga;*.dds;*.png|All (*.*)|*.*|" filename:texFilename
if check != undefined then texFilename = check
)
)
if not doesFileExist texFilename then format "Unable to find texture %\n" texFilename
-- continue setup (even in a case of error)
local bitmap = bitmapTexture name:texFilename fileName:texFilename
subMat.diffuseMap = bitmap
-- return
subMat
)
-------------------------------------------------------------------------------
-- MAX helpers
-------------------------------------------------------------------------------
fn FindAllBones_Recurse bones parent =
(
for i = 1 to parent.children.count do
(
node = parent.children[i]
if isKindOf node BoneObj then
(
append bones node
)
FindAllBones_Recurse bones node
)
)
fn FindAllBones =
(
local bones = #()
FindAllBones_Recurse bones rootNode
bones
)
fn RemoveAnimation =
(
stopAnimation()
bones = FindAllBones()
for i = 1 to bones.count do
(
b = bones[i]
deleteKeys b #allKeys
)
animationRange = interval 0 1
)
fn RestoreBindpose =
(
RemoveAnimation()
try
(
local rotMatrix = axGetRootMatrix()
-- note: should rotate every bone because we are not applying parent's rotation here
-- find bones
bones = FindAllBones()
for i = 1 to bones.count do
(
b = bones[i]
data = custAttributes.get b AXBoneCustomDataDef
if data != undefined then
(
b.transform = data.AX_WorldMatrix * rotMatrix
)
-- else
-- (
-- format "no info for %\n" b.name
-- )
)
set coordsys world
)
catch
(
format "ERROR!\n"
)
)
fn ClearMaxScene =
(
max select all
if $ != undefined then delete $
)
-------------------------------------------------------------------------------
-- Loading PSK file
-------------------------------------------------------------------------------
fn ImportPskFile filename skelOnly:false =
(
set coordsys world
local Verts = #()
local Wedges = #()
local Tris = #()
local Materials = #()
local MeshBones = #()
local Infs = #()
local Colors = #()
--------- Read the file ---------
local numVerts = 0
local numWedges = 0
local numTris = 0
local numMaterials = 0
local numBones = 0
local numInfluences = 0
local numVertColors = 0
local numTexCoords = 1
local extraUV = #()
axBeginProfile()
try
(
file = fopen filename "rb"
if file == undefined then return undefined
-- First header --
hdr = ReadChunkHeader file
if (hdr.ChunkID != "ACTRHEAD") then
(
ErrorMessage("Bad chunk header: \"" + hdr.ChunkID + "\"")
)
while not IsEndOfFile(file) do
(
hdr = ReadChunkHeader file