#include "md2model.hpp" #include "md2rep.hpp" #include "std.hpp" struct MD2Model::Rep : public MD2Rep { int ref_cnt; Rep(const string& f) : MD2Rep(f), ref_cnt(1) {} }; MD2Model::MD2Model(const string& f) : rep(new Rep(f)), anim_mode(0), anim_time(0), render_a(0), render_b(0), render_t(0), trans_verts(0) {} MD2Model::MD2Model(const MD2Model& t) : Model(t), rep(t.rep), anim_mode(0), anim_time(0), render_a(0), render_b(0), render_t(0), trans_verts(0) { ++rep->ref_cnt; } MD2Model::~MD2Model() { if (!--rep->ref_cnt) delete rep; if (trans_verts) delete[] trans_verts; } void MD2Model::startMD2Anim(int first, int last, int mode, float speed, float trans) { if (last < first) std::swap(first, last); if (first < 0) first = 0; else if (first >= rep->numFrames()) first = rep->numFrames() - 1; if (last < 0) last = 0; else if (last >= rep->numFrames()) last = rep->numFrames() - 1; if (trans > 0) { if (!trans_verts) trans_verts = new MD2Rep::Vert[rep->numVertices()]; if (anim_mode & 0x8000) rep->render(trans_verts, anim_time, trans_time); else rep->render(trans_verts, render_a, render_b, render_t); trans_speed = 1.0f / trans; trans_time = 0; mode |= 0x8000; } anim_first = first; anim_last = last; anim_len = last - first; anim_speed = speed; anim_time = ((mode & 0x7fff) == Animator::ANIM_MODE_LOOP || anim_speed >= 0) ? anim_first : anim_last; anim_mode = mode; if (!anim_speed || !anim_len) { render_a = render_b = anim_time; render_t = 0; anim_mode &= 0x8000; } } void MD2Model::animate(float e) { Model::animate(e); if (!anim_mode) return; if (anim_mode & 0x8000) { trans_time += trans_speed; if (trans_time < 1) return; anim_mode &= ~0x8000; if (!anim_mode) return; } anim_time = anim_time + anim_speed * e; if (anim_time < anim_first) { switch (anim_mode) { case Animator::ANIM_MODE_LOOP: anim_time += anim_len; break; case Animator::ANIM_MODE_PINGPONG: anim_time = anim_first + (anim_first - anim_time); anim_speed = -anim_speed; break; default: anim_time = anim_first; anim_mode = 0; break; } } else if (anim_time >= anim_last) { switch (anim_mode) { case Animator::ANIM_MODE_LOOP: anim_time -= anim_len; break; case Animator::ANIM_MODE_PINGPONG: anim_time = anim_last - (anim_time - anim_last); anim_speed = -anim_speed; break; default: anim_time = anim_last; anim_mode = 0; break; } } render_a = floor(anim_time); render_b = render_a + 1; if (anim_mode == Animator::ANIM_MODE_LOOP && render_b == anim_last) render_b = anim_first; render_t = anim_time - render_a; } bool MD2Model::render(const RenderContext& rc) { static Frustum f; new (&f) Frustum(rc.getWorldFrustum(), -getRenderTform()); if (!f.cull(rep->getBox())) return false; if (anim_mode & 0x8000) { rep->render(this, trans_verts, anim_time, trans_time); } else { rep->render(this, render_a, render_b, render_t); } return false; } int MD2Model::getMD2AnimLength() const { return rep->numFrames(); } bool MD2Model::getValid() const { return rep->numFrames() > 0; }