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 "bitmap.h"
|
||||
#include "m_argv.h"
|
||||
#include "gamestruct.h"
|
||||
#include "gamecontrol.h"
|
||||
#include "palettecontainer.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> },
|
||||
{ "newgamechoices", parseEmptyBlock },
|
||||
{ "rffdefineid", parseRffDefineId },
|
||||
{ "defineqav", parseDefineQAV },
|
||||
{ nullptr, nullptr },
|
||||
};
|
||||
|
||||
|
|
|
@ -122,6 +122,9 @@ struct GameInterface
|
|||
virtual int Voxelize(int sprnum) { return -1; }
|
||||
virtual void AddExcludedEpisode(FString episode) {}
|
||||
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()
|
||||
{
|
||||
|
|
|
@ -150,6 +150,9 @@ struct GameInterface : public ::GameInterface
|
|||
void LeavePortal(spritetype* viewer, int type) override;
|
||||
void LoadGameTextures() 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;
|
||||
};
|
||||
|
|
|
@ -46,23 +46,22 @@ enum
|
|||
};
|
||||
|
||||
static TMap<FString, QAVPrevTileFinder> qavPrevTileFinders;
|
||||
static TMap<int, TMap<int, TArray<int>>> qavSkippedFrameTiles;
|
||||
static TMap<int, QAVInterpProps> qavInterpProps;
|
||||
|
||||
static void qavInitTileFinderMap()
|
||||
{
|
||||
// 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;
|
||||
});
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
// 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)
|
||||
{
|
||||
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.
|
||||
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)
|
||||
{
|
||||
return &prevFrame->tiles[j];
|
||||
}
|
||||
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)
|
||||
|
@ -89,6 +85,21 @@ QAVPrevTileFinder qavGetInterpType(const FString& 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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
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 tileY = y;
|
||||
|
|
|
@ -244,6 +244,14 @@ struct QAVInterpProps
|
|||
{
|
||||
int flags;
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue