mirror of
https://github.com/ZDoom/raze-gles.git
synced 2024-11-10 14:52:01 +00:00
- Blood: Implement defineqav
DEF parser with hookup to game-side code.
This commit is contained in:
parent
da78160cd1
commit
916241dcdb
5 changed files with 196 additions and 9 deletions
|
@ -40,6 +40,7 @@
|
||||||
#include "buildtiles.h"
|
#include "buildtiles.h"
|
||||||
#include "bitmap.h"
|
#include "bitmap.h"
|
||||||
#include "m_argv.h"
|
#include "m_argv.h"
|
||||||
|
#include "gamestruct.h"
|
||||||
#include "gamecontrol.h"
|
#include "gamecontrol.h"
|
||||||
#include "palettecontainer.h"
|
#include "palettecontainer.h"
|
||||||
#include "mapinfo.h"
|
#include "mapinfo.h"
|
||||||
|
@ -2008,6 +2009,166 @@ void parseModel(FScanner& sc, FScriptPosition& pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
static bool parseDefineQAVInterpolateIgnoreBlock(FScanner& sc, const int& res_id, TMap<int, TArray<int>>& ignoredata, const int& numframes)
|
||||||
|
{
|
||||||
|
FScanner::SavedPos blockend;
|
||||||
|
FScriptPosition pos = sc;
|
||||||
|
|
||||||
|
FString scframes, sctiles;
|
||||||
|
TArray<int> framearray, tilearray;
|
||||||
|
|
||||||
|
if (sc.StartBraces(&blockend))
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: malformed syntax, unable to continue", res_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (!sc.FoundEndBrace(blockend))
|
||||||
|
{
|
||||||
|
sc.GetString();
|
||||||
|
if (sc.Compare("frames")) sc.GetString(scframes);
|
||||||
|
else if (sc.Compare("tiles")) sc.GetString(sctiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm we received something for 'frames' and 'tiles'.
|
||||||
|
if (scframes.IsEmpty() || sctiles.IsEmpty())
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: unable to get any values for 'frames' or 'tiles', unable to continue", res_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto arraybuilder = [&](const FString& input, TArray<int>& output, const int& maxvalue) -> bool
|
||||||
|
{
|
||||||
|
// Split input if it is an array, otherwise push the singular value twice.
|
||||||
|
if (input.IndexOf("-") != -1)
|
||||||
|
{
|
||||||
|
auto temparray = input.Split("-");
|
||||||
|
for (auto& value : temparray) output.Push(atoi(value));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto tempvalue = atoi(input);
|
||||||
|
for (auto i = 0; i < 2; i++) output.Push(tempvalue);
|
||||||
|
}
|
||||||
|
if (output.Size() != 2 || output[0] > output[1] || output[1] > maxvalue)
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): interpolate: ignore: value of '%s' is malformed, unable to continue", res_id, input.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!arraybuilder(scframes, framearray, numframes - 1)) return false;
|
||||||
|
if (!arraybuilder(sctiles, tilearray, 7)) return false;
|
||||||
|
|
||||||
|
// Process arrays and add ignored frames as required.
|
||||||
|
for (auto i = framearray[0]; i <= framearray[1]; i++)
|
||||||
|
{
|
||||||
|
auto& frametiles = ignoredata[i];
|
||||||
|
for (auto j = tilearray[0]; j <= tilearray[1]; j++)
|
||||||
|
{
|
||||||
|
if (!frametiles.Contains(j)) frametiles.Push(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parseDefineQAVInterpolateBlock(FScanner& sc, const int& res_id, const int& numframes)
|
||||||
|
{
|
||||||
|
FScanner::SavedPos blockend;
|
||||||
|
FScriptPosition pos = sc;
|
||||||
|
|
||||||
|
FString interptype;
|
||||||
|
bool loopable = false;
|
||||||
|
TMap<int, TArray<int>> ignoredata;
|
||||||
|
|
||||||
|
if (sc.StartBraces(&blockend))
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): malformed syntax, unable to continue", res_id, interptype.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (!sc.FoundEndBrace(blockend))
|
||||||
|
{
|
||||||
|
sc.GetString();
|
||||||
|
if (sc.Compare("type"))
|
||||||
|
{
|
||||||
|
sc.GetString(interptype);
|
||||||
|
if (!gi->IsQAVInterpTypeValid(interptype))
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): interpolate (%s): interpolation type not found", res_id, interptype.GetChars());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sc.Compare("loopable")) loopable = true;
|
||||||
|
else if (sc.Compare("ignore")) if (!parseDefineQAVInterpolateIgnoreBlock(sc, res_id, ignoredata, numframes)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add interpolation properties to game for processing while drawing.
|
||||||
|
gi->AddQAVInterpProps(res_id, interptype, loopable, ignoredata);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseDefineQAV(FScanner& sc, FScriptPosition& pos)
|
||||||
|
{
|
||||||
|
FScanner::SavedPos blockend;
|
||||||
|
FString fn;
|
||||||
|
int res_id = -1;
|
||||||
|
int numframes = -1;
|
||||||
|
bool interpolate = false;
|
||||||
|
|
||||||
|
if (!sc.GetNumber(res_id, true))
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav: invalid or non-defined resource ID");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sc.StartBraces(&blockend))
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): malformed syntax, unable to continue", res_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (!sc.FoundEndBrace(blockend))
|
||||||
|
{
|
||||||
|
sc.MustGetString();
|
||||||
|
if (sc.Compare("file"))
|
||||||
|
{
|
||||||
|
sc.GetString(fn);
|
||||||
|
|
||||||
|
// Test file's validity.
|
||||||
|
FixPathSeperator(fn);
|
||||||
|
auto lump = fileSystem.FindFile(fn);
|
||||||
|
if (lump < 0)
|
||||||
|
{
|
||||||
|
pos.Message(MSG_ERROR, "defineqav (%d): file '%s' could not be found", res_id, fn.GetChars());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read file to get number of frames from QAV, skipping first 8 bytes.
|
||||||
|
auto fr = fileSystem.OpenFileReader(lump);
|
||||||
|
fr.ReadUInt64();
|
||||||
|
numframes = fr.ReadInt32();
|
||||||
|
}
|
||||||
|
else if (sc.Compare("interpolate"))
|
||||||
|
{
|
||||||
|
interpolate = true;
|
||||||
|
if (!parseDefineQAVInterpolateBlock(sc, res_id, numframes)) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're not interpolating, remove any reference to interpolation data for this res_id.
|
||||||
|
if (!interpolate) gi->RemoveQAVInterpProps(res_id);
|
||||||
|
|
||||||
|
// Add new file to filesystem.
|
||||||
|
fileSystem.CreatePathlessCopy(fn, res_id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -2098,6 +2259,7 @@ static const dispatch basetokens[] =
|
||||||
{ "shadefactor", parseSkip<1> },
|
{ "shadefactor", parseSkip<1> },
|
||||||
{ "newgamechoices", parseEmptyBlock },
|
{ "newgamechoices", parseEmptyBlock },
|
||||||
{ "rffdefineid", parseRffDefineId },
|
{ "rffdefineid", parseRffDefineId },
|
||||||
|
{ "defineqav", parseDefineQAV },
|
||||||
{ nullptr, nullptr },
|
{ nullptr, nullptr },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -122,6 +122,9 @@ struct GameInterface
|
||||||
virtual int Voxelize(int sprnum) { return -1; }
|
virtual int Voxelize(int sprnum) { return -1; }
|
||||||
virtual void AddExcludedEpisode(FString episode) {}
|
virtual void AddExcludedEpisode(FString episode) {}
|
||||||
virtual int GetCurrentSkill() { return -1; }
|
virtual int GetCurrentSkill() { return -1; }
|
||||||
|
virtual bool IsQAVInterpTypeValid(const FString& type) { return false; }
|
||||||
|
virtual void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) { }
|
||||||
|
virtual void RemoveQAVInterpProps(const int& res_id) { }
|
||||||
|
|
||||||
virtual FString statFPS()
|
virtual FString statFPS()
|
||||||
{
|
{
|
||||||
|
|
|
@ -150,6 +150,9 @@ struct GameInterface : public ::GameInterface
|
||||||
void LeavePortal(spritetype* viewer, int type) override;
|
void LeavePortal(spritetype* viewer, int type) override;
|
||||||
void LoadGameTextures() override;
|
void LoadGameTextures() override;
|
||||||
int GetCurrentSkill() override;
|
int GetCurrentSkill() override;
|
||||||
|
bool IsQAVInterpTypeValid(const FString& type) override;
|
||||||
|
void AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata) override;
|
||||||
|
void RemoveQAVInterpProps(const int& res_id) override;
|
||||||
|
|
||||||
GameStats getStats() override;
|
GameStats getStats() override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,23 +46,22 @@ enum
|
||||||
};
|
};
|
||||||
|
|
||||||
static TMap<FString, QAVPrevTileFinder> qavPrevTileFinders;
|
static TMap<FString, QAVPrevTileFinder> qavPrevTileFinders;
|
||||||
static TMap<int, TMap<int, TArray<int>>> qavSkippedFrameTiles;
|
|
||||||
static TMap<int, QAVInterpProps> qavInterpProps;
|
static TMap<int, QAVInterpProps> qavInterpProps;
|
||||||
|
|
||||||
static void qavInitTileFinderMap()
|
static void qavInitTileFinderMap()
|
||||||
{
|
{
|
||||||
// Interpolate between frames if the picnums match. This is safest but could miss interpolations between suitable picnums.
|
// Interpolate between frames if the picnums match. This is safest but could miss interpolations between suitable picnums.
|
||||||
qavPrevTileFinders.Insert("interpolate-picnum", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
qavPrevTileFinders.Insert("picnum", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
||||||
return prevFrame->tiles[i].picnum == thisFrame->tiles[i].picnum ? &prevFrame->tiles[i] : nullptr;
|
return prevFrame->tiles[i].picnum == thisFrame->tiles[i].picnum ? &prevFrame->tiles[i] : nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Interpolate between frames if the picnum is valid. This can be problematic if tile indices change between frames.
|
// Interpolate between frames if the picnum is valid. This can be problematic if tile indices change between frames.
|
||||||
qavPrevTileFinders.Insert("interpolate-index", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
qavPrevTileFinders.Insert("index", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
||||||
return prevFrame->tiles[i].picnum > 0 ? &prevFrame->tiles[i] : nullptr;
|
return prevFrame->tiles[i].picnum > 0 ? &prevFrame->tiles[i] : nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find previous frame by iterating all previous frame's tiles and return on first matched x coordinate.
|
// Find previous frame by iterating all previous frame's tiles and return on first matched x coordinate.
|
||||||
qavPrevTileFinders.Insert("interpolate-x", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
qavPrevTileFinders.Insert("x", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
||||||
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].x == prevFrame->tiles[j].x)
|
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].x == prevFrame->tiles[j].x)
|
||||||
{
|
{
|
||||||
return &prevFrame->tiles[j];
|
return &prevFrame->tiles[j];
|
||||||
|
@ -71,16 +70,13 @@ static void qavInitTileFinderMap()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Find previous frame by iterating all previous frame's tiles and return on first matched y coordinate.
|
// Find previous frame by iterating all previous frame's tiles and return on first matched y coordinate.
|
||||||
qavPrevTileFinders.Insert("interpolate-y", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
qavPrevTileFinders.Insert("y", [](FRAMEINFO* const thisFrame, FRAMEINFO* const prevFrame, const int& i) -> TILE_FRAME* {
|
||||||
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].y == prevFrame->tiles[j].y)
|
for (int j = 0; j < 8; j++) if (thisFrame->tiles[i].y == prevFrame->tiles[j].y)
|
||||||
{
|
{
|
||||||
return &prevFrame->tiles[j];
|
return &prevFrame->tiles[j];
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
});
|
});
|
||||||
|
|
||||||
// When type is unspecified, default to using the safest interpolation option.
|
|
||||||
qavPrevTileFinders.Insert("interpolate", *qavPrevTileFinders.CheckKey("interpolate-picnum"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QAVPrevTileFinder qavGetInterpType(const FString& type)
|
QAVPrevTileFinder qavGetInterpType(const FString& type)
|
||||||
|
@ -89,6 +85,21 @@ QAVPrevTileFinder qavGetInterpType(const FString& type)
|
||||||
return *qavPrevTileFinders.CheckKey(type);
|
return *qavPrevTileFinders.CheckKey(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GameInterface::IsQAVInterpTypeValid(const FString& type)
|
||||||
|
{
|
||||||
|
return qavGetInterpType(type) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInterface::AddQAVInterpProps(const int& res_id, const FString& interptype, const bool& loopable, const TMap<int, TArray<int>>& ignoredata)
|
||||||
|
{
|
||||||
|
qavInterpProps.Insert(res_id, { loopable << kQAVIsLoopable, qavGetInterpType(interptype), ignoredata });
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameInterface::RemoveQAVInterpProps(const int& res_id)
|
||||||
|
{
|
||||||
|
qavInterpProps.Remove(res_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int stat, int shade, int palnum, bool to3dview)
|
void DrawFrame(double x, double y, double z, double a, TILE_FRAME *pTile, int stat, int shade, int palnum, bool to3dview)
|
||||||
{
|
{
|
||||||
|
@ -147,7 +158,7 @@ void QAV::Draw(double x, double y, int ticks, int stat, int shade, int palnum, b
|
||||||
if (thisFrame->tiles[i].picnum > 0)
|
if (thisFrame->tiles[i].picnum > 0)
|
||||||
{
|
{
|
||||||
TILE_FRAME* const thisTile = &thisFrame->tiles[i];
|
TILE_FRAME* const thisTile = &thisFrame->tiles[i];
|
||||||
TILE_FRAME* const prevTile = interpolate ? interpdata->PrevTileFinder(thisFrame, prevFrame, i) : nullptr;
|
TILE_FRAME* const prevTile = interpolate && interpdata->CanInterpFrameTile(nFrame, i) ? interpdata->PrevTileFinder(thisFrame, prevFrame, i) : nullptr;
|
||||||
|
|
||||||
double tileX = x;
|
double tileX = x;
|
||||||
double tileY = y;
|
double tileY = y;
|
||||||
|
|
|
@ -244,6 +244,14 @@ struct QAVInterpProps
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
QAVPrevTileFinder PrevTileFinder;
|
QAVPrevTileFinder PrevTileFinder;
|
||||||
|
TMap<int, TArray<int>> IgnoreData;
|
||||||
|
|
||||||
|
bool CanInterpFrameTile(const int& nFrame, const int& i)
|
||||||
|
{
|
||||||
|
// Check whether the current frame's tile is skippable.
|
||||||
|
auto thisFrame = IgnoreData.CheckKey(nFrame);
|
||||||
|
return thisFrame ? !thisFrame->Contains(i) : true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QAV* getQAV(int res_id);
|
QAV* getQAV(int res_id);
|
||||||
|
|
Loading…
Reference in a new issue