mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 16:21:04 +02:00
976 lines
18 KiB
C++
976 lines
18 KiB
C++
/*
|
|
===========================================================================
|
|
|
|
Quake 4 / Raven playback decl support
|
|
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "DeclPlayback.h"
|
|
|
|
rvDeclPlaybackEdit* declPlaybackEdit = NULL;
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::rvDeclPlayback
|
|
================
|
|
*/
|
|
rvDeclPlayback::rvDeclPlayback(void) {
|
|
flags = 0;
|
|
frameRate = 15.0f;
|
|
duration = 0.0f;
|
|
|
|
origin.Zero();
|
|
|
|
bounds.Clear();
|
|
|
|
//points.SetGranularity(16);
|
|
//angles.SetGranularity(16);
|
|
//buttons.SetGranularity(16);
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::~rvDeclPlayback
|
|
================
|
|
*/
|
|
rvDeclPlayback::~rvDeclPlayback(void) {
|
|
FreeData();
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::DefaultDefinition
|
|
================
|
|
*/
|
|
const char* rvDeclPlayback::DefaultDefinition(void) const {
|
|
return "{ sequence { } data { } }";
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::FreeData
|
|
================
|
|
*/
|
|
void rvDeclPlayback::FreeData(void) {
|
|
points.Clear();
|
|
angles.Clear();
|
|
buttons.Clear();
|
|
|
|
flags = 0;
|
|
frameRate = 15.0f;
|
|
duration = 0.0f;
|
|
|
|
origin.Zero();
|
|
bounds.Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Size
|
|
================
|
|
*/
|
|
size_t rvDeclPlayback::Size(void) const {
|
|
return sizeof(rvDeclPlayback) +
|
|
points.GetNumValues() * sizeof(idVec3) +
|
|
angles.GetNumValues() * sizeof(idAngles) +
|
|
buttons.Num() * sizeof(rvButtonState);
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::ParseSample
|
|
================
|
|
*/
|
|
void rvDeclPlayback::ParseSample(idLexer* src, idVec3& pos, idAngles& ang) {
|
|
idToken token;
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("pos") == 0) {
|
|
pos.x = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
pos.y = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
pos.z = src->ParseFloat();
|
|
|
|
SetHasPositions(true);
|
|
}
|
|
else if (token.Icmp("ang") == 0) {
|
|
ang.pitch = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
ang.yaw = src->ParseFloat();
|
|
ang.roll = 0.0f;
|
|
|
|
SetHasAngles(true);
|
|
}
|
|
else if (token.Icmp("rotate") == 0) {
|
|
ang.pitch = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
ang.yaw = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
ang.roll = src->ParseFloat();
|
|
|
|
SetHasAngles(true);
|
|
}
|
|
else if (token.Icmp("down") == 0 ||
|
|
token.Icmp("up") == 0 ||
|
|
token.Icmp("impulse") == 0) {
|
|
src->ParseInt();
|
|
}
|
|
else {
|
|
src->Warning("rvDeclPlayback::ParseSample: unknown token '%s'", token.c_str());
|
|
}
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::ParseData
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::ParseData(idLexer* src) {
|
|
idToken token;
|
|
idVec3 pos;
|
|
idAngles ang;
|
|
float time;
|
|
|
|
time = 0.0f;
|
|
pos.Zero();
|
|
ang.Zero();
|
|
|
|
src->ExpectTokenString("{");
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("{") == 0) {
|
|
ParseSample(src, pos, ang);
|
|
|
|
points.AddValue(time, pos);
|
|
angles.AddValue(time, ang);
|
|
|
|
if (frameRate > 0.0f) {
|
|
time += 1.0f / frameRate;
|
|
}
|
|
}
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
duration = time;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::ParseButton
|
|
================
|
|
*/
|
|
void rvDeclPlayback::ParseButton(idLexer* src, byte& button, rvButtonState& state) {
|
|
idToken token;
|
|
float time;
|
|
byte impulse;
|
|
|
|
impulse = 0;
|
|
time = src->ParseFloat();
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
state.Init(time, button, impulse);
|
|
return;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("down") == 0) {
|
|
button |= (byte)src->ParseInt();
|
|
}
|
|
else if (token.Icmp("up") == 0) {
|
|
button &= ~(byte)src->ParseInt();
|
|
}
|
|
else if (token.Icmp("impulse") == 0) {
|
|
impulse = (byte)src->ParseInt();
|
|
}
|
|
else {
|
|
src->Warning("rvDeclPlayback::ParseButton: unknown token '%s'", token.c_str());
|
|
}
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
state.Init(time, button, impulse);
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::ParseButtons
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::ParseButtons(idLexer* src) {
|
|
idToken token;
|
|
byte button;
|
|
rvButtonState state;
|
|
|
|
button = 0;
|
|
|
|
src->ExpectTokenString("{");
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("{") == 0) {
|
|
ParseButton(src, button, state);
|
|
buttons.Append(state);
|
|
SetHasButtons(true);
|
|
}
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::ParseSequence
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::ParseSequence(idLexer* src) {
|
|
idToken token;
|
|
|
|
src->ExpectTokenString("sequence");
|
|
src->ExpectTokenString("{");
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("origin") == 0) {
|
|
origin.x = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
origin.y = src->ParseFloat();
|
|
src->ExpectTokenString(",");
|
|
origin.z = src->ParseFloat();
|
|
}
|
|
else if (token.Icmp("framerate") == 0 || token.Icmp("frameRate") == 0) {
|
|
frameRate = src->ParseFloat();
|
|
}
|
|
else if (token.Icmp("destination") == 0) {
|
|
idStr deprecated;
|
|
src->ParseRestOfLine(deprecated);
|
|
}
|
|
else {
|
|
src->Error("Invalid token %s in file %s.\n", token.c_str(), GetName());
|
|
return false;
|
|
}
|
|
|
|
if (!src->ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Parse
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::Parse(const char* text, const int textLength) {
|
|
idLexer src;
|
|
idToken token;
|
|
|
|
FreeData();
|
|
|
|
src.LoadMemory(text, textLength, GetFileName(), GetLineNum());
|
|
src.SetFlags(
|
|
LEXFL_NOSTRINGCONCAT |
|
|
LEXFL_NOSTRINGESCAPECHARS |
|
|
LEXFL_ALLOWPATHNAMES |
|
|
LEXFL_ALLOWMULTICHARLITERALS |
|
|
LEXFL_ALLOWBACKSLASHSTRINGCONCAT |
|
|
LEXFL_NOFATALERRORS |
|
|
LEXFL_ALLOWIPADDRESSES
|
|
);
|
|
|
|
src.SkipUntilString("{");
|
|
|
|
if (!ParseSequence(&src)) {
|
|
return false;
|
|
}
|
|
|
|
if (!src.ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
|
|
while (token.Icmp("}") != 0) {
|
|
if (token.Icmp("data") == 0) {
|
|
if (!ParseData(&src)) {
|
|
return false;
|
|
}
|
|
}
|
|
else if (token.Icmp("buttons") == 0) {
|
|
if (!ParseButtons(&src)) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
src.Warning("rvDeclPlayback::Parse: unknown token '%s'", token.c_str());
|
|
}
|
|
|
|
if (!src.ReadToken(&token)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
SetOrigin();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::WriteSequence
|
|
================
|
|
*/
|
|
void rvDeclPlayback::WriteSequence(idFile_Memory& f) {
|
|
f.WriteFloatString("\tsequence\n\t{\n");
|
|
f.WriteFloatString("\t\torigin\t\t%.1f,%.1f,%.1f\n", origin.x, origin.y, origin.z);
|
|
f.WriteFloatString("\t\tframeRate\t%.1f\n", frameRate);
|
|
f.WriteFloatString("\t}\n");
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::WriteData
|
|
================
|
|
*/
|
|
void rvDeclPlayback::WriteData(idFile_Memory& f) {
|
|
idVec3 oldPos;
|
|
idAngles oldAng;
|
|
|
|
oldPos.Zero();
|
|
oldAng.Zero();
|
|
|
|
if ((points.GetNumValues() == 0 && angles.GetNumValues() == 0) || !(flags & (PBFL_GET_POSITION | PBFL_GET_ANGLES))) {
|
|
return;
|
|
}
|
|
|
|
f.WriteFloatString("\tdata\n\t{\n");
|
|
|
|
for (int i = 0; i < points.GetNumValues(); i++) {
|
|
f.WriteFloatString("\t\t{ ");
|
|
|
|
if (flags & PBFL_GET_POSITION) {
|
|
const idVec3& pos = points.GetValue(i);
|
|
|
|
if (i == 0 || idMath::Fabs(pos.x - oldPos.x) > 0.0625f ||
|
|
idMath::Fabs(pos.y - oldPos.y) > 0.0625f ||
|
|
idMath::Fabs(pos.z - oldPos.z) > 0.0625f) {
|
|
f.WriteFloatString("pos %.1f,%.1f,%.1f ", pos.x, pos.y, pos.z);
|
|
oldPos = pos;
|
|
}
|
|
}
|
|
|
|
if (flags & PBFL_GET_ANGLES) {
|
|
const idAngles& ang = angles.GetValue(i);
|
|
|
|
if (i == 0 || idMath::Fabs(ang.pitch - oldAng.pitch) > 0.0625f ||
|
|
idMath::Fabs(ang.yaw - oldAng.yaw) > 0.0625f ||
|
|
idMath::Fabs(ang.roll - oldAng.roll) > 0.0625f) {
|
|
if (ang.roll == 0.0f) {
|
|
f.WriteFloatString("ang %.1f,%.1f ", ang.pitch, ang.yaw);
|
|
}
|
|
else {
|
|
f.WriteFloatString("rotate %.1f,%.1f,%.1f ", ang.pitch, ang.yaw, ang.roll);
|
|
}
|
|
|
|
oldAng = ang;
|
|
}
|
|
}
|
|
|
|
f.WriteFloatString("}\n");
|
|
}
|
|
|
|
f.WriteFloatString("\t}\n");
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::WriteButtons
|
|
================
|
|
*/
|
|
void rvDeclPlayback::WriteButtons(idFile_Memory& f) {
|
|
byte oldState;
|
|
|
|
if (buttons.Num() == 0 || !(flags & PBFL_GET_BUTTONS)) {
|
|
return;
|
|
}
|
|
|
|
oldState = 0;
|
|
|
|
f.WriteFloatString("\tbuttons\n\t{\n");
|
|
|
|
for (int i = 0; i < buttons.Num(); i++) {
|
|
const rvButtonState& button = buttons[i];
|
|
const byte changed = oldState ^ button.state;
|
|
|
|
if (changed == 0 && button.impulse == 0) {
|
|
continue;
|
|
}
|
|
|
|
f.WriteFloatString("\t\t{ %.3g ", button.time);
|
|
|
|
if (changed != 0) {
|
|
if (button.state & changed) {
|
|
f.WriteFloatString("down %d ", button.state & changed);
|
|
}
|
|
|
|
if (oldState & changed) {
|
|
f.WriteFloatString("up %d ", oldState & changed);
|
|
}
|
|
|
|
oldState = button.state;
|
|
}
|
|
|
|
if (button.impulse != 0) {
|
|
f.WriteFloatString("impulse %d ", button.impulse);
|
|
}
|
|
|
|
f.WriteFloatString("}\n");
|
|
}
|
|
|
|
f.WriteFloatString("\t}\n");
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::RebuildTextSource
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::RebuildTextSource(void) {
|
|
#if 0
|
|
idFile_Memory f;
|
|
|
|
f.WriteFloatString("\nplayback %s\n{\n", GetName());
|
|
WriteSequence(f);
|
|
WriteData(f);
|
|
WriteButtons(f);
|
|
f.WriteFloatString("}\n\n");
|
|
|
|
SetText(f.GetDataPtr());
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Start
|
|
================
|
|
*/
|
|
void rvDeclPlayback::Start(void) {
|
|
origin.Zero();
|
|
|
|
bounds.Clear();
|
|
|
|
points.Clear();
|
|
angles.Clear();
|
|
buttons.Clear();
|
|
|
|
//points.SetGranularity(60);
|
|
//angles.SetGranularity(60);
|
|
//buttons.SetGranularity(60);
|
|
|
|
duration = 0.0f;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::SetOrigin
|
|
================
|
|
*/
|
|
void rvDeclPlayback::SetOrigin(void) {
|
|
if (points.GetNumValues() <= 0) {
|
|
return;
|
|
}
|
|
|
|
const idVec3 first = points.GetValue(0);
|
|
|
|
origin += first;
|
|
|
|
bounds.Clear();
|
|
|
|
for (int i = 0; i < points.GetNumValues(); i++) {
|
|
idVec3 p = points.GetValue(i);
|
|
p -= first;
|
|
|
|
points.SetValue(i, p);
|
|
bounds.AddPoint(p);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Copy
|
|
================
|
|
*/
|
|
void rvDeclPlayback::Copy(rvDeclPlayback* pb) {
|
|
flags = pb->flags & ~PBFL_ED_MASK;
|
|
frameRate = pb->frameRate;
|
|
duration = pb->duration;
|
|
origin = pb->origin;
|
|
bounds = pb->bounds;
|
|
|
|
points = pb->points;
|
|
angles = pb->angles;
|
|
buttons = pb->buttons;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::SetCurrentData
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::SetCurrentData(float localTime, int control, rvDeclPlaybackData* pbd) {
|
|
if (control & PBFL_GET_POSITION) {
|
|
points.AddValue(localTime, pbd->GetPosition());
|
|
SetHasPositions(true);
|
|
}
|
|
|
|
if (control & PBFL_GET_ANGLES) {
|
|
angles.AddValue(localTime, pbd->GetAngles());
|
|
SetHasAngles(true);
|
|
}
|
|
|
|
if (control & PBFL_GET_BUTTONS) {
|
|
rvButtonState state;
|
|
state.Init(localTime, pbd->GetButtons(), pbd->GetImpulse());
|
|
|
|
buttons.Append(state);
|
|
SetHasButtons(true);
|
|
}
|
|
|
|
if (localTime > duration) {
|
|
duration = localTime;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::GetCurrentOffset
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::GetCurrentOffset(float localTime, idVec3& pos) const {
|
|
if (points.GetNumValues() <= 0) {
|
|
pos.Zero();
|
|
return false;
|
|
}
|
|
|
|
pos = points.GetCurrentValue(localTime);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::GetCurrentAngles
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::GetCurrentAngles(float localTime, idAngles& ang) const {
|
|
if (angles.GetNumValues() <= 0) {
|
|
ang.Zero();
|
|
return false;
|
|
}
|
|
|
|
ang = angles.GetCurrentValue(localTime);
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::GetCurrentData
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::GetCurrentData(int control, float localTime, float lastTime, rvDeclPlaybackData* pbd) const {
|
|
byte changed;
|
|
|
|
if (pbd == NULL) {
|
|
return false;
|
|
}
|
|
|
|
changed = 0;
|
|
|
|
if (control & PBFL_GET_POSITION) {
|
|
idVec3 offset;
|
|
|
|
if (GetCurrentOffset(localTime, offset)) {
|
|
if (control & PBFL_RELATIVE_POSITION) {
|
|
pbd->SetPosition(offset);
|
|
}
|
|
else {
|
|
pbd->SetPosition(origin + offset);
|
|
}
|
|
|
|
changed |= PBFL_GET_POSITION;
|
|
}
|
|
}
|
|
|
|
if (control & PBFL_GET_ANGLES) {
|
|
idAngles currentAngles;
|
|
|
|
if (GetCurrentAngles(localTime, currentAngles)) {
|
|
pbd->SetAngles(currentAngles);
|
|
changed |= PBFL_GET_ANGLES;
|
|
}
|
|
}
|
|
|
|
if (control & PBFL_GET_VELOCITY) {
|
|
idVec3 now;
|
|
idVec3 prev;
|
|
float delta;
|
|
|
|
delta = localTime - lastTime;
|
|
if (delta <= 0.0f) {
|
|
delta = 1.0f / Max(frameRate, 1.0f);
|
|
}
|
|
|
|
if (GetCurrentOffset(localTime, now) && GetCurrentOffset(localTime - delta, prev)) {
|
|
pbd->SetVelocity((now - prev) / delta);
|
|
changed |= PBFL_GET_VELOCITY;
|
|
}
|
|
}
|
|
|
|
if (control & PBFL_GET_ACCELERATION) {
|
|
idVec3 now;
|
|
idVec3 prev;
|
|
idVec3 prev2;
|
|
float delta;
|
|
|
|
delta = localTime - lastTime;
|
|
if (delta <= 0.0f) {
|
|
delta = 1.0f / Max(frameRate, 1.0f);
|
|
}
|
|
|
|
if (GetCurrentOffset(localTime, now) &&
|
|
GetCurrentOffset(localTime - delta, prev) &&
|
|
GetCurrentOffset(localTime - delta * 2.0f, prev2)) {
|
|
const idVec3 vel0 = (now - prev) / delta;
|
|
const idVec3 vel1 = (prev - prev2) / delta;
|
|
|
|
pbd->SetAcceleration((vel0 - vel1) / delta);
|
|
changed |= PBFL_GET_ACCELERATION;
|
|
}
|
|
}
|
|
|
|
if (control & PBFL_GET_ANGLES_FROM_VEL) {
|
|
const idVec3& vel = pbd->GetVelocity();
|
|
|
|
if (vel.LengthSqr() > 0.0001f) {
|
|
pbd->SetAngles(vel.ToAngles());
|
|
changed |= PBFL_GET_ANGLES;
|
|
}
|
|
}
|
|
|
|
if (control & PBFL_GET_BUTTONS) {
|
|
byte currentButton;
|
|
byte impulse;
|
|
|
|
currentButton = 0;
|
|
impulse = 0;
|
|
|
|
for (int i = 0; i < buttons.Num(); i++) {
|
|
const rvButtonState& state = buttons[i];
|
|
|
|
if (state.time > localTime) {
|
|
break;
|
|
}
|
|
|
|
currentButton = state.state;
|
|
|
|
if (state.time > lastTime && state.time <= localTime) {
|
|
const byte previousButton = pbd->GetButtons();
|
|
const byte down = state.state & ~previousButton;
|
|
const byte up = previousButton & ~state.state;
|
|
|
|
if (down) {
|
|
pbd->SetButtons(state.state);
|
|
pbd->CallCallback(PBCB_BUTTON_DOWN, state.time);
|
|
}
|
|
|
|
if (up) {
|
|
pbd->SetButtons(state.state);
|
|
pbd->CallCallback(PBCB_BUTTON_UP, state.time);
|
|
}
|
|
|
|
if (state.impulse) {
|
|
impulse = state.impulse;
|
|
pbd->SetImpulse(impulse);
|
|
pbd->CallCallback(PBCB_IMPULSE, state.time);
|
|
}
|
|
}
|
|
}
|
|
|
|
pbd->SetButtons(currentButton);
|
|
pbd->SetImpulse(impulse);
|
|
|
|
changed |= PBFL_GET_BUTTONS;
|
|
}
|
|
|
|
pbd->SetChanged(changed);
|
|
|
|
return changed != 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Finish
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::Finish(float desiredDuration) {
|
|
rvDeclPlayback temp;
|
|
float speed;
|
|
|
|
SetOrigin();
|
|
|
|
temp.Copy(this);
|
|
|
|
FreeData();
|
|
|
|
flags = temp.flags;
|
|
frameRate = temp.frameRate;
|
|
origin = temp.origin;
|
|
|
|
if (desiredDuration >= 0.0f) {
|
|
duration = desiredDuration;
|
|
speed = temp.duration / Max(desiredDuration, 0.001f);
|
|
}
|
|
else {
|
|
duration = temp.duration;
|
|
speed = 1.0f;
|
|
}
|
|
|
|
for (int i = 0; i < temp.buttons.Num(); i++) {
|
|
const rvButtonState& src = temp.buttons[i];
|
|
|
|
if (i == 0 || src.state != temp.buttons[i - 1].state || src.impulse != 0) {
|
|
rvButtonState dst;
|
|
dst.Init(src.time / speed, src.state, src.impulse);
|
|
buttons.Append(dst);
|
|
}
|
|
}
|
|
|
|
float oldTime = 0.0f;
|
|
float newTime = 0.0f;
|
|
const float step = 1.0f / Max(frameRate, 1.0f);
|
|
|
|
while (oldTime <= temp.duration) {
|
|
rvDeclPlaybackData pbd;
|
|
pbd.Init();
|
|
|
|
temp.GetCurrentData(PBFL_GET_POSITION | PBFL_GET_ANGLES, oldTime, 0.0f, &pbd);
|
|
|
|
points.AddValue(newTime, pbd.GetPosition() - origin);
|
|
angles.AddValue(newTime, pbd.GetAngles());
|
|
|
|
oldTime += step * speed;
|
|
newTime += step;
|
|
}
|
|
|
|
//common->UpdateScreen();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Validate
|
|
================
|
|
*/
|
|
bool rvDeclPlayback::Validate(const char* psText, int iTextLength, idStr& strReportTo) const {
|
|
idLexer src;
|
|
idToken token;
|
|
|
|
src.LoadMemory(psText, iTextLength, GetFileName(), GetLineNum());
|
|
src.SetFlags(
|
|
LEXFL_NOSTRINGCONCAT |
|
|
LEXFL_NOSTRINGESCAPECHARS |
|
|
LEXFL_ALLOWPATHNAMES |
|
|
LEXFL_ALLOWMULTICHARLITERALS |
|
|
LEXFL_ALLOWBACKSLASHSTRINGCONCAT |
|
|
LEXFL_NOFATALERRORS |
|
|
LEXFL_ALLOWIPADDRESSES
|
|
);
|
|
|
|
if (!src.SkipUntilString("{")) {
|
|
strReportTo += "Missing opening brace.\n";
|
|
return false;
|
|
}
|
|
|
|
if (!src.ReadToken(&token) || token.Icmp("sequence") != 0) {
|
|
strReportTo += "Missing sequence block.\n";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlaybackEditLocal
|
|
================
|
|
*/
|
|
class rvDeclPlaybackEditLocal : public rvDeclPlaybackEdit {
|
|
public:
|
|
virtual bool Finish(rvDeclPlayback* edit, float desiredDuration) {
|
|
return edit->Finish(desiredDuration);
|
|
}
|
|
|
|
virtual void SetOrigin(rvDeclPlayback* edit) {
|
|
edit->SetOrigin();
|
|
}
|
|
|
|
virtual void SetOrigin(rvDeclPlayback* edit, idVec3& origin) {
|
|
edit->SetOrigin(origin);
|
|
}
|
|
|
|
virtual void Copy(rvDeclPlayback* edit, rvDeclPlayback* copy) {
|
|
edit->Copy(copy);
|
|
}
|
|
};
|
|
|
|
static rvDeclPlaybackEditLocal declPlaybackEditLocal;
|
|
|
|
/*
|
|
================
|
|
DeclPlayback_Init
|
|
================
|
|
*/
|
|
void DeclPlayback_Init(void) {
|
|
declPlaybackEdit = &declPlaybackEditLocal;
|
|
}
|
|
|
|
/*
|
|
================
|
|
DeclPlayback_Shutdown
|
|
================
|
|
*/
|
|
void DeclPlayback_Shutdown(void) {
|
|
if (declPlaybackEdit == &declPlaybackEditLocal) {
|
|
declPlaybackEdit = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef RV_BINARYDECLS
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::rvDeclPlayback
|
|
================
|
|
*/
|
|
rvDeclPlayback::rvDeclPlayback(SerialInputStream& stream) {
|
|
flags = stream.ReadInt();
|
|
frameRate = stream.ReadFloat();
|
|
duration = stream.ReadFloat();
|
|
|
|
stream.ReadVec3(origin);
|
|
stream.ReadBounds(bounds);
|
|
|
|
int count = stream.ReadInt();
|
|
for (int i = 0; i < count; i++) {
|
|
float t;
|
|
idVec3 v;
|
|
|
|
t = stream.ReadFloat();
|
|
stream.ReadVec3(v);
|
|
|
|
points.AddValue(t, v);
|
|
}
|
|
|
|
count = stream.ReadInt();
|
|
for (int i = 0; i < count; i++) {
|
|
float t;
|
|
idAngles a;
|
|
|
|
t = stream.ReadFloat();
|
|
stream.ReadAngles(a);
|
|
|
|
angles.AddValue(t, a);
|
|
}
|
|
|
|
count = stream.ReadInt();
|
|
for (int i = 0; i < count; i++) {
|
|
rvButtonState state;
|
|
|
|
state.time = stream.ReadFloat();
|
|
state.state = stream.ReadByte();
|
|
state.impulse = stream.ReadByte();
|
|
|
|
buttons.Append(state);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::Write
|
|
================
|
|
*/
|
|
void rvDeclPlayback::Write(SerialOutputStream& stream) const {
|
|
stream.WriteInt(flags);
|
|
stream.WriteFloat(frameRate);
|
|
stream.WriteFloat(duration);
|
|
|
|
stream.WriteVec3(origin);
|
|
stream.WriteBounds(bounds);
|
|
|
|
stream.WriteInt(points.GetNumValues());
|
|
for (int i = 0; i < points.GetNumValues(); i++) {
|
|
stream.WriteFloat(points.GetTime(i));
|
|
stream.WriteVec3(points.GetValue(i));
|
|
}
|
|
|
|
stream.WriteInt(angles.GetNumValues());
|
|
for (int i = 0; i < angles.GetNumValues(); i++) {
|
|
stream.WriteFloat(angles.GetTime(i));
|
|
stream.WriteAngles(angles.GetValue(i));
|
|
}
|
|
|
|
stream.WriteInt(buttons.Num());
|
|
for (int i = 0; i < buttons.Num(); i++) {
|
|
stream.WriteFloat(buttons[i].time);
|
|
stream.WriteByte(buttons[i].state);
|
|
stream.WriteByte(buttons[i].impulse);
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
rvDeclPlayback::AddReferences
|
|
================
|
|
*/
|
|
void rvDeclPlayback::AddReferences(void) const {
|
|
}
|
|
|
|
#endif |