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") |