dumpsca.py
#**************************************************************************************************
# Copyright (c) 2006 Gas Powered Games Corp. All Rights Reserved.
# Gas Powered Games and Supreme Commander are the exclusive trademarks of Gas Powered Games Corp.
#**************************************************************************************************
def DumpSCA(filename):
import struct,string
data = file(filename, 'rb').read()
fileheader_fmt = '4sllflllll'
fileheader_size = struct.calcsize(fileheader_fmt)
start,stop = 0,fileheader_size
(magic, \
version, \
numframes, \
durationseconds, \
numbones, \
namesoffset, \
linksoffset, \
firstframeoffset, \
framesize) = struct.unpack(fileheader_fmt,data[start:stop])
print "----------------"
print " Animation Header"
print "----------------"
print "File Type:",magic
print "Version:",version
print "NumFrames:",numframes
print "NumBones:",numbones
print "Duration: %-10.5f" % durationseconds
print "NamesOffset:",namesoffset
print "LinkOffset:",linksoffset
print "DataOffset:",firstframeoffset
print "FrameSize:",framesize
print "\n----------------"
print " Bone Info"
print "----------------"
start = namesoffset
stop = linksoffset
rawnames = struct.unpack(str(stop-start)+'s',data[start:stop])
bonenames = string.split(rawnames[0],'\0')[:-1]
links_fmt = str(numbones)+'l'
links_size = struct.calcsize(links_fmt)
start = linksoffset
stop = start + links_size
bonelinks = struct.unpack(links_fmt,data[start:stop])
b = 0
for b in range(0,len(bonenames)) :
if (bonelinks[b] == -1) :
print "#%d %-12s (<local root>)" % (b, bonenames[b])
else :
print "#%d %-12s (child of #%d %s)" % (b, bonenames[b], bonelinks[b], bonenames[bonelinks[b]])
print "\n----------------"
print " Animation Data"
print "----------------"
vec3_prettyprint = "(%11.5f,%11.5f,%11.5f)"
quat_prettyprint = "(%11.5f,%11.5f,%11.5f,%11.5f)"
frameheader_fmt = 'fl'
frameheader_size = struct.calcsize(frameheader_fmt)
posrot_fmt = '3f4f'
posrot_size = struct.calcsize(posrot_fmt)
start,stop = firstframeoffset,firstframeoffset+posrot_size
root_posrot = struct.unpack(posrot_fmt,data[start:stop])
print ("Root Delta: Pos: " + vec3_prettyprint + " Rot: " + quat_prettyprint) % root_posrot
for f in range (0, numframes) :
start,stop = stop,stop+frameheader_size
(keytime,keyflags) = struct.unpack(frameheader_fmt,data[start:stop])
# Don't dump all the keys, only the beginning, middle, and end...
dumpit = (f < 2) or ((f > (numframes/2)-2) and (f < (numframes/2+1))) or f > (numframes-3)
if dumpit :
print "\nFrame: %-4d Time: %-11.5f Flags: 0x%08X\n" % (f, keytime, keyflags)
for b in range (0, numbones) :
start,stop = stop,stop+posrot_size
keydata = struct.unpack(posrot_fmt,data[start:stop])
if dumpit:
print " %2d: %-14s " % (b,'['+bonenames[b]+']'), (" Pos: " + vec3_prettyprint + " Rot: " + quat_prettyprint) % keydata
if __name__ == '__main__' :
import sys
from os import path
if len(sys.argv) == 2 :
DumpSCA(sys.argv[1])
else:
print "usage %s <SCA filename>" % path.basename(sys.argv[0])
dumpscm.py
#**************************************************************************************************
# Copyright (c) 2006 Gas Powered Games Corp. All Rights Reserved.
# Gas Powered Games and Supreme Commander are the exclusive trademarks of Gas Powered Games Corp.
#**************************************************************************************************
#define some pretty print formats
vec4pp = "[%11.5f,%11.5f,%11.5f,%11.5f]"
vec3pp = "[%11.5f,%11.5f,%11.5f]"
vec2pp = "[%11.5f,%11.5f]"
def DumpVert(v,d):
print "VERT[%4d]" % v
print (" Pos: " + vec3pp) % d[0:3]
print (" Tangent: " + vec3pp) % d[3:6]
print (" Normal: " + vec3pp) % d[6:9]
print (" Binormal: " + vec3pp) % d[9:12]
print (" UV0: " + vec2pp) % d[12:14]
print (" UV1: " + vec2pp) % d[14:16]
print " Bone %3d" % d[16:17]
def DumpSCM(filename) :
import struct,string
data = file(filename, 'rb').read()
start,stop = 0,struct.calcsize('4sL')
marker,version = struct.unpack('4sL',data[start:stop])
start,stop = stop,stop+struct.calcsize('2L')
boneoffset,bonecount = struct.unpack ('2L',data[start:stop])
start,stop = stop,stop+struct.calcsize('3L')
vertoffset,extravertoffset,vertcount = struct.unpack ('3L',data[start:stop])
start,stop = stop,stop+struct.calcsize('2L')
indexoffset,indexcount = struct.unpack ('2L',data[start:stop])
tricount = indexcount/3
start,stop = stop,stop+struct.calcsize('2L')
infooffset,infocount = struct.unpack ('2L',data[start:stop])
print "*** HEADER ***\n"
print 'File Type: %s' %marker
print 'Version: %d' % version
print 'Bone count: %d, Bone offset: %d' % (bonecount,boneoffset)
print 'Vertex count: %d, Vertex offset: %d, ExtraVert offset: %d' % (vertcount,vertoffset,extravertoffset)
print 'Triangle coun:t %d, Triangle offset: %d' % (tricount,indexoffset)
print 'Info count: %d, Info offset: %d' % (infocount,infooffset)
padding = str(32-(stop+4)%32)+'s4s'
start = stop+struct.calcsize(padding)
stop = boneoffset
rawnames = struct.unpack(str(stop-start)+'s',data[start:stop])
print "\n*** BONE NAMES ***\n"
bonenames = string.split(rawnames[0],'\0')[:-1]
for b in range(0,len(bonenames)):
print "[%2d] %s" % (b,bonenames[b])
print "\n*** BONE DATA ***\n"
bonestruct = '16f3f4f4i'
bonesize = struct.calcsize(bonestruct)
start,stop = boneoffset,boneoffset+bonesize
for b in range(0,bonecount):
bone = struct.unpack(bonestruct,data[start:stop])
start,stop = stop,stop+bonesize
print "\nBONE %d : [%s]" % (b,bonenames[b])
print ' Parent Bone'
if (bone[24] == -1) :
print ' -1 <root>'
else :
print ' %d <%s>' % (bone[24],bonenames[bone[24]])
print ' Parent Relative Position'
print (' '+vec3pp) % bone[16:19]
print ' Parent Relative Rotation'
print (' ' +vec4pp) % bone[19:23]
print ' Rest Pose Inverse'
for row in range(4):
print (' '+ vec4pp) % bone[row*4:row*4+4]
print "\n*** VERTEX DATA ***\n"
vertstruct = '3f3f3f3f2f2f4B'
vertsize = struct.calcsize(vertstruct)
stop = vertoffset
if (vertcount < 7):
for v in range(0,vertcount):
start,stop = stop,stop+vertsize
vert = struct.unpack(vertstruct,data[start:stop])
DumpVert(v,vert)
else:
for v in range(0,3):
start,stop = stop,stop+vertsize
vert = struct.unpack(vertstruct,data[start:stop])
DumpVert(v,vert)
print "...skipping %d verts..." % (vertcount-5)
stop = vertoffset+(vertsize*(vertcount-3))
for v in range(vertcount-3,vertcount):
start,stop = stop,stop+vertsize
vert = struct.unpack(vertstruct,data[start:stop])
DumpVert(v,vert)
if (extravertoffset != 0) :
print "EXTRAVERTS (first 5 only...)\n"
extravertstruct = '2f'
extravertsize = struct.calcsize(extravertstruct)
start,stop = extravertoffset,extravertoffset+extravertsize
for v in range(0,min(5,vertcount)):
xvert = struct.unpack(extravertstruct,data[start:stop])
start,stop = stop,stop+extravertsize
print xvert[0:2]
else :
print "No EXTRAVERT data for this model\n"
print "\n*** TRIANGLE INDICES ***\n"
tristruct = '3h'
trisize = struct.calcsize(tristruct)
stop = indexoffset
if (tricount < 7) :
for t in range(0,tricount):
start,stop = stop,stop+trisize
tri = struct.unpack(tristruct,data[start:stop])
print tri[0],
print tri[1],
print tri[2]
else :
for t in range(0,3):
start,stop = stop,stop+trisize
tri = struct.unpack(tristruct,data[start:stop])
print "%4d: %s" % (t, tri)
print "...skipping %d triangles..." % (tricount-5)
stop = indexoffset+(trisize*(tricount-3))
for t in range(tricount-3,tricount):
start,stop = stop,stop+trisize
tri = struct.unpack(tristruct,data[start:stop])
print "%4d: %s" % (t, tri)
print "\n*** INFO ***\n"
infostruct = str(infocount)+'s'
infosize = struct.calcsize(infostruct)
start,stop = infooffset,infooffset+infosize
info = struct.unpack(infostruct,data[start:stop])
infostrings = string.split(info[0],'\0')[:-1]
for i in infostrings:
print " %s" % i
if __name__ == '__main__' :
import sys
from os import path
if len(sys.argv) == 2 :
DumpSCM(sys.argv[1])
else:
print "usage %s <SCM filename>" % path.basename(sys.argv[0])
ScaFile_format.h
/**************************************************************************************************
Copyright (c) 2006 Gas Powered Games Corp. All Rights Reserved.
Gas Powered Games and Supreme Commander are the exclusive trademarks of Gas Powered Games Corp.
***************************************************************************************************/
#ifndef SCAFILE_H
#define SCAFILE_H
// SScaFileHeader -- The header for .SCA files.
//
struct SScaFileHeader
{
// The FOURCC 'ANIM'
unsigned long mMagic;
// The .SCA version number.
unsigned long mVersion;
// The number of frames in this animation.
unsigned long mNumFrames;
// The duration (in seconds) of this animation.
// The animation plays at (mNumFrames-1)/mDuration frames per second.
float mDuration;
// The number of bones in this animation.
unsigned long mNumBones;
// Offset of the bone names (SScaFileBoneNames[0])
unsigned long mBoneNamesOffset;
// Offset of the bone link info (SScaFileBoneLinks[0])
unsigned long mBoneLinksOffset;
// Offset of the actual animation data (SScaFileAnimData[0])
unsigned long mFirstFrameOffset;
// The number of bytes in one animation frame.
unsigned long mFrameSize;
};
// SScaFileBoneNames -- The bone names used in this animation.
//
struct SScaFileBoneNames
{
// Array of bone names. There are header.mNumBones NUL terminated
// strings concatenated together starting here.
char mBoneNameData[1]; //(array size is mNumBones)
};
// SScaFileBoneLinks -- The parent links for the bones used in this animation.
//
struct SScaFileBoneLinks
{
// Array of bone indices.
unsigned long mParentBoneIndex[]; //(array size is mNumBones)
};
// SScaFileBoneKeyframe -- The data for single bone at a single key
// frame.
//
struct SScaFileBoneKeyframe
{
// Position relative to the parent bone.
// Vector (x,y,z)
float mPosition[3];
// Rotation relative to the parent bone.
// Quaternion (w,x,y,z)
float mRotation[4];
};
// SScaFileKeyframe -- The data about a single key frame.
//
struct SScaFileKeyframe
{
// The time (in seconds) of this keyframe.
float mTime;
// Various flags. None defined yet.
unsigned long mFlags;
// Array of keyframe data for each bone.
SScaFileBoneKeyframe mBones[1]; //(array size is mNumBones)
};
// SScaFileAnimData -- The actual animation data.
//
struct SScaFileAnimData
{
// The total position delta between the first frame and the last frame.
// Vector (x,y,z)
float mPositionDelta[3];
// The total orientation delta between the first frame and the last frame.
// Quaternion (w,x,y,z)
float mOrientDelta[4];
// The per-frame data.
SScaFileKeyframe mFrames[1]; //(array size is mNumFrames)
};
#endif SCAFILE_H
ScmFile_format.h
/**************************************************************************************************
Copyright (c) 2006 Gas Powered Games Corp. All Rights Reserved.
Gas Powered Games and Supreme Commander are the exclusive trademarks of Gas Powered Games Corp.
***************************************************************************************************/
#ifndef SCMFILE_H
#define SCMFILE_H
// SCM VERSION 5 DATA LAYOUT
// Multi-byte data is writting in little-endian ("Intel") format
// There are 5 required and 2 optional sections in an SCM file, each indicated by a leading FOURCC code:
// FOURCC | Contents
// --------+------------------------
// 'MODL' | Header info
// 'NAME' | List of bone name strings
// 'SKEL' | Array of bone data
// 'VTXL' | Array of basic vertex data
// 'TRIS' | Array of triangle indices
// 'VEXT' | Array of extra vertex data (OPTIONAL SECTION)
// 'INFO' | List of null terminated information strings (OPTIONAL SECTION)
// Section offsets in the file header point to the start of the data for that section (ie, the first byte AFTER
// the section's identifying FOURCC) Padding characters are added to the end of each section to ensure that
// the next section is 16-byte aligned. Ommitted sections are indicated by an offset of 0.
// *** All offsets are relative to the start of the file ***
//
//
struct ScmHeader
{
// The FOURCC 'MODL'
unsigned long mMagic;
// The .SCM version number
unsigned long mVersion;
// Offset to SCM_BoneData[0]
unsigned long mBoneOffset;
// Number of elements in SCM_BoneData that actually influence verts (no reference points)
unsigned long mWeightedBoneCount;
// Offset of basic vertex data section (SCM_VertData[0])
unsigned long mVertexOffset;
// Offset of extra vertex data section (SCM_VertExtraData[0])
// Contains additional per-vertex information. *** Currently unused (and omitted) in SupCom 1.0 ***
unsigned long mVertexExtraOffset;
// Number of elements in the SCM_VertData array
// (and the SCM_VertExtraData array, if mVertexExtraOffset != 0)
unsigned long mVertexCount;
// Offset of the triangle index section (SCM_TriangleData[0])
unsigned long mIndexOffset;
// Number of elements in the SCM_TriangleData array
unsigned long mIndexCount;
// Offset of information section (SCM_InfoData[0])
unsigned long mInfoOffset;
// Number of elements in the SCM_InfoData list
unsigned long mInfoCount;
// Number of elements in the SCM_BoneData array (including 'reference point' bones)
unsigned long mTotalBoneCount;
};
//
//
struct ScmBoneData
{
// Inverse transform of the bone relative to the local origin of the mesh
// 4x4 Matrix with row major (i.e. D3D default ordering)
float mRestPoseInverse[4][4];
// Position relative to the parent bone.
// Vector (x,y,z)
float mPosition[3];
// Rotation relative to the parent bone.
// Quaternion (w,x,y,z)
float mRotation[4];
// Offset of the bone's name string
unsigned long mNameOffset;
// Index of the bone's parent in the SCM_BoneData array
unsigned long mParentBoneIndex;
unsigned long RESERVED_0;
unsigned long RESERVED_1;
};
//
//
struct ScmVertData
{
// Position of the vertex relative to the local origin of the mesh
float mPosition[3];
// 'Tangent Space' normal, tangent & binormal unit vectors
float mNormal[3];
float mTangent[3];
float mBinormal[3];
// Two sets of UV coordinates
float mUV0[2];
float mUV1[2];
// Up to 4-bone skinning can be supported using additional
// indices (in conjunction with bone weights in the optional VertexExtra array)
// Skinned meshes are not used in SupCom 1.0 so only mBoneIndex[0] is expected
// to contain a valid index.
unsigned char mBoneIndex[4];
};
struct ScmTriangleData
{
unsigned short triIndices[3];
};
#endif SCMFILE_H
以上文件来源于GPG论坛,本人估计是开发最高指挥官SCM/SCA模型动画格式导入导出插件所需要用到的数据结构布局源件.
最高指挥官模型解析器原始下载地址:
http://www.pixelheaven.net/supcom/SupCom3DFormats.rar
http://viking.gurut.org/tools/SupCom3DFormats.rar
最高指挥官模型解析器天下会备份下载地址:
SupCom3DFormats.rar (188 KB)
115网盘下载地址:
http://115.com/file/c24amasb#
最高指挥官模型解析器图片嵌入包:
使用说明:点击以下图片并保存为PNG格式,改后缀名为RAR即可得嵌入文件包,此包可解压.
最高指挥官模型与动画格式导入导出插件汇总:
说明;以上附件包包含Autodesk 3ds Max,Blender与LightWave 3D三个建模工具的SCM&SCA格式导入导出插件.