md5: add md5anim
This commit is contained in:
parent
efe6470afe
commit
1a290c03d2
@ -47,8 +47,10 @@ using vec3 = vec<3, float>;
|
||||
using vec4 = vec<4, float>;
|
||||
using mat4x4 = mat<4, 4, float>;
|
||||
|
||||
#include "md5/md5.h"
|
||||
#include "model/boblamp/boblamp.h"
|
||||
#include "md5/md5mesh.h"
|
||||
#include "md5/md5anim.h"
|
||||
#include "model/boblamp/boblamp_mesh.h"
|
||||
#include "model/boblamp/boblamp_anim.h"
|
||||
|
||||
static int joint_ix_sel = 0;
|
||||
|
||||
|
29
md5/md5anim.h
Normal file
29
md5/md5anim.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
struct md5_anim_hierarchy {
|
||||
const char * name;
|
||||
int parent_index;
|
||||
int flags;
|
||||
int start_index;
|
||||
};
|
||||
|
||||
struct md5_anim_bounds {
|
||||
vec3 min;
|
||||
vec3 max;
|
||||
};
|
||||
|
||||
struct md5_anim_base_frame {
|
||||
vec3 pos;
|
||||
vec4 orient;
|
||||
};
|
||||
|
||||
struct md5_anim {
|
||||
int num_frames;
|
||||
int num_joints;
|
||||
int frame_rate;
|
||||
int num_animated_components;
|
||||
md5_anim_hierarchy * hierarchy;
|
||||
md5_anim_bounds * bounds;
|
||||
md5_anim_base_frame * base_frame;
|
||||
float ** frame;
|
||||
};
|
187
md5/md5anim.py
Normal file
187
md5/md5anim.py
Normal file
@ -0,0 +1,187 @@
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from pprint import pprint
|
||||
|
||||
@dataclass
|
||||
class MD5AnimFrame:
|
||||
value: list[float] = field(default_factory=lambda: list())
|
||||
|
||||
@dataclass
|
||||
class MD5AnimBaseFrame:
|
||||
pos_x: float = None
|
||||
pos_y: float = None
|
||||
pos_z: float = None
|
||||
orient_x: float = None
|
||||
orient_y: float = None
|
||||
orient_z: float = None
|
||||
|
||||
@dataclass
|
||||
class MD5AnimBounds:
|
||||
min_x: float = None
|
||||
min_y: float = None
|
||||
min_z: float = None
|
||||
max_x: float = None
|
||||
max_y: float = None
|
||||
max_z: float = None
|
||||
|
||||
@dataclass
|
||||
class MD5AnimHierarchy:
|
||||
name: str = None
|
||||
parent_index: int = None
|
||||
flags: int = None
|
||||
start_index: int = None
|
||||
|
||||
@dataclass
|
||||
class MD5Anim:
|
||||
num_frames: int = None
|
||||
num_joints: int = None
|
||||
frame_rate: int = None
|
||||
num_animated_components: int = None
|
||||
hierarchy: list[MD5AnimHierarchy] = field(default_factory=lambda: list())
|
||||
bounds: list[MD5AnimBounds] = field(default_factory=lambda: list())
|
||||
base_frame: list[MD5AnimBaseFrame] = field(default_factory=lambda: list())
|
||||
frame: list[MD5AnimFrame] = field(default_factory=lambda: list())
|
||||
|
||||
def parse_header(l, ix, md5anim):
|
||||
assert l[ix+0] == "MD5Version 10"
|
||||
assert l[ix+1].startswith("commandline")
|
||||
assert l[ix+2].startswith("numFrames ")
|
||||
assert l[ix+3].startswith("numJoints ")
|
||||
assert l[ix+4].startswith("frameRate ")
|
||||
assert l[ix+5].startswith("numAnimatedComponents ")
|
||||
|
||||
md5anim.num_frames = int(l[ix+2].removeprefix("numFrames "), 10)
|
||||
md5anim.num_joints = int(l[ix+3].removeprefix("numJoints "), 10)
|
||||
md5anim.frame_rate = int(l[ix+4].removeprefix("frameRate "), 10)
|
||||
md5anim.num_animated_components = int(l[ix+5].removeprefix("numAnimatedComponents "), 10)
|
||||
|
||||
return ix + 6
|
||||
|
||||
def parse_hierarchy(l, ix, md5anim):
|
||||
s = l[ix]
|
||||
lc = s.split("//", maxsplit=1)
|
||||
if len(lc) == 2:
|
||||
line, comment = lc
|
||||
elif len(lc) == 1:
|
||||
line = lc
|
||||
comment = None
|
||||
else:
|
||||
assert False, len(lc)
|
||||
|
||||
tokens = line.split()
|
||||
hierarchy = MD5AnimHierarchy()
|
||||
|
||||
# name
|
||||
name = tokens[0]
|
||||
assert name.startswith('"') and name.endswith('"')
|
||||
hierarchy.name = name[1:-1]
|
||||
|
||||
hierarchy.parent_index = int(tokens[1], 10)
|
||||
hierarchy.flags = int(tokens[2], 10)
|
||||
hierarchy.start_index = int(tokens[3], 10)
|
||||
|
||||
md5anim.hierarchy.append(hierarchy)
|
||||
|
||||
return ix + 1
|
||||
|
||||
def parse_bounds(l, ix, md5anim):
|
||||
line = l[ix]
|
||||
tokens = line.split()
|
||||
|
||||
bounds = MD5AnimBounds()
|
||||
|
||||
assert tokens[0] == "("
|
||||
bounds.min_x = float(tokens[1])
|
||||
bounds.min_y = float(tokens[2])
|
||||
bounds.min_z = float(tokens[3])
|
||||
assert tokens[4] == ")"
|
||||
assert tokens[5] == "("
|
||||
bounds.max_x = float(tokens[6])
|
||||
bounds.max_y = float(tokens[7])
|
||||
bounds.max_z = float(tokens[8])
|
||||
assert tokens[9] == ")"
|
||||
|
||||
md5anim.bounds.append(bounds)
|
||||
|
||||
return ix + 1
|
||||
|
||||
def parse_base_frame(l, ix, md5anim):
|
||||
line = l[ix]
|
||||
tokens = line.split()
|
||||
|
||||
base_frame = MD5AnimBaseFrame()
|
||||
|
||||
assert tokens[0] == "("
|
||||
base_frame.pos_x = float(tokens[1])
|
||||
base_frame.pos_y = float(tokens[2])
|
||||
base_frame.pos_z = float(tokens[3])
|
||||
assert tokens[4] == ")"
|
||||
assert tokens[5] == "("
|
||||
base_frame.orient_x = float(tokens[6])
|
||||
base_frame.orient_y = float(tokens[7])
|
||||
base_frame.orient_z = float(tokens[8])
|
||||
assert tokens[9] == ")"
|
||||
|
||||
md5anim.base_frame.append(base_frame)
|
||||
|
||||
return ix + 1
|
||||
|
||||
def parse_frame(l, ix, md5anim):
|
||||
frame = MD5AnimFrame()
|
||||
|
||||
while l[ix] != "}":
|
||||
tokens = l[ix].split()
|
||||
for token in tokens:
|
||||
value = float(token)
|
||||
frame.value.append(value)
|
||||
ix += 1
|
||||
|
||||
assert len(frame.value) == md5anim.num_animated_components
|
||||
|
||||
md5anim.frame.append(frame)
|
||||
|
||||
return ix
|
||||
|
||||
def parse_ordered_list(l, ix, md5anim):
|
||||
assert l[ix].endswith("{"), l[ix]
|
||||
string, _ = l[ix].rsplit(maxsplit=1)
|
||||
ix += 1
|
||||
|
||||
if string == "hierarchy":
|
||||
while l[ix] != "}":
|
||||
ix = parse_hierarchy(l, ix, md5anim)
|
||||
elif string == "bounds":
|
||||
while l[ix] != "}":
|
||||
ix = parse_bounds(l, ix, md5anim)
|
||||
elif string == "baseframe":
|
||||
while l[ix] != "}":
|
||||
ix = parse_base_frame(l, ix, md5anim)
|
||||
elif string.startswith("frame"):
|
||||
frame, frame_ix = string.split()
|
||||
assert int(frame_ix) == len(md5anim.frame)
|
||||
while l[ix] != "}":
|
||||
ix = parse_frame(l, ix, md5anim)
|
||||
assert l[ix] == "}", l[ix]
|
||||
ix += 1
|
||||
return ix
|
||||
|
||||
def parse_file(l):
|
||||
ix = 0
|
||||
md5anim = MD5Anim()
|
||||
ix = parse_header(l, ix, md5anim)
|
||||
while ix < len(l):
|
||||
ix = parse_ordered_list(l, ix, md5anim)
|
||||
|
||||
assert len(md5anim.hierarchy) == md5anim.num_joints, (len(md5anim.hierarchy))
|
||||
assert len(md5anim.bounds) == md5anim.num_frames, (len(md5anim.bounds))
|
||||
assert len(md5anim.base_frame) == md5anim.num_joints, (len(md5anim.base_frame))
|
||||
assert len(md5anim.frame) == md5anim.num_frames, (len(md5anim.frame))
|
||||
|
||||
return md5anim
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
buf = f.read()
|
||||
l = [i.strip() for i in buf.split('\n') if i.strip()]
|
||||
md5anim = parse_file(l)
|
||||
pprint(md5anim)
|
94
md5/md5anim_gen.py
Normal file
94
md5/md5anim_gen.py
Normal file
@ -0,0 +1,94 @@
|
||||
from generate import renderer
|
||||
import sys
|
||||
import md5anim
|
||||
from md5mesh_gen import vec2, vec3, vec4, unit_quaternion_w
|
||||
|
||||
def _render_md5_anim_hierarchy(h):
|
||||
yield f'.name = "{h.name}",'
|
||||
yield f".parent_index = {h.parent_index},"
|
||||
yield f".flags = {h.flags},"
|
||||
yield f".start_index = {h.start_index},"
|
||||
|
||||
def render_md5_anim_hierarchy(prefix, hierarchy):
|
||||
yield f"struct md5_anim_hierarchy {prefix}_hierarchy[] = {{"
|
||||
for h in hierarchy:
|
||||
yield "{"
|
||||
yield from _render_md5_anim_hierarchy(h)
|
||||
yield "},"
|
||||
yield "};"
|
||||
|
||||
def _render_md5_anim_bounds(b):
|
||||
min = vec3(b.min_x, b.min_y, b.min_z)
|
||||
max = vec3(b.max_x, b.max_y, b.max_z)
|
||||
yield f".min = {min},"
|
||||
yield f".max = {max},"
|
||||
|
||||
def render_md5_anim_bounds(prefix, bounds):
|
||||
yield f"struct md5_anim_bounds {prefix}_bounds[] = {{"
|
||||
for b in bounds:
|
||||
yield "{"
|
||||
yield from _render_md5_anim_bounds(b)
|
||||
yield "},"
|
||||
yield "};"
|
||||
|
||||
def _render_md5_anim_base_frame(bf):
|
||||
pos = vec3(bf.pos_x, bf.pos_x, bf.pos_x)
|
||||
w = unit_quaternion_w(bf.orient_x, bf.orient_y, bf.orient_z)
|
||||
orient = vec4(bf.orient_x, bf.orient_y, bf.orient_z, w)
|
||||
yield f".pos = {pos},"
|
||||
yield f".orient = {orient},"
|
||||
|
||||
def render_md5_anim_base_frame(prefix, base_frame):
|
||||
yield f"struct md5_anim_base_frame {prefix}_base_frame[] = {{"
|
||||
for bf in base_frame:
|
||||
yield "{"
|
||||
yield from _render_md5_anim_base_frame(bf)
|
||||
yield "},"
|
||||
yield "};"
|
||||
|
||||
def render_md5_anim_frames(prefix, frame):
|
||||
for i, anim_frame in enumerate(frame):
|
||||
yield f"float {prefix}_{i}_frame[] = {{"
|
||||
for f in anim_frame.value:
|
||||
yield f"{f:.6f},"
|
||||
yield "};"
|
||||
|
||||
def render_md5_anim_frame(prefix, frame):
|
||||
yield from render_md5_anim_frames(prefix, frame)
|
||||
yield f"float * {prefix}_frame[] = {{"
|
||||
for i, anim_frame in enumerate(frame):
|
||||
yield f"{prefix}_{i}_frame,"
|
||||
yield "};"
|
||||
|
||||
def render_md5_anim(prefix, a):
|
||||
yield f".num_frames = {a.num_frames},"
|
||||
yield f".num_joints = {a.num_joints},"
|
||||
yield f".frame_rate = {a.frame_rate},"
|
||||
yield f".num_animated_components = {a.num_animated_components},"
|
||||
yield f".hierarchy = {prefix}_hierarchy,"
|
||||
yield f".bounds = {prefix}_bounds,"
|
||||
yield f".base_frame = {prefix}_base_frame,"
|
||||
yield f".frame = {prefix}_frame,"
|
||||
|
||||
def render_anim(prefix, a):
|
||||
yield from render_md5_anim_hierarchy(prefix, a.hierarchy)
|
||||
yield from render_md5_anim_bounds(prefix, a.bounds)
|
||||
yield from render_md5_anim_base_frame(prefix, a.base_frame)
|
||||
yield from render_md5_anim_frame(prefix, a.frame)
|
||||
|
||||
yield f"md5_anim {prefix}_anim {{"
|
||||
yield from render_md5_anim(prefix, a)
|
||||
yield "};"
|
||||
|
||||
def render_all(prefix, a):
|
||||
yield from render_anim(prefix, a)
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
buf = f.read()
|
||||
l = [i.strip() for i in buf.split('\n') if i.strip()]
|
||||
a = md5anim.parse_file(l)
|
||||
|
||||
render, out = renderer()
|
||||
render(render_all(sys.argv[2], a))
|
||||
sys.stdout.write(out.getvalue())
|
29193
model/boblamp/boblamp_anim.h
Normal file
29193
model/boblamp/boblamp_anim.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user