Quake 4 integrated with DoomRTX

This commit is contained in:
Justin Marshall
2026-05-09 22:10:40 -07:00
parent 8c4a087aa9
commit d37f87e493
436 changed files with 277587 additions and 10254 deletions
+107
View File
@@ -0,0 +1,107 @@
// DeclLipSync.cpp
//
#include "precompiled.h"
#include "../idLib/Lib.h"
/*
===================
rvDeclPlayerModel::SetLipSyncData
===================
*/
void rvDeclLipSync::SetLipSyncData(const char* lsd, const char* lang) {
if (!strchr(lsd, 37)) {
mLipSyncData.Set(lsd, lang);
return;
}
common->Warning("SetLipSyncData: language %s for lipsync '%s' has invalid character %% in it", lsd, base->GetType());
}
/*
===================
rvDeclPlayerModel::Size
===================
*/
size_t rvDeclLipSync::Size(void) const {
return sizeof(rvDeclLipSync);
}
/*
===================
rvDeclPlayerModel::DefaultDefinition
===================
*/
const char* rvDeclLipSync::DefaultDefinition() const {
return "{ description \"<DEFAULTED>\" }";
}
/*
===================
rvDeclPlayerModel::FreeData
===================
*/
bool rvDeclLipSync::Parse(const char* text, const int textLength) {
idLexer src;
idToken token, token2;
src.LoadMemory(text, textLength, GetFileName(), GetLineNum());
src.SetFlags(DECL_LEXER_FLAGS);
src.SkipUntilString("{");
while (1) {
if (!src.ReadToken(&token)) {
break;
}
if (!token.Icmp("}")) {
break;
}
if (token == "visemes")
{
idToken lang;
idToken data;
src.ReadToken(&lang);
src.ReadToken(&data);
SetLipSyncData(lang.c_str(), data.c_str());
continue;
}
else if (token == "hmm")
{
src.ReadToken(&token);
mHMM = token;
continue;
}
else if (token == "text")
{
src.ReadToken(&token);
mTranscribeText = token;
continue;
}
else if (token == "description")
{
src.ReadToken(&token);
mDescription = token;
continue;
}
else
{
src.Error("Invalid or unexpected token %s\n", token.c_str());
return false;
}
}
return true;
}
/*
===================
rvDeclLipSync::FreeData
===================
*/
void rvDeclLipSync::FreeData(void) {
}
+74
View File
@@ -0,0 +1,74 @@
#ifndef __DECLLIPSYNC_H__
#define __DECLLIPSYNC_H__
// A way of cross referencing strings and sound shaders
// RAVEN BEGIN
// jsinger: added to support serialization/deserialization of binary decls
#ifdef RV_BINARYDECLS
class rvDeclLipSync : public idDecl, public Serializable<'RDLS'>
{
public:
virtual void Write(SerialOutputStream& stream) const;
virtual void AddReferences() const;
rvDeclLipSync(SerialInputStream& stream);
#else
class rvDeclLipSync : public idDecl
{
#endif
// RAVEN END
public:
rvDeclLipSync(void) {}
~rvDeclLipSync(void) {}
void SetDescription(const char* desc) { mDescription = desc; }
const idStr& GetDescription(void) const { return(mDescription); }
void SetHMM(idStr& hmm) { mHMM = hmm; }
const idStr& GetHMM(void) const { return(mHMM); }
void SetTranscribeText(const char* text) { mTranscribeText = text; }
const char* GetTranscribeText(int langIndex = -1) const { return(common->GetLocalizedString(mTranscribeText, langIndex)); }
const char* GetRawTranscribeText(void) const { return(mTranscribeText.c_str()); }
void SetLipSyncData(const char* lsd, const char* lang);
const char* GetLipSyncData(int langIdx = -1) const;
virtual const char* DefaultDefinition(void) const;
virtual bool Parse(const char* text, const int textLength) override;
virtual void FreeData(void);
//virtual bool RebuildTextSource( void );
virtual size_t Size(void) const;
// scork: for detailed error-reporting
//virtual bool Validate( const char *psText, int iTextLength, idStr &strReportTo ) const;
private:
idStr mDescription;
idStr mTranscribeText;
idStr mHMM;
idDict mLipSyncData;
};
ID_INLINE const char* rvDeclLipSync::GetLipSyncData(int langIdx) const
{
//if( common->LanguageHasVO( langIdx ) )
//{
// return( mLipSyncData.GetString( common->GetLanguage( langIdx ) ) );
//}
return(mLipSyncData.GetString("english"));
}
class rvDeclLipSyncEdit
{
public:
virtual ~rvDeclLipSyncEdit() {}
virtual void SetLipSyncDescription(rvDeclLipSync* edit, const char* desc) = 0;
virtual void SetLipSyncTranscribeText(rvDeclLipSync* edit, const char* text) = 0;
virtual void SetLipSyncData(rvDeclLipSync* edit, const char* lsd, const char* lang) = 0;
};
extern rvDeclLipSyncEdit* declLipSyncEdit;
#endif // __DECLLIPSYNC_H__
+381
View File
@@ -0,0 +1,381 @@
/*
===========================================================================
Quake 4 / Raven material type decl support
===========================================================================
*/
#include "precompiled.h"
#pragma hdrstop
#include "../idLib/Lib.h"
idCVar mat_useHitMaterials(
"mat_useHitMaterials",
"1",
CVAR_RENDERER | CVAR_BOOL,
"use hit materials for ray/path tracing material lookup"
);
idCVar mat_writeHitMaterials(
"mat_writeHitMaterials",
"0",
CVAR_RENDERER | CVAR_BOOL,
"write/debug hit material data"
);
/*
================
rvDeclMatType::DefaultDefinition
================
*/
const char* rvDeclMatType::DefaultDefinition(void) const {
return "{ description \"<DEFAULTED>\" rgb 0,0,0 }";
}
/*
================
rvDeclMatType::FreeData
================
*/
void rvDeclMatType::FreeData(void) {
mDescription.Clear();
*(ulong*)mTint = 0;
}
/*
================
rvDeclMatType::Size
================
*/
size_t rvDeclMatType::Size(void) const {
return sizeof(rvDeclMatType) + mDescription.Allocated();
}
/*
================
rvDeclMatType::Parse
================
*/
bool rvDeclMatType::Parse(const char* text, const int textLength, bool noCaching) {
idLexer src;
idToken token;
//parserLineNum = 1;
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 (!src.ReadToken(&token)) {
return false;
}
while (token.Icmp("}") != 0) {
if (token.Icmp("rgb") == 0) {
byte tint[4];
tint[0] = (byte)src.ParseInt();
src.ExpectTokenString(",");
tint[1] = (byte)src.ParseInt();
src.ExpectTokenString(",");
tint[2] = (byte)src.ParseInt();
tint[3] = 0xFF;
SetTint(tint);
}
else if (token.Icmp("description") == 0) {
if (!src.ReadToken(&token)) {
return false;
}
mDescription = token;
}
else {
src.Warning("rvDeclMatType::Parse: unknown token '%s'", token.c_str());
}
if (!src.ReadToken(&token)) {
return false;
}
}
//parserLineNum = 0;
return true;
}
/*
================
rvDeclMatType::Validate
================
*/
bool rvDeclMatType::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;
}
while (src.ReadToken(&token)) {
if (token.Icmp("}") == 0) {
return true;
}
if (token.Icmp("rgb") == 0) {
if (!src.ReadToken(&token)) {
strReportTo += "rgb missing red value.\n";
return false;
}
if (!src.ExpectTokenString(",")) {
strReportTo += "rgb missing comma after red value.\n";
return false;
}
if (!src.ReadToken(&token)) {
strReportTo += "rgb missing green value.\n";
return false;
}
if (!src.ExpectTokenString(",")) {
strReportTo += "rgb missing comma after green value.\n";
return false;
}
if (!src.ReadToken(&token)) {
strReportTo += "rgb missing blue value.\n";
return false;
}
continue;
}
if (token.Icmp("description") == 0) {
if (!src.ReadToken(&token)) {
strReportTo += "description missing string.\n";
return false;
}
continue;
}
strReportTo += va("Unknown token '%s'.\n", token.c_str());
}
strReportTo += "Missing closing brace.\n";
return false;
}
/*
================
MT_FindMaterialTypeByTint
================
*/
const rvDeclMatType* MT_FindMaterialTypeByTint(unsigned long tint) {
const int numMaterialTypes = declManager->GetNumDecls(DECL_MATERIALTYPE);
for (int i = 0; i < numMaterialTypes; i++) {
const rvDeclMatType* matType = static_cast<const rvDeclMatType*>(
declManager->DeclByIndex(DECL_MATERIALTYPE, i, true)
);
if (matType == NULL) {
continue;
}
if (matType->GetTint() == (int)tint) {
return matType;
}
}
return NULL;
}
/*
================
MT_FindMaterialTypeByClosestTint
================
*/
const rvDeclMatType* MT_FindMaterialTypeByClosestTint(unsigned long tint) {
const byte* wanted = reinterpret_cast<const byte*>(&tint);
const rvDeclMatType* bestMatType = NULL;
int bestDist = 0x01000001;
const int numMaterialTypes = declManager->GetNumDecls(DECL_MATERIALTYPE);
for (int i = 0; i < numMaterialTypes; i++) {
const rvDeclMatType* matType = static_cast<const rvDeclMatType*>(
declManager->DeclByIndex(DECL_MATERIALTYPE, i, true)
);
if (matType == NULL) {
continue;
}
const int matTint = matType->GetTint();
const byte* test = reinterpret_cast<const byte*>(&matTint);
const int dr = (int)test[0] - (int)wanted[0];
const int dg = (int)test[1] - (int)wanted[1];
const int db = (int)test[2] - (int)wanted[2];
const int dist = dr * dr + dg * dg + db * db;
if (dist < bestDist) {
bestMatType = matType;
bestDist = dist;
}
}
return bestMatType;
}
/*
================
MT_GetMaterialTypeArray
Returns one byte per source image pixel.
Each byte is the material type decl index.
================
*/
byte* MT_GetMaterialTypeArray(idStr image, int& width, int& height) {
idFile* hitFile = NULL;
if (mat_useHitMaterials.GetBool()) {
image.SetFileExtension(".hit");
hitFile = fileSystem->OpenFileRead(image.c_str(), true);
if (hitFile != NULL) {
hitFile->Read(&height, sizeof(height));
height = LittleLong(height);
hitFile->Read(&width, sizeof(width));
width = LittleLong(width);
const int size = width * height;
byte* data = (byte*)Mem_ClearedAlloc(size);
hitFile->Read(data, size);
fileSystem->CloseFile(hitFile);
return data;
}
image.StripFileExtension();
}
byte* pic = NULL;
renderSystem->LoadImage(image.c_str(), &pic, &width, &height, NULL, false);
if (pic == NULL) {
common->Printf("Failed to load hit material image %s\n", image.c_str());
return NULL;
}
const int size = width * height;
byte* data = (byte*)malloc(size);
byte* dst = data;
byte* src = pic;
for (int i = 0; i < size; i++) {
const unsigned long color = *(unsigned long*)src;
src += 4;
const rvDeclMatType* type = MT_FindMaterialTypeByTint(color);
if (type == NULL) {
type = MT_FindMaterialTypeByClosestTint(color);
}
if (type != NULL) {
*dst++ = (byte)type->Index();
}
else {
*dst++ = 0;
}
}
free(pic);
if (mat_writeHitMaterials.GetBool()) {
idStr hitImage = image;
hitImage.SetFileExtension(".hit");
hitFile = fileSystem->OpenFileWrite(hitImage.c_str(), "fs_savepath");
if (hitFile != NULL) {
const int littleHeight = LittleLong(height);
const int littleWidth = LittleLong(width);
hitFile->Write(&littleHeight, sizeof(littleHeight));
hitFile->Write(&littleWidth, sizeof(littleWidth));
hitFile->Write(data, size);
fileSystem->CloseFile(hitFile);
}
}
return data;
}
#ifdef RV_BINARYDECLS
/*
================
rvDeclMatType::rvDeclMatType
================
*/
rvDeclMatType::rvDeclMatType(SerialInputStream& stream) {
*(ulong*)mTint = 0;
stream.ReadString(mDescription);
stream.Read(mTint, sizeof(mTint));
}
/*
================
rvDeclMatType::Write
================
*/
void rvDeclMatType::Write(SerialOutputStream& stream) const {
stream.WriteString(mDescription);
stream.Write(mTint, sizeof(mTint));
}
/*
================
rvDeclMatType::AddReferences
================
*/
void rvDeclMatType::AddReferences(void) const {
}
#endif
+53
View File
@@ -0,0 +1,53 @@
#ifndef __DECLMATTYPE_H__
#define __DECLMATTYPE_H__
// Defines a material type - such as concrete, metal, glass etc
#ifdef RV_BINARYDECLS
class rvDeclMatType : public idDecl, public Serializable<'RDMT'>
{
public:
// jsinger: allow exporting of this decl type in a preparsed form
virtual void Write(SerialOutputStream& stream) const;
virtual void AddReferences() const;
rvDeclMatType(SerialInputStream& stream);
#else
class rvDeclMatType : public idDecl
{
public:
#endif
rvDeclMatType(void) { *(ulong*)mTint = 0; }
~rvDeclMatType(void) {}
void SetDescription(idStr& desc) { mDescription = desc; }
const idStr& GetDescription(void) const { return(mDescription); }
void SetTint(byte tint[4]) { *(ulong*)mTint = *(ulong*)tint; }
int GetTint(void) const { return(*(int*)mTint); }
float GetRed(void) const { return(mTint[0] / 255.0f); }
float GetGreen(void) const { return(mTint[1] / 255.0f); }
float GetBlue(void) const { return(mTint[2] / 255.0f); }
virtual const char* DefaultDefinition(void) const;
virtual bool Parse(const char* text, const int textLength, bool noCaching);
virtual void FreeData(void);
virtual size_t Size(void) const;
// RAVEN BEGIN
// jscott: to prevent a recursive crash
virtual bool RebuildTextSource(void) { return(false); }
// scork: for detailed error-reporting
virtual bool Validate(const char* psText, int iTextLength, idStr& strReportTo) const;
// RAVEN END
private:
idStr mDescription;
byte mTint[4];
};
byte* MT_GetMaterialTypeArray(idStr image, int& width, int& height);
#endif // __DECLMATTYPE_H__
+976
View File
@@ -0,0 +1,976 @@
/*
===========================================================================
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
+185
View File
@@ -0,0 +1,185 @@
#ifndef __DECLPLAYBACK_H__
#define __DECLPLAYBACK_H__
// WARNING: These must stay mirrored in both Q4Monster.state
#define PBFL_GET_POSITION BIT( 0 ) // Stored in playback file
#define PBFL_GET_ANGLES BIT( 1 )
#define PBFL_GET_BUTTONS BIT( 2 )
#define PBFL_GET_VELOCITY BIT( 4 ) // Derived from data
#define PBFL_GET_ACCELERATION BIT( 5 )
#define PBFL_GET_ANGLES_FROM_VEL BIT( 6 )
#define PBFL_AT_DEST BIT( 7 )
#define PBFL_RELATIVE_POSITION BIT( 8 )
#define PBFL_ED_MODIFIED BIT( 29 )
#define PBFL_ED_NEW BIT( 30 )
#define PBFL_ED_CHECKEDIN BIT( 31 )
#define PBFL_ED_MASK ( PBFL_ED_MODIFIED | PBFL_ED_NEW | PBFL_ED_CHECKEDIN )
#define PBCB_NONE 0
#define PBCB_BUTTON_DOWN 1
#define PBCB_BUTTON_UP 2
#define PBCB_IMPULSE 3
typedef void ( *pbCallback_t )( int type, float time, const void *data );
class rvDeclPlaybackData
{
public:
void Init( void ) { entity = NULL; Callback = NULL; position.Zero(); velocity.Zero(); acceleration.Zero(); angles.Zero(); changed = 0; button = 0; impulse = 0; }
void SetPosition( const idVec3 &pos ) { position = pos; }
void SetVelocity( const idVec3 &vel ) { velocity = vel; }
void SetAcceleration( const idVec3 &accel ) { acceleration = accel; }
void SetAngles( const idAngles &ang ) { angles = ang; }
void SetChanged( const byte chg ) { changed = chg; }
void SetButtons( const byte btn ) { button = btn; }
void SetImpulse( const byte imp ) { impulse = imp; }
const idVec3 &GetPosition( void ) const { return( position ); }
const idVec3 &GetVelocity( void ) const { return( velocity ); }
const idVec3 &GetAcceleration( void ) const { return( acceleration ); }
const idAngles &GetAngles( void ) const { return( angles ); }
byte GetChanged( void ) const { return( changed ); }
byte GetButtons( void ) const { return( button ); }
byte GetImpulse( void ) const { return( impulse ); }
class idEntity *GetEntity( void ) const { return( entity ); }
void SetCallback( class idEntity *ent, pbCallback_t cb ) { entity = ent; Callback = cb; }
void CallCallback( int type, float time ) { if( Callback ) { Callback( type, time, this ); } }
private:
class idEntity *entity;
pbCallback_t Callback;
idVec3 position;
idVec3 velocity;
idVec3 acceleration;
idAngles angles;
byte changed;
byte button;
byte impulse;
};
class rvButtonState
{
public:
void Init( float t, byte b = 0, byte i = 0 ) { time = t; state = b; impulse = i; }
float time;
byte state;
byte impulse;
};
#ifdef RV_BINARYDECLS
class rvDeclPlayback : public idDecl, public Serializable<'RDP '>
{
public:
// jsinger: allow exporting of this decl type in a preparsed form
virtual void Write( SerialOutputStream &stream ) const;
virtual void AddReferences() const;
rvDeclPlayback( SerialInputStream &stream );
#else
class rvDeclPlayback : public idDecl
{
#endif
public:
rvDeclPlayback( void );
~rvDeclPlayback( void );
void SetFlag( bool on, int flag ) { on ? flags |= flag : flags &= ~flag; }
bool GetHasPositions( void ) const { return( !!( flags & PBFL_GET_POSITION ) ); }
bool GetHasAngles( void ) const { return( !!( flags & PBFL_GET_ANGLES ) ); }
bool GetHasButtons( void ) const { return( !!( flags & PBFL_GET_BUTTONS ) ); }
bool GetEditorModified( void ) const { return( !!( flags & PBFL_ED_MODIFIED ) ); }
bool GetEditorNew( void ) const { return( !!( flags & PBFL_ED_NEW ) ); }
bool GetEditorCheckedIn( void ) const { return( !!( flags & PBFL_ED_CHECKEDIN ) ); }
void SetHasPositions( bool pos ) { SetFlag( pos, PBFL_GET_POSITION ); }
void SetHasAngles( bool ang ) { SetFlag( ang, PBFL_GET_ANGLES ); }
void SetHasButtons( bool btn ) { SetFlag( btn, PBFL_GET_BUTTONS ); }
void SetEditorModified( bool em ) { SetFlag( em, PBFL_ED_MODIFIED ); }
void SetEditorNew( bool en ) { SetFlag( en, PBFL_ED_NEW ); }
void SetEditorCheckedIn( bool eci ) { SetFlag( eci, PBFL_ED_CHECKEDIN ); }
int GetFlags( void ) const { return( flags ); }
void SetFlags( int in ) { flags = in; }
float GetFrameRate( void ) const { return( frameRate ); }
void SetFrameRate( float in ) { frameRate = in; }
idVec3 GetOrigin( void ) const { return( origin ); }
void SetOrigin( idVec3 &in ) { origin = in; }
float GetDuration( void ) const { return( duration ); }
void SetDuration( float dur ) { duration = dur; }
idBounds GetBounds( void ) const { return( bounds ); }
void ParseSample( idLexer *src, idVec3 &pos, idAngles &ang );
void WriteData( idFile_Memory &f );
void WriteButtons( idFile_Memory &f );
void WriteSequence( idFile_Memory &f );
bool ParseData( idLexer *src );
void ParseButton( idLexer *src, byte &button, rvButtonState &state );
bool ParseSequence( idLexer *src );
bool ParseButtons( idLexer *src );
void Copy( rvDeclPlayback *pb );
void SetOrigin( void );
void Start( void );
bool Finish( float desiredDuration = -1.0f );
bool SetCurrentData( float localTime, int control, rvDeclPlaybackData *pbd );
bool GetCurrentOffset( float localTime, idVec3 &pos ) const;
bool GetCurrentAngles( float localTime, idAngles &ang ) const;
bool GetCurrentData( int control, float localTime, float lastTime, rvDeclPlaybackData *pbd ) const;
virtual const char *DefaultDefinition( void ) const;
virtual bool Parse( const char *text, const int textLength );
virtual void FreeData( void );
virtual bool RebuildTextSource( void );
virtual size_t Size( void ) const;
// RAVEN BEGIN
// scork: for detailed error-reporting
virtual bool Validate( const char *psText, int iTextLength, idStr &strReportTo ) const;
// RAVEN END
idCurve_UniformCubicBSpline<idVec3> &GetPoints( void ) { return( points ); }
idCurve_UniformCubicBSpline<idAngles> &GetAngles( void ) { return( angles ); }
idList<rvButtonState> &GetButtons( void ) { return( buttons ); }
private:
int flags;
float frameRate;
float duration;
idVec3 origin;
idBounds bounds;
idCurve_UniformCubicBSpline<idVec3> points;
idCurve_UniformCubicBSpline<idAngles> angles;
idList<rvButtonState> buttons;
};
class rvDeclPlaybackEdit
{
public:
virtual ~rvDeclPlaybackEdit() {}
virtual bool Finish( rvDeclPlayback *edit, float desiredDuration ) = 0;
virtual void SetOrigin( rvDeclPlayback *edit ) = 0;
virtual void SetOrigin( rvDeclPlayback *edit, idVec3 &origin ) = 0;
virtual void Copy( rvDeclPlayback *edit, rvDeclPlayback *copy ) = 0;
};
extern rvDeclPlaybackEdit *declPlaybackEdit;
#endif // __DECLPLAYBACK_H__
+126
View File
@@ -0,0 +1,126 @@
#include "precompiled.h"
#pragma hdrstop
#include "../idLib/Lib.h"
rvDeclPlayerModel::rvDeclPlayerModel() {
FreeData();
}
/*
===================
rvDeclPlayerModel::Size
===================
*/
size_t rvDeclPlayerModel::Size(void) const {
return sizeof(rvDeclPlayerModel);
}
/*
===================
rvDeclPlayerModel::DefaultDefinition
===================
*/
const char* rvDeclPlayerModel::DefaultDefinition() const {
return "{\n\t\"model\"\t\"model_player_marine\"\n\t\"def_head\"\t\"char_marinehead_kane2_client\"\n\t\"def_head_ui\"\t\"char_marinehead_kane2_mp\"\n\t\"skin\"\t\"skins/multiplayer/marine\"\n}";
}
/*
===================
rvDeclPlayerModel::FreeData
===================
*/
bool rvDeclPlayerModel::Parse(const char* text, const int textLength) {
idLexer src;
idToken token;
FreeData();
src.LoadMemory(text, textLength, GetFileName(), GetLineNum());
src.SetFlags(DECL_LEXER_FLAGS);
src.SkipUntilString("{");
while (1) {
if (!src.ReadToken(&token)) {
break;
}
if (!token.Icmp("}")) {
break;
}
if (!token.Icmp("head_offset")) {
src.Parse1DMatrix(3, headOffset.ToFloatPtr());
continue;
}
idToken value;
if (!src.ReadToken(&value)) {
src.Error("Unexpected end of file parsing key '%s' in playerModel decl '%s'", token.c_str(), GetName());
return false;
}
if (!token.Icmp("model")) {
model = value;
}
else if (!token.Icmp("def_head") || !token.Icmp("head")) {
head = value;
}
else if (!token.Icmp("def_head_ui") || !token.Icmp("ui_head")) {
uiHead = value;
}
else if (!token.Icmp("skin")) {
skin = value;
}
else if (!token.Icmp("team")) {
team = value;
}
else if (!token.Icmp("description")) {
description = value;
}
else if (!idStr::Cmpn(token.c_str(), "snd_", 4)) {
sounds.Set(token.c_str(), value.c_str());
}
}
if (model.Length() <= 0) {
src.Error("playerModel decl '%s' without model declaration", GetName());
return false;
}
if (!head.Length()) {
head = uiHead;
}
if (!uiHead.Length()) {
uiHead = head;
}
return true;
}
/*
===================
rvDeclPlayerModel::FreeData
===================
*/
void rvDeclPlayerModel::FreeData(void) {
model.Clear();
head.Clear();
headOffset.Zero();
uiHead.Clear();
team.Clear();
skin.Clear();
description.Clear();
sounds.Clear();
}
/*
===================
rvDeclPlayerModel::DefaultDefinition
===================
*/
void rvDeclPlayerModel::Print(void) {
}
+41
View File
@@ -0,0 +1,41 @@
//----------------------------------------------------------------
// DeclPlayerModel.h
//
// Copyright 2002-2006 Raven Software
//----------------------------------------------------------------
#ifndef __DECLPLAYERMODEL_H__
#define __DECLPLAYERMODEL_H__
/*
===============================================================================
rvDeclPlayerModel
===============================================================================
*/
class rvDeclPlayerModel : public idDecl {
public:
rvDeclPlayerModel();
idStr model;
idStr head;
idVec3 headOffset;
idStr uiHead;
idStr team;
idStr skin;
idStr description;
idDict sounds;
virtual size_t Size( void ) const;
virtual const char * DefaultDefinition() const;
virtual bool Parse( const char *text, const int textLength );
virtual void FreeData( void );
virtual void Print( void );
virtual bool RebuildTextSource( void ) { return( false ); }
//virtual bool Validate( const char *psText, int iTextLength, idStr &strReportTo ) const;
};
#endif