View difference between Paste ID: CTcStn1j and
SHOW: | | - or go back to the newest paste.
1-
1+
#!BPY
2
3
#**************************************************************************************************
4
# Supreme Commander Importer for Blender3D - www.blender3d.org
5
#
6
# Written by dan - www.sup-com.net
7
# modified by Gniarf (2010/08)
8
#
9
# History
10
#   0.1.0   06/06/06   - Initial version. 
11
#   0.2.0   06/06/10   - Added SCA (Animation) support
12
#   0.3.0   06/07/02   - Alpha release
13
#   0.4.0   10/08/12   - modification to load Supcom2 sca won't load Supcom 1 sca anymore
14
#
15
# Todo
16
#   - Material/uv map 2
17
#   - Bone pos/rot for scm & sca. Not perfect to use gentle words.
18
#   - Make sca loading independent of the scm_mesh. (e.g get bone pos/loc from armature instead)
19
#   - GUI for loading
20
#
21
#**************************************************************************************************
22
23
"""
24
Name: 'SupCom2 Model (.scm)'
25
Blender: 232
26
Group: 'Import'
27
Tooltip: 'Imports Supreme Commander 2 Models (*.scm) and Animations (*.sca)'
28
"""
29
30
import Blender
31
from Blender import NMesh, Scene, Object
32
33
from Blender import Mathutils
34
from Blender.Mathutils import *
35
36
from Blender.BGL import *
37
from Blender import Draw
38
from Blender.Draw import *
39
40
import os
41
from os import path
42
43
44
import struct
45
import string
46
import math
47
from math import *
48
49
50
VERSION = '4.5'
51
52
######################################################
53
# User defined behaviour, Select as you need
54
######################################################
55
56
#Enable Progress Bar ( 0 = faster )
57
PROG_BAR_ENABLE = 1
58
#how many steps a progress bar has (the lesser the faster)
59
PROG_BAR_STEP = 25
60
61
#LOG File for debuging
62
#Enable LOG File (0 = Disabled , 1 = Enabled )
63
LOG_ENABLE = 0
64
#Filename / Path. Default is blender directory Filename SC-E_LOG.txt
65
LOG_FILENAME = "SC-E_LOG.txt"
66
67
######################################################
68
# Init Supreme Commander SCM( _bone, _vertex, _mesh), SCA(_bone, _frame, _anim) Layout
69
######################################################
70
#xy_to_xz_transform = Matrix([1, 0, 0], [ 0, 0, 1], [ 0, 1, 0])
71
xy_to_xz_transform = Matrix([1, 0, 0], [ 0, 0, 1], [ 0, -1, 0])
72
73
74
	#	-1	0	0
75
	#	0	0	1
76
	#	0	1	0
77
78
79
class scm_bone :
80
	
81
	name = ""
82
	rel_mat = []
83
	rel_mat_inv = []
84
	position = []
85
	rotation = []
86
	parent = 0
87
	parent_index = 0
88
	
89
	rel_matrix_inv = []
90
	
91
	def __init__(self, name):
92
		self.name = name
93
		self.rel_mat_inv = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
94
		self.rel_mat = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
95
		self.rotation = Quaternion(0,0,0,0)
96
		self.position = Vector(0,0,0)
97
98
	def load(self, file):
99
		bonestruct = '16f3f4f4i'
100
		buffer = file.read(struct.calcsize(bonestruct))
101
		readout = struct.unpack(bonestruct, buffer)
102
103
		#supcom information:
104
		readRPI = Matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
105
		#// Inverse transform of the bone relative to the local origin of the mesh
106
		#// 4x4 Matrix with row major (i.e. D3D default ordering)
107
		for i in range(4):
108
			readRPI[i] = readout[i*4:i*4+4]
109
		
110
		self.rel_mat_inv = Matrix(readRPI[0], readRPI[1], readRPI[2], readRPI[3])#*xy_to_xz_transform #note rot here changes pointing direction of spikie 
111
		self.rel_mat = self.rel_mat_inv.invert()
112
113
		#self.rel_mat = (Matrix(rest_pose_inv).invert()) 
114
115
		#// Position relative to the parent bone.
116
		pos = readout[16:19]
117
		self.position = Vector(pos[0], pos[1], pos[2])
118
		
119
		#// Rotation relative to the parent bone.
120
		rot = readout[19:23]
121
		self.rotation = Quaternion( rot[0], rot[1], rot[2], rot[3] )
122
123
		#// Index of the bone's parent in the SCM_BoneData array
124
		self.parent_index = readout[24]
125
126
		
127
		return self
128
	
129
	def dump(self):
130
		print 'Bone       ', self.name
131
		print 'Position   ', self.position
132
		print 'Rotation   ', self.rotation
133
		print 'Parent Idx ', self.parent_index		
134
		if (self.parent != 0): 
135
			print 'Parent     ', self.parent.name
136
		else:
137
			print 'Parent     <NONE>'		
138
		print 'Rest Pose Inv.'
139
		#for row in range(4):
140
			#print '  ', self.rest_pose_inv[row]		
141
142
143
class scm_vertex :
144
	
145
	position = []
146
	tangent = []
147
	normal = []
148
	binormal = []
149
	uv1 = []
150
	uv2 = []
151
	bone_index = []
152
153
	def __init__(self):
154
		self.position 	= Vector(0,0,0)
155
		self.tangent 	= Vector(0,0,0)
156
		self.normal 	= Vector(0,0,0)
157
		self.binormal 	= Vector(0,0,0)
158
		self.uv1 	= Vector(0,0)
159
		self.uv2 	= Vector(0,0)
160
		self.bone_index = [0]*4
161
162
	def load(self, file):
163
		
164
		vertstruct = '3f3f3f3f2f2f4B'
165
		vertsize = struct.calcsize(vertstruct)
166
		
167
		
168
		buffer = file.read(vertsize)
169
		vertex = struct.unpack(vertstruct, buffer)
170
		
171
		self.position = vertex[0:3]
172
		self.tangent = vertex[3:6]
173
		self.normal = vertex[6:9]
174
		self.binormal = vertex[9:12]
175
		self.uv1 = vertex[12:14]
176
		self.uv2 = vertex[14:16]
177
		self.bone_index = vertex[16:20]
178
		return self
179
	
180
	def dump(self):
181
		print 'position ', self.position
182
		print 'tangent  ', self.tangent
183
		print 'normal   ', self.normal
184
		print 'binormal ', self.binormal
185
		print 'uv1      ', self.uv1
186
		print 'uv2      ', self.uv2
187
		print 'bones    ', self.bone_index
188
189
190
class scm_mesh :
191
	
192
	bones = []
193
	vertices = []
194
	faces = []
195
	info = []
196
	filename = ""
197
	
198
	def __init__(self):
199
		self.bones = []
200
		self.vertices = []
201
		self.faces = []
202
		self.info = []
203
		self.filename = ""
204
205
	def load(self, filename):	
206
		global xy_to_xz_transform
207
		self.filename = filename
208
		scm = file(filename, 'rb')
209
		
210
		# Read header
211
		headerstruct = '4s11L'
212
		buffer = scm.read(struct.calcsize(headerstruct))
213
		header = struct.unpack(headerstruct, buffer)
214
		
215
		marker = header[0]
216
		version = header[1]
217
		boneoffset = header[2]
218
		bonecount = header[3]
219
		vertoffset = header[4]
220
		extravertoffset = header[5]
221
		vertcount = header[6]
222
		indexoffset = header[7]
223
		indexcount = header[8]
224
		tricount = indexcount / 3 #?
225
		infooffset = header[9]
226
		infocount = header[10]
227
		totalbonecount = header[11]
228
		
229
		if (marker != 'MODL'):
230
			print 'Not a valid scm'
231
			return
232
			
233
		#if (version != 5):
234
		#	print 'Unsupported version (%d)' % version
235
		#	return
236
		
237
		# Read bone names
238
		scm.seek(pad(scm.tell()), 1)
239
		length = (boneoffset - 4) - scm.tell()
240
241
		# This should probably be handeled by the scm_bone reader as it contains the nameoffset. But I'm lazy
242
		# and logic tells me it's written in the same order as the bones.
243
		buffer = scm.read(length)		
244
		rawnames = struct.unpack(str(length)+'s',buffer)		
245
		bonenames = string.split(rawnames[0],'\0')[:-1]
246
		
247
		# Read bones
248
		scm.seek(boneoffset, 0)
249
		for b in range(0, totalbonecount):
250
			bone = scm_bone(bonenames[b])
251
			bone.load(scm) 			
252
			self.bones.append(bone)
253
				
254
		#show them (for debug)				
255
		#for b in range(0, totalbonecount):
256
			#print "bone %d has %d children = " %(b, self.bones[b].numchildren)
257
		
258
		# Set parent (this could probably be done in the other loop since parents are usually written to the file
259
		# before the children. But you never know..
260
		for bone in self.bones:
261
			if (bone.parent_index != -1):
262
				bone.parent = self.bones[bone.parent_index]
263
			else:
264
				bone.parent = 0
265
		
266
			# the bone matrix relative to the parent.
267
			if (bone.parent != 0):
268
				mrel = (bone.rel_mat) * Matrix(bone.parent.rel_mat).invert() #* xy_to_xz_transform
269
				bone.rel_matrix_inv = Matrix(mrel).invert()
270
			else:
271
				mrel = bone.rel_mat * xy_to_xz_transform  #there is no parent
272
				bone.rel_matrix_inv = Matrix(mrel).invert()
273
						
274
		
275
		# Read vertices
276
		scm.seek(vertoffset, 0)
277
		for b in range(0, vertcount):
278
			vert = scm_vertex()
279
			vert.load(scm)			
280
			self.vertices.append(vert)
281
		
282
		# Read extra vertex data		
283
		# Not implemented in Sup Com 1.0!
284
		
285
		# Read indices (triangles)
286
		tristruct = '3h'
287
		trisize = struct.calcsize(tristruct)
288
			
289
		scm.seek(indexoffset, 0)			
290
		for t in range(tricount):			
291
			buffer = scm.read(trisize)
292
			face = struct.unpack(tristruct, buffer)
293
			self.faces.append(list(face))
294
			
295
		
296
		# Read info
297
		if (infocount > 0):
298
			scm.seek(infooffset)
299
			buffer = scm.read()
300
			rawinfo = struct.unpack(str(len(buffer))+'s',buffer)		
301
			self.info = string.split(rawinfo[0],'\0')[:-1]
302
		
303
		scm.close()	
304
		
305
		return self
306
307
	def dump(self):
308
		print ''
309
		print 'Filename: ', self.filename
310
		print 'Bones ', len(self.bones)
311
		print 'Verts ', len(self.vertices)
312
		print 'Faces ', len(self.faces)		
313
		print ''
314
		print 'INFO: '
315
		for info in self.info:
316
			print '  ', info
317
		
318
319
320
class sca_bone:
321
322
	position = []
323
	rotation = []
324
	#changed: rototation -> rotation
325
	pose_pos = []
326
	pose_rot = []
327
328
	def __init__(self, pos, rot):
329
		self.position = pos
330
		self.rotation = rot
331
332
333
	def dump(self):
334
		print 'Position ', self.position
335
		print 'Rotation ', self.rotation
336
		
337
338
339
class sca_frame:
340
341
	keytime = 0.0
342
	bones = []
343
	anim = None
344
	
345
	def __init__(self, anim):
346
		self.keytime = 0.0
347
		self.bones = []
348
		self.anim = anim
349
350
	def load(self, file):		
351
		frameheader_fmt = 'f'
352
		frameheader_size = struct.calcsize(frameheader_fmt)
353
		buffer = file.read(frameheader_size)
354
		
355
		(self.keytime,) = struct.unpack(frameheader_fmt, buffer)
356
		
357
		posrot_fmt = '3f4f'
358
		posrot_size = struct.calcsize(posrot_fmt)
359
		
360
		buffer = file.read(posrot_size)
361
		posrot = struct.unpack(posrot_fmt, buffer)			
362
		bone = sca_bone([posrot[4],posrot[5],posrot[6]], [posrot[0],posrot[1],posrot[2],posrot[3]])
363
		self.bones.append(bone)
364
365
	def dump(self):
366
		print 'Time  ', self.keytime
367
		
368
369
370
class sca_anim :
371
	
372
	filename = ""
373
	frames = [[]]
374
	bones = []
375
	bonelinks = []
376
	bonenames = []
377
	numbones = 0
378
	duration = 0.0
379
	numframes = 0
380
	
381
	def __init__(self):
382
		self.filename = ""
383
		self.frames=list()
384
		self.bones = []
385
		self.numbones = 0
386
		self.bonelinks = []
387
		self.bonenames = list()
388
		self.duration = 0.0
389
390
	def read_bone_name(self,sca):
391
		bone_name=""
392
		letter=""
393
		while letter!='\0':
394
			bone_name=bone_name+letter
395
			letter=sca.read(1)
396
		return bone_name
397
398
	def load(self, filename):
399
		self.filename = filename
400
		sca = file(filename, 'rb')
401
		
402
		# Read header
403
		headerstruct = '4sllflllll'
404
		buffer = sca.read(struct.calcsize(headerstruct))
405
		header = struct.unpack(headerstruct, buffer)
406
		
407
		
408
		(magic,             \
409
		 version,           \
410
		 self.numframes,         \
411
		 self.duration,     \
412
		 self.numbones,     \
413
		 namesoffset,       \
414
		 linksoffset,       \
415
		 animoffset,        \
416
		 framesize) = struct.unpack(headerstruct, buffer)
417
		 
418
		#namesoffset,linksoffset,animoffset are NOT always
419
		#reliable, so use data alignment instead
420
		
421
		if (magic != 'ANIM'):
422
			print 'Not a valid .sca animation file'
423
			return
424
		
425
		#if (version != 5):
426
		#	print 'Unsupported sca version: %d'  % version
427
		#	return
428
		
429
		#Read bone names
430
		# go to next section (names)
431
		token_found=0
432
		while (token_found==0):
433
			sca.seek(28-(sca.tell()%32), os.SEEK_CUR )
434
			magic = sca.read(4)
435
			if (magic=='NAME'):
436
				token_found=1
437
			else:
438
				sca.seek(8, os.SEEK_CUR )
439
				
440
		
441
		for i in range(0,self.numbones):
442
			self.bonenames.append(self.read_bone_name(sca))
443
			print self.bonenames[i]
444
		
445
		# Read links
446
		token_found=0
447
		while (token_found==0):
448
			sca.seek(28-(sca.tell()%32), os.SEEK_CUR )
449
			magic = sca.read(4)
450
			if (magic=='LINK'):
451
				token_found=1
452
			else:
453
				sca.seek(8, os.SEEK_CUR )
454
		links_fmt = str(self.numbones)+'l'
455
		links_size = struct.calcsize(links_fmt)
456
		buffer = sca.read(links_size)
457
		self.bonelinks = struct.unpack(links_fmt, buffer)
458
			
459
		posrot_fmt = '3f4f'
460
		posrot_size = struct.calcsize(posrot_fmt)
461
		
462
		# go to next section (data)
463
		#sounds like data is 0x40 aligned
464
		token_found=0
465
		while (token_found==0):
466
			sca.seek(28-(sca.tell()%32), os.SEEK_CUR )
467
			magic = sca.read(4)
468
			if (magic=='DATA'):
469
				token_found=1
470
			else:
471
				sca.seek(8, os.SEEK_CUR )
472
		buffer = sca.read(posrot_size)
473
		root_posrot = struct.unpack(posrot_fmt, buffer)
474
		for f in range(0, self.numbones) :
475
			buffer = sca.read(4)
476
			(frames_for_this_bone,) = struct.unpack('l', buffer)
477
			frame_list_for_this_bone=list()
478
			for i in range(0, frames_for_this_bone):
479
				frame_list_for_this_bone.append(sca_frame(self))
480
				frame_list_for_this_bone[i].load(sca)
481
			self.frames.append(frame_list_for_this_bone)
482
		sca.close()
483
		
484
		return self
485
486
	def dump(self):
487
		print 'SCA:  ', self.filename
488
		print 'Duration: %fs' % self.duration
489
		print 'Num loaded frames ', len(self.frames)
490
		
491
		print 'Bonelinks'		
492
		for link in self.bonelinks:
493
			print ' ', link
494
		
495
		print 'Bone names'
496
		for name in self.bonenames:
497
			print ' ', name
498
	
499
				
500
def pad(size):
501
	val = 32 - (size % 32)
502
	
503
	if (val > 31):
504
		return 0
505
		
506
	return val
507
			
508
			
509
#**************************************************************************************************
510
# Blender Interface
511
#**************************************************************************************************
512
def GetLeftRightBone(BoneNames,bone):
513
	if BoneNames[bone].find("Left") != -1:
514
		return BoneNames[bone].replace("Left","Right",1)
515
	elif BoneNames[bone].find("Right") != -1:
516
		return BoneNames[bone].replace("Right","Left",1)
517
	return BoneNames[bone]
518
519
520
def read_scm() :
521
	global xy_to_xz_transform
522
	global scm_filepath # [0] both [1] path [2] name
523
	global sca_filepath # [0] both [1] path [2] name
524
	
525
	print "=== LOADING Sup Com Model ==="
526
	print ""
527
	
528
	xy_to_xz_transform.resize4x4()
529
	
530
	scene = Blender.Scene.GetCurrent() 	
531
	
532
	mesh = scm_mesh()
533
	
534
	if (mesh.load(scm_filepath[0]) == None):
535
		print 'Failed to load %s' %scm_filepath[2]
536
		return
537
	
538
	ProgBarLSCM = ProgressBar( "Imp: load SCM", (2*len(mesh.vertices) + len(mesh.faces)))	
539
	
540
	armature_name = string.rstrip(scm_filepath[2], ".scm")
541
	print "armature ", armature_name
542
	
543
	###		CREATE ARMATURE 
544
	armObj = Object.New('Armature', armature_name)	#bad 
545
	
546
	armData = Blender.Armature.Armature(armature_name) 
547
	armData.drawAxes = True 
548
	armData.makeEditable()	
549
	 
550
	for index in range(len(mesh.bones)):
551
		bone = mesh.bones[index]	
552
		blender_bone = Blender.Armature.Editbone()		
553
		#not nice parent may not exist,  but usualy should exist (depends on storing in scm)
554
		if (bone.parent != 0) :
555
			blender_bone.parent = armData.bones[bone.parent.name]
556
		
557
558
		#blender_bone.options(Armature.CONNECTED)
559
		blender_bone.matrix = Matrix(bone.rel_mat * xy_to_xz_transform)		
560
				
561
		armData.bones[bone.name] = blender_bone
562
563
	
564
	#save changes (after linking!)
565
	armObj.link(armData)
566
	scene.link(armObj)
567
	#scene.objects.new(armData)
568
	###		CREATE MESH
569
	meshData = Blender.Mesh.New('Mesh')
570
	
571
	ProgBarLSCM.text = "IMP: Verticles"
572
	#add verts
573
	vertlist = []
574
	for vert in mesh.vertices:
575
		ProgBarLSCM.do()
576
		vertlist.append(Vector(vert.position)*xy_to_xz_transform)
577
	
578
	meshData.verts.extend(vertlist)
579
580
	meshData.vertexUV = True
581
	for i_v in xrange(len(meshData.verts)):
582
		uv1 = mesh.vertices[i_v].uv1
583
		meshData.verts[i_v].uvco = Vector(uv1[0], 1.0-uv1[1])
584
	
585
	ProgBarLSCM.text = "IMP: Faces"
586
	
587
	#reverse faces
588
	#for face in mesh.faces:
589
	#	face.reverse()
590
		
591
	#add faces
592
	meshData.faces.extend(mesh.faces)	
593
	meshData.faceUV = True	
594
	for face in meshData.faces :
595
		ProgBarLSCM.do()
596
		face.uv = [face.verts[i].uvco for i in range(3)]
597
	
598
	#put in scene
599
	mesh_obj = Object.New('Mesh','Mesh')
600
	mesh_obj.link(meshData)
601
	
602
	#scene.objects.new(meshData)
603
604
	#assigns vertex groups #mesh must be in object
605
	for bone in mesh.bones:
606
		meshData.addVertGroup(bone.name)
607
608
	for vertex_index in range(len(mesh.vertices)):
609
		ProgBarLSCM.do()
610
		vertex = mesh.vertices[vertex_index]
611
		bone_index = vertex.bone_index[0]
612
		meshData.assignVertsToGroup(mesh.bones[bone_index].name, [vertex_index], 1.0, Blender.Mesh.AssignModes.REPLACE) #'REPLACE'
613
	
614
	# it works... but you've to select/change to edit mode for the object to show up.
615
	# dunno why that is, maybe because Nmesh is depracated.
616
	meshData.update()
617
		
618
	#bones disapear wen update ?
619
	#armData.update()
620
621
	scene.link(mesh_obj)
622
	
623
	#must be in scene
624
	#armObj = None 
625
	#meshObj = None
626
	#for obj in Object.Get():
627
	#	if obj.getType() == 'Armature':
628
	#		armObj = obj
629
	#	if obj.getType() == 'Mesh':
630
	#		meshObj = obj
631
			
632
	#mesh_obj = Blender.Object.Get('Mesh')
633
	armObj.makeParentDeform([mesh_obj], 0, 0)
634
	#makeParentVertex(objects, indices, noninverse=0, fast=0)
635
	
636
	meshData.update()
637
	armData.update() 
638
639
	if len(mesh.info):
640
		print "=== INFO ==="
641
		for info in mesh.info:
642
			print "",info
643
644
	print "=== COMPLETE ==="
645
	
646
	if sca_filepath[0] != "" :
647
		read_anim(mesh)
648
649
	
650
651
652
def read_anim(mesh):
653
	global sca_filepath # [0] both [1] path [2] name
654
655
	
656
	print "=== LOADING Sup Com Animation ==="
657
	print ""
658
	
659
	anim = sca_anim()
660
	anim.load(sca_filepath[0])
661
	
662
	ProgBarLSCA = ProgressBar( "Imp: Frames", len(anim.frames))
663
	
664
	scene = Blender.Scene.GetCurrent()
665
	
666
	arm_obj = None
667
	for obj in scene.objects:
668
		data = obj.getData()
669
		if type(data) is Blender.Types.ArmatureType:
670
			arm_obj = obj
671
			break
672
		
673
	if arm_obj == None:
674
		print "couldn't apply animation, no armature in the scene" 
675
		return
676
677
	print arm_obj.name
678
	
679
	action = Blender.Armature.NLA.NewAction(sca_filepath[2])
680
	action.setActive(arm_obj)
681
	
682
	pose = arm_obj.getPose()
683
	
684
	for b in range(0,anim.numbones):
685
		ProgBarLSCA.do()
686
		for frame_index in range(0,len(anim.frames[b]) ):
687
			
688
			frame = anim.frames[b][frame_index]
689
			#Blender.Set("curframe",1+frame_index)
690
			
691
			pose_bone = pose.bones[anim.bonenames[b]]
692
			
693
			if (pose_bone == None):
694
				print 'Frame %d - Bone \"%s\" not found' % (frame_index, anim.bonenames[b])
695
				continue	
696
697
			anim_bone = frame.bones[0]
698
			pose_bone.loc = Vector(anim_bone.position)-Vector(mesh.bones[b].position)
699
			pose_bone.quat = DifferenceQuats(Quaternion(mesh.bones[b].rotation), Quaternion(anim_bone.rotation))
700
			#switch x and -y
701
			temp=pose_bone.loc.x
702
			pose_bone.loc.x=pose_bone.loc.y
703
			pose_bone.loc.y=temp
704
			# print anim.bonenames[b]
705
			# print " loc x=" +str(pose_bone.loc.x) +" y="+str(pose_bone.loc.y)+" z="+str(pose_bone.loc.z)
706
			# print " rot x=" +str(pose_bone.quat.x) +" y="+str(pose_bone.quat.y)+" z="+str(pose_bone.quat.z)+" w="+str(pose_bone.quat.w)
707
			
708
709
710
			pose_bone.size = Vector(1,1,1)
711
					
712
			pose.update()
713
			pose_bone.insertKey(arm_obj, 1+int(anim.numframes*frame.keytime/anim.duration), [Blender.Object.Pose.LOC, Blender.Object.Pose.ROT, Blender.Object.Pose.SIZE])
714
			pose.update()
715
	
716
	
717
	Blender.Set("curframe", 1)
718
	
719
	#scene = Blender.Scene.GetCurrent()
720
	context = scene.getRenderingContext()
721
722
	context.endFrame(anim.numframes)
723
	
724
	print "=== COMPLETE ==="
725
726
727
728
######################################################
729
# GUI
730
######################################################
731
	
732
log = []
733
log_max_lines = 14
734
LOG_FILE = None
735
736
#log to file
737
def LOGn(message):
738
	global LOG_FILE
739
	global LOG_ENABLE
740
	global LOG_FILENAME
741
	
742
	if LOG_ENABLE :
743
		if LOG_FILE == None :			
744
			LOG_FILE = open( LOG_FILENAME, 'w')
745
			LOG_FILE.write('SupCom Exporter LOG File:\n\n')
746
			
747
			LOGp( "LOG enabled: %s" % (LOG_FILENAME))
748
			Log(message + '\n')
749
			
750
		else :		
751
			LOG_FILE.write(message + '\n')
752
			
753
#Log to file, to console and exp window					
754
def LOGp(message):
755
	global log, log_max_lines
756
	
757
	LOGn(message)
758
	print message	
759
	log.append(message)
760
	
761
	if len(log) > log_max_lines:
762
		del log[0]
763
		
764
		
765
counter = []
766
cLog = []
767
#log for a amount of errors like vertex errors
768
def countLOG(message):
769
	global cLog
770
	global counter
771
	
772
	cont = False
773
	
774
	for i in xrange(len(cLog)):
775
		if cLog[i] == message:
776
			cont = True
777
			counter[i] +=1
778
			break
779
			
780
	if not cont :
781
		
782
		cLog.append( message)
783
		counter.append( 1)
784
785
def closeLog():
786
	global cLog, LOG_FILE
787
	global counter
788
	
789
	for i in xrange(len(cLog)):
790
		LOGp("%s (Times:%d)" % (cLog[i], counter[i]))
791
792
	if LOG_FILE != None :
793
		LOG_FILE.close()	
794
		
795
	Blender.Window.RedrawAll()
796
		
797
798
class ProgressBar :
799
800
	global PROG_BAR_STEP
801
	global PROG_BAR_ENABLE
802
	
803
	progress = 0
804
	progressold = 0	
805
	current = 0	
806
	end = 0
807
	div = 0
808
	text = "None"	
809
	
810
	def __init__(self, text, end):
811
		self.progress = 0
812
		self.progressold = 0
813
		self.current = 0
814
		self.end = end
815
		self.text = text
816
		self.div = PROG_BAR_STEP
817
		
818
		#it looks like blender needs to init this progress bar with 0.0
819
		if PROG_BAR_ENABLE :
820
			Blender.Window.DrawProgressBar ( 0.0 , text)
821
		
822
	def do(self):	
823
		
824
		if PROG_BAR_ENABLE :
825
			self.current += 1
826
			self.progress = (self.current*self.div)/self.end
827
			
828
			if self.progress != self.progressold :
829
				self.progressold = self.progress
830
				Blender.Window.DrawProgressBar ( float(self.progress)/self.div , self.text)
831
				
832
833
834
835
# Events
836
EVENT_DRAW = 1
837
EVENT_EXIT = 2
838
EVENT_SCMDIR = 3
839
EVENT_SCADIR = 4
840
841
842
show_log = 0
843
844
sca_filepath = [ "", "", "None"]
845
scm_filepath = [ "", "", "None"]
846
847
def anim_fileselector_callback(filename):
848
	global sca_filepath
849
	
850
	sca_filepath[0] = filename
851
	
852
	#print "Filename%sI\n" % filename
853
	#if ( filename != "" ) :
854
		#sca_filepath = [ "" , "None"]
855
		#return
856
	#else :
857
	
858
	length = len(filename)
859
	if filename[length-4:length] == ".sca" :		
860
		sca_filepath[1], sca_filepath[2]  = os.path.split(filename)
861
	else :
862
		sca_filepath[0] = ""
863
		sca_filepath[1] = ""
864
		sca_filepath[2] = "Non Supported"
865
866
867
def fileselector_callback(filename):
868
	global scm_filepath
869
	#sadly you cant check whether the cancel button is pressed
870
	scm_filepath[0] = filename
871
	length = len(filename)
872
	if filename[length-4:length] == ".scm" :		
873
		scm_filepath[1], scm_filepath[2]  = os.path.split(filename)
874
	else :
875
		scm_filepath[0] = ""
876
		scm_filepath[1] = ""
877
		scm_filepath[2] = "Non Supported"
878
879
	
880
def draw():
881
	global EVENT_DRAW, EVENT_EXIT,EVENT_SCADIR,EVENT_SCADIR
882
	global scm_filepath, sca_filepath, show_log
883
	global log_max_lines, log
884
	global VERSION
885
886
	# Titles
887
	glClear(GL_COLOR_BUFFER_BIT)
888
	
889
	top = 60 + log_max_lines * 12 + 8
890
	#top = 500
891
	top_x = 304
892
	
893
	glColor3f(0.8, 0.8, 1)
894
	glRecti(top_x, top, 4, 4)
895
	glBegin(GL_LINES)
896
	glColor3f(0.8, 0.8, 0.8)
897
	glVertex2d(4, top)
898
	glVertex2d(4, 4)
899
	glVertex2d(4, 4)
900
	glVertex2d(top_x, 4)
901
	glColor3f(0.5, 0.5, 0.5)
902
	glVertex2d(top_x, top)
903
	glVertex2d(4, top)
904
	glVertex2d(top_x, top)
905
	glVertex2d(top_x, top-1)
906
	glEnd()
907
	
908
	glColor3f(0, 0, 0)
909
	glRasterPos2d(10, top-16)
910
	Text("Supreme Commander2 Importer " + VERSION)	
911
912
	# Show exporting log
913
	if show_log:
914
915
		for index in range(0, len(log)):
916
			i = (len(log) - 1) - index
917
			glRasterPos2i(10, 40 + i*12)
918
			Text(log[index]) #, 'tiny')
919
		
920
		
921
		Button("Close", EVENT_EXIT , 10, 10, 80, 18)
922
923
		# Exporter GUI
924
	else:
925
		
926
		Blender.Draw.Button("Browse SCM", EVENT_SCMDIR, 10, 45, 80, 18, "Select scm")
927
		Blender.Draw.Button("Browse SCA", EVENT_SCADIR, 10, 80, 80, 18, "Select sca")	
928
		
929
		glRasterPos2d(100, 47)
930
		if scm_filepath[0] == "" :
931
			Text("SCM: " + scm_filepath[2])
932
		else:
933
			Text(":" + scm_filepath[2])
934
			
935
		glRasterPos2d(100, 82)
936
		if sca_filepath[0] == "" :
937
			Text("SCA: " + sca_filepath[2])
938
		else : 
939
			Text(":" + sca_filepath[2])
940
941
		# Draw and Exit Buttons
942
		Button("Import", EVENT_DRAW , 10, 10, 80, 18)
943
		Button("Exit", EVENT_EXIT , 100, 10, 80, 18)
944
945
def event(evt, val):	
946
	if (evt == QKEY and not val): 
947
		Exit()
948
949
def bevent(evt):
950
	global EVENT_DRAW,EVENT_EXIT
951
	global scm_filepath
952
	global show_log
953
954
	if (evt == EVENT_EXIT): 
955
		#show_log = 1
956
		Exit()
957
	
958
	elif (evt == EVENT_SCMDIR):
959
		Blender.Window.FileSelector (fileselector_callback, "Select SCM File")
960
		Blender.Redraw()
961
		
962
	elif (evt == EVENT_SCADIR):
963
		if scm_filepath[0] != "" :			
964
			Blender.Window.FileSelector (anim_fileselector_callback, "Select SCA File", scm_filepath[1]+"\\")			
965
		else :
966
			Blender.Window.FileSelector (anim_fileselector_callback, "Select SCA File")			
967
		Blender.Redraw()
968
	
969
	elif (evt == EVENT_DRAW):
970
		
971
		if (scm_filepath[0] != ''):		
972
			show_log = 1			
973
			read_scm() 
974
		
975
		Blender.Redraw()
976
977
		
978
979
Register(draw, event, bevent)
980
981
#open fileselector automaticly
982
Blender.Window.FileSelector (fileselector_callback, "Select SCM File")