208 lines
5.3 KiB
Python
208 lines
5.3 KiB
Python
"""
|
|
|
|
MIT License
|
|
|
|
Copyright (c) 2020 Benjamin Collins (kion @ dashgl.com)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
"""
|
|
|
|
import math
|
|
import struct
|
|
from Mat4 import Mat4
|
|
|
|
class NinjaMotion:
|
|
|
|
def __init__(self):
|
|
self.debug = False
|
|
self.index = -1
|
|
self.name = "";
|
|
self.skeleton = []
|
|
self.frames = 0
|
|
self.fps = 30
|
|
self.keyFrames = []
|
|
self.count = 0
|
|
return None
|
|
|
|
def setName(self, index):
|
|
self.index = index
|
|
self.name = "anim_%03d" % index
|
|
return None
|
|
|
|
def setSkeleton(self, bones):
|
|
self.skeleton = bones
|
|
for i in range(len(bones)):
|
|
self.keyFrames.append([])
|
|
return None
|
|
|
|
def setFrames(self, frames):
|
|
self.frames = frames
|
|
return None
|
|
|
|
def appendKeyFrame(self, boneIndex, frame, vec3, type):
|
|
keyFrames = self.keyFrames[boneIndex]
|
|
|
|
if self.debug:
|
|
print("Adding %s type frame to bone %d" % (type, boneIndex))
|
|
|
|
for keys in keyFrames:
|
|
if keys['frame'] != frame:
|
|
continue
|
|
keys[type] = vec3
|
|
return None
|
|
|
|
keyFrame = {
|
|
'frame' : frame,
|
|
type : vec3
|
|
}
|
|
|
|
keyFrames.append(keyFrame)
|
|
return None
|
|
|
|
def save(self, boneIndex):
|
|
|
|
bone = self.skeleton[boneIndex]
|
|
keyFrames = self.keyFrames[boneIndex]
|
|
|
|
if len(keyFrames) == 0:
|
|
keyFrames.append({
|
|
'frame' : 0
|
|
})
|
|
keyFrames.append({
|
|
'frame' : self.frames - 1
|
|
})
|
|
|
|
if 'scl' not in keyFrames[0].keys():
|
|
keyFrames[0]['scl'] = bone.getScale()
|
|
|
|
if 'pos' not in keyFrames[0].keys():
|
|
keyFrames[0]['pos'] = bone.getPosition()
|
|
|
|
if 'rot' not in keyFrames[0].keys():
|
|
keyFrames[0]['rot'] = bone.getRotation()
|
|
|
|
lastIndex = len(keyFrames) - 1
|
|
|
|
if 'scl' not in keyFrames[lastIndex].keys():
|
|
keyFrames[lastIndex]['scl'] = bone.getScale()
|
|
|
|
if 'pos' not in keyFrames[lastIndex].keys():
|
|
keyFrames[lastIndex]['pos'] = bone.getPosition()
|
|
|
|
if 'rot' not in keyFrames[lastIndex].keys():
|
|
keyFrames[lastIndex]['rot'] = bone.getRotation()
|
|
|
|
for keyFrame in keyFrames:
|
|
|
|
self.count += 1
|
|
if 'rot' not in keyFrame.keys():
|
|
continue
|
|
|
|
c1 = math.cos( keyFrame['rot'][0] / 2 );
|
|
c2 = math.cos( keyFrame['rot'][1] / 2 );
|
|
c3 = math.cos( keyFrame['rot'][2] / 2 );
|
|
|
|
s1 = math.sin( keyFrame['rot'][0] / 2 );
|
|
s2 = math.sin( keyFrame['rot'][1] / 2 );
|
|
s3 = math.sin( keyFrame['rot'][2] / 2 );
|
|
|
|
x = s1 * c2 * c3 + c1 * s2 * s3
|
|
y = c1 * s2 * c3 - s1 * c2 * s3
|
|
z = c1 * c2 * s3 + s1 * s2 * c3
|
|
w = c1 * c2 * c3 - s1 * s2 * s3
|
|
keyFrame['quat'] = [ x, y, z, w ]
|
|
|
|
return None
|
|
|
|
def generateDmfEntry(self, file):
|
|
|
|
name = self.name
|
|
while len(name) < 0x20:
|
|
name += '\0'
|
|
bytes = name.encode()
|
|
file.write(bytes)
|
|
|
|
bytes = struct.pack('hh', self.index, self.fps)
|
|
file.write(bytes)
|
|
|
|
self.pos = file.tell()
|
|
file.write(struct.pack('I', 0))
|
|
file.write(struct.pack('I', self.count))
|
|
|
|
duration = (self.frames - 1) / self.fps
|
|
file.write(struct.pack('f', duration))
|
|
|
|
return None
|
|
|
|
def writeDmfAnimation(self, file):
|
|
|
|
offset = file.tell()
|
|
file.seek(self.pos, 0)
|
|
file.write(struct.pack('I', offset))
|
|
file.seek(0, 2)
|
|
|
|
for i in range(len(self.keyFrames)):
|
|
|
|
keyFrames = self.keyFrames[i]
|
|
for keyFrame in keyFrames:
|
|
skipFlags = 0
|
|
|
|
if 'pos' in keyFrame.keys():
|
|
skipFlags |= 0x01
|
|
|
|
if 'rot' in keyFrame.keys():
|
|
skipFlags |= 0x02
|
|
|
|
if 'scl' in keyFrame.keys():
|
|
skipFlags |= 0x04
|
|
|
|
file.write(struct.pack('hh', i, skipFlags))
|
|
file.write(struct.pack('f', keyFrame['frame'] / self.fps))
|
|
|
|
if 'pos' in keyFrame.keys():
|
|
file.write(struct.pack('f', keyFrame['pos'][0]))
|
|
file.write(struct.pack('f', keyFrame['pos'][1]))
|
|
file.write(struct.pack('f', keyFrame['pos'][2]))
|
|
else:
|
|
file.write(struct.pack('f', 0))
|
|
file.write(struct.pack('f', 0))
|
|
file.write(struct.pack('f', 0))
|
|
|
|
if 'quat' in keyFrame.keys():
|
|
file.write(struct.pack('f', keyFrame['quat'][0]))
|
|
file.write(struct.pack('f', keyFrame['quat'][1]))
|
|
file.write(struct.pack('f', keyFrame['quat'][2]))
|
|
file.write(struct.pack('f', keyFrame['quat'][3]))
|
|
else:
|
|
file.write(struct.pack('f', 0))
|
|
file.write(struct.pack('f', 0))
|
|
file.write(struct.pack('f', 0))
|
|
file.write(struct.pack('f', 1))
|
|
|
|
if 'scl' in keyFrame.keys():
|
|
file.write(struct.pack('f', keyFrame['scl'][0]))
|
|
file.write(struct.pack('f', keyFrame['scl'][1]))
|
|
file.write(struct.pack('f', keyFrame['scl'][2]))
|
|
else:
|
|
file.write(struct.pack('f', 1))
|
|
file.write(struct.pack('f', 1))
|
|
file.write(struct.pack('f', 1))
|
|
|
|
return None
|