9using namespace Tempest;
13 moverKeyFrames = mover.keyframes;
14 behavior = mover.behavior;
15 speedType = mover.speed_mode;
16 lerpType = mover.lerp_mode;
17 autoRotate = mover.auto_rotate;
18 sfxOpenStart = mover.sfx_open_start;
19 stayOpenTime = uint64_t(mover.stay_open_time_sec * 1000.f);
20 sfxOpenEnd = mover.sfx_open_end;
21 sfxCloseStart = mover.sfx_close_start;
22 sfxCloseEnd = mover.sfx_close_end;
23 sfxMoving = mover.sfx_transitioning;
24 visualName = mover.visual->name;
26 if(mover.cd_dynamic || mover.cd_static) {
31 const float speed = mover.speed;
32 keyframes.resize(moverKeyFrames.size());
33 for(
size_t i=0; i<moverKeyFrames.size(); ++i) {
34 auto& f0 = moverKeyFrames[i];
35 auto& f1 = moverKeyFrames[(i+1)%moverKeyFrames.size()];
36 auto dx = (f1.position.x-f0.position.x);
37 auto dy = (f1.position.y-f0.position.y);
38 auto dz = (f1.position.z-f0.position.z);
40 float theta = 2.f*std::pow(f1.rotation.x*f0.rotation.x + f1.rotation.y*f0.rotation.y + f1.rotation.z*f0.rotation.z + f1.rotation.w*f0.rotation.w, 2.f) - 1.f;
41 float angle = float(std::acos(std::clamp(theta, -1.f, 1.f))*180.0/M_PI);
42 float len = Vec3(dx,dy,dz).length();
50 static const float rotationThreshold = 0.01f;
53 if(len>rotationThreshold)
54 ticks = uint64_t(len/speed);
else
55 ticks = uint64_t((angle/360.f) * 1000.f/scaleRotSpeed(speed));
56 keyframes[i].ticks = std::max<uint64_t>(1,ticks);
61 if(frame<moverKeyFrames.size())
62 tr =
mkMatrix(moverKeyFrames[frame]);
68 MoveTrigger::moveEvent();
73 fout.
write(pos0,uint8_t(state),frameTime,frame,targetFrame);
78 fin.
read(pos0,
reinterpret_cast<uint8_t&
>(state),frameTime,frame);
80 fin.
read(targetFrame);
87float MoveTrigger::scaleRotSpeed(
float speed)
const {
113 const float sFactor = 300;
114 const float sFactorBoat = 7;
115 const float lowSpeed = 0.006f;
117 return sFactorBoat*speed;
119 return sFactor*speed;
127void MoveTrigger::emitSound(std::string_view snd,
bool freeSlot)
const {
133void MoveTrigger::invalidateView() {
143void MoveTrigger::moveEvent() {
150 if(moverKeyFrames.size()<2 || keyframes[0].ticks==0)
155 case zenkit::MoverBehavior::TOGGLE: {
156 if((frame==0 && state==Idle) || state==Close)
161 case zenkit::MoverBehavior::TRIGGER_CONTROL: {
162 if(frame==0 && state==Idle)
166 case zenkit::MoverBehavior::OPEN_TIME: {
172 case zenkit::MoverBehavior::LOOP: {
176 case zenkit::MoverBehavior::SINGLE_KEYS: {
180 preProcessTrigger(prev);
184 if(keyframes.size()<2 || keyframes[0].ticks==0)
186 if(behavior!=zenkit::MoverBehavior::TRIGGER_CONTROL)
188 if(frame>0 && state==Idle) {
196 if(keyframes.size()<2 || keyframes[0].ticks==0)
200 if(behavior!=zenkit::MoverBehavior::SINGLE_KEYS)
206 case zenkit::MoverMessageType::NEXT:
207 targetFrame = nextFrame(frame);
209 case zenkit::MoverMessageType::PREVIOUS:
210 targetFrame = prevFrame(frame);
212 case zenkit::MoverMessageType::FIXED_DIRECT:
213 case zenkit::MoverMessageType::FIXED_ORDER:
214 targetFrame = uint32_t(evt.
move.
key);
220void MoveTrigger::preProcessTrigger(State prev) {
221 if(prev==state || state==Idle)
224 targetFrame = uint32_t(keyframes.size())-1;
225 emitSound(sfxOpenStart);
227 frameTime = keyframes[frame].ticks - frameTime;
228 frame = nextFrame(frame);
232 else if(state==Close) {
234 emitSound(sfxCloseStart);
236 frame = prevFrame(frame);
237 frameTime = keyframes[frame].ticks - frameTime;
245void MoveTrigger::postProcessTrigger() {
251 emitSound(sfxOpenEnd);
253 emitSound(sfxCloseEnd);
254 if(behavior==zenkit::MoverBehavior::OPEN_TIME && state==Open) {
263uint32_t MoveTrigger::nextFrame(uint32_t i)
const {
264 uint32_t size = uint32_t(keyframes.size());
265 if(behavior==zenkit::MoverBehavior::LOOP)
267 return std::min<uint32_t>(i+1, size-1);
270uint32_t MoveTrigger::prevFrame(uint32_t i)
const {
271 uint32_t size = uint32_t(keyframes.size());
272 if(behavior==zenkit::MoverBehavior::LOOP)
273 return (i+size-1)%size;
274 return std::max<uint32_t>(i, 1) - 1;
280 if(state==OpenTimed) {
281 if(frameTime<=stayOpenTime)
285 frameTime -= stayOpenTime;
287 if(frame==targetFrame) {
288 postProcessTrigger();
293 emitSound(sfxMoving);
296void MoveTrigger::updateFrame() {
297 uint32_t f = (state==Close) ? prevFrame(frame) : frame;
298 if(frameTime<keyframes[f].ticks)
301 frame = prevFrame(frame);
else
302 frame = nextFrame(frame);
306 void MoveTrigger::advanceAnim() {
307 uint32_t f1 = (state==Close) ? prevFrame(frame) : frame;
308 uint32_t f2 = nextFrame(f1);
309 float a = calcProgress(f1,f2);
310 auto m = calcTransform(f1,f2,a);
316float MoveTrigger::calcProgress(uint32_t f1, uint32_t f2)
const {
317 float a = float(frameTime)/float(keyframes[f1].ticks);
318 a = std::clamp(a,0.f,1.f);
321 bool start = (f1==0 && state!=Loop);
322 bool end = (f2==moverKeyFrames.size()-1 && state!=Loop);
324 case zenkit::MoverSpeedType::CONSTANT:
326 case zenkit::MoverSpeedType::SLOW_START_END:
327 case zenkit::MoverSpeedType::SEGMENT_SLOW_START_END:
328 if((start && end) || speedType==zenkit::MoverSpeedType::SEGMENT_SLOW_START_END)
333 a = ((1 - a)*a + 1)*a;
335 case zenkit::MoverSpeedType::SLOW_START:
336 case zenkit::MoverSpeedType::SEGMENT_SLOW_START:
337 if(start || speedType==zenkit::MoverSpeedType::SEGMENT_SLOW_START)
340 case zenkit::MoverSpeedType::SLOW_END:
341 case zenkit::MoverSpeedType::SEGMENT_SLOW_END:
342 if(end || speedType==zenkit::MoverSpeedType::SEGMENT_SLOW_END)
343 a = ((1 - a)*a + 1)*a;
346 return std::clamp(a,0.f,1.f);
349Matrix4x4 MoveTrigger::calcTransform(uint32_t f1, uint32_t f2,
float a)
const {
350 zenkit::AnimationSample fr = {};
352 if(lerpType==zenkit::MoverLerpType::LINEAR) {
353 auto& pos1 = moverKeyFrames[f1].position;
354 auto& pos2 = moverKeyFrames[f2].position;
355 fr =
mix(moverKeyFrames[f1],moverKeyFrames[f2],a);
356 forward = {pos2.x-pos1.x,pos2.y-pos1.y,pos2.z-pos1.z};
358 auto& kF0 = moverKeyFrames[prevFrame(f1)].position;
359 auto& kF1 = moverKeyFrames[f1].position;
360 auto& kF2 = moverKeyFrames[f2].position;
361 auto& kF3 = moverKeyFrames[nextFrame(f2)].position;
362 Vec3 p0 = {kF0.x,kF0.y,kF0.z};
363 Vec3 p1 = {kF1.x,kF1.y,kF1.z};
364 Vec3 p2 = {kF2.x,kF2.y,kF2.z};
365 Vec3 p3 = {kF3.x,kF3.y,kF3.z};
366 Vec3 b1 = -p0 + p1 - p2 + p3;
367 Vec3 b2 = 2*p0 - 2*p1 + p2 - p3;
369 Vec3 pos = ((b1*a + b2)*a + b3)*a + p1;
370 forward = (3*b1*a + 2*b2)*a + b3;
371 fr.position.x = pos.x;
372 fr.position.y = pos.y;
373 fr.position.z = pos.z;
374 fr.rotation =
slerp(moverKeyFrames[f1].rotation,moverKeyFrames[f2].rotation,a);
379 Vec3 z = Vec3::normalize(forward);
380 Vec3 up = std::abs(z.y)<0.999f ? Vec3(0,1,0) : Vec3(1,0,0);
381 Vec3 x = Vec3::normalize(Vec3::crossProduct(up,z));
382 Vec3 y = Vec3::crossProduct(z,x);
384 x.x, y.x, z.x, fr.position.x,
385 x.y, y.y, z.y, fr.position.y,
386 x.z, y.z, z.z, fr.position.z,
static Tempest::Matrix4x4 mkMatrix(float x, float y, float z, float w, float px, float py, float pz)
zenkit::Quat slerp(const zenkit::Quat &x, const zenkit::Quat &y, float a)
void load(Serialize &fin) override
void save(Serialize &fout) const override
void moveEvent() override
void setObjMatrix(const Tempest::Matrix4x4 &mt)
void save(Serialize &fout) const override
void onTrigger(const TriggerEvent &evt) override
void onGotoMsg(const TriggerEvent &evt) override
MoveTrigger(Vob *parent, World &world, const zenkit::VMover &data, Flags flags)
void onUntrigger(const TriggerEvent &evt) override
void tick(uint64_t dt) override
void load(Serialize &fin) override
void setObjMatrix(const Tempest::Matrix4x4 &m)
static const ProtoMesh * loadMesh(std::string_view name)
void write(const Arg &... a)
zenkit::MoverMessageType msg
struct TriggerEvent::@26 move
virtual bool isDynamic() const
void setLocalTransform(const Tempest::Matrix4x4 &p)
auto localTransform() const -> const Tempest::Matrix4x4 &
auto transform() const -> const Tempest::Matrix4x4 &
Tempest::Vec3 position() const
void triggerEvent(const TriggerEvent &e)
DynamicWorld * physic() const
std::string_view name() const
MeshObjects::Mesh addView(std::string_view visual) const
MeshObjects::Mesh addStaticView(const ProtoMesh *visual, bool staticDraw)
static float mix(float x, float y, float a)