Skip to content

Commit

Permalink
#6092: Action parsing code and unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Sep 6, 2022
1 parent 5f23cd9 commit dcac59a
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 60 deletions.
15 changes: 15 additions & 0 deletions include/ifx.h
Expand Up @@ -81,6 +81,21 @@ class IFxAction

// Offset from the origin of the entity (or bind point) this action is located at
virtual const Vector3& getOffset() = 0;

// Axis of the model, mutually exclusive with angle
virtual const Vector3& getAxis() = 0;

// Alternate way of setting the axis of the model
virtual const Vector3& getAngle() = 0;

// Returns the name of the action containing the light which should be used
virtual const std::string& getUseLight() = 0;

// Attach to external light (a light not defined in the effect) for fading.
virtual const std::string& getAttachLight() = 0;

// Attach to an external entity
virtual const std::string& getAttachEntity() = 0;
};

class IFxDeclaration :
Expand Down
115 changes: 56 additions & 59 deletions radiantcore/fx/FxAction.cpp
Expand Up @@ -25,7 +25,10 @@ FxAction::FxAction(FxDeclaration& fx) :
_restart(false),
_fadeInTimeInSeconds(0),
_fadeOutTimeInSeconds(0),
_decalSize(0)
_decalSize(0),
_offset(0,0,0),
_axis(0,0,0),
_angle(0,0,0)
{}

FxAction::Type FxAction::getType()
Expand Down Expand Up @@ -128,6 +131,31 @@ const Vector3& FxAction::getOffset()
return _offset;
}

const Vector3& FxAction::getAxis()
{
return _axis;
}

const Vector3& FxAction::getAngle()
{
return _angle;
}

const std::string& FxAction::getUseLight()
{
return _useLightAction;
}

const std::string& FxAction::getAttachLight()
{
return _attachLightName;
}

const std::string& FxAction::getAttachEntity()
{
return _attachEntityName;
}

void FxAction::parseFromTokens(parser::DefTokeniser& tokeniser)
{
while (tokeniser.hasMoreTokens())
Expand Down Expand Up @@ -214,69 +242,38 @@ void FxAction::parseFromTokens(parser::DefTokeniser& tokeniser)
tokeniser.assertNextToken(",");
_offset.z() = string::convert<float>(tokeniser.nextToken());
}
#if 0
if (!token.Icmp("axis")) {
idVec3 v;
v.x = src.ParseFloat();
src.ExpectTokenString(",");
v.y = src.ParseFloat();
src.ExpectTokenString(",");
v.z = src.ParseFloat();
v.Normalize();
FXAction.axis = v.ToMat3();
FXAction.explicitAxis = true;
continue;
else if (token == "axis")
{
_axis.x() = string::convert<float>(tokeniser.nextToken());
tokeniser.assertNextToken(",");
_axis.y() = string::convert<float>(tokeniser.nextToken());
tokeniser.assertNextToken(",");
_axis.z() = string::convert<float>(tokeniser.nextToken());
}

if (!token.Icmp("angle")) {
idAngles a;
a[0] = src.ParseFloat();
src.ExpectTokenString(",");
a[1] = src.ParseFloat();
src.ExpectTokenString(",");
a[2] = src.ParseFloat();
FXAction.axis = a.ToMat3();
FXAction.explicitAxis = true;
continue;
else if (token == "angle")
{
_angle.x() = string::convert<float>(tokeniser.nextToken());
tokeniser.assertNextToken(",");
_angle.y() = string::convert<float>(tokeniser.nextToken());
tokeniser.assertNextToken(",");
_angle.z() = string::convert<float>(tokeniser.nextToken());
}

if (!token.Icmp("uselight")) {
src.ReadToken(&token);
FXAction.data = token;
for (int i = 0; i < events.Num(); i++) {
if (events[i].name.Icmp(FXAction.data) == 0) {
FXAction.sibling = i;
FXAction.lightColor = events[i].lightColor;
FXAction.lightRadius = events[i].lightRadius;
}
}
FXAction.type = FX_LIGHT;

// precache the light material
declManager->FindMaterial(FXAction.data);
continue;
else if (token == "uselight")
{
_useLightAction = tokeniser.nextToken();
_type = Type::Light;
}

if (!token.Icmp("attachlight")) {
src.ReadToken(&token);
FXAction.data = token;
FXAction.type = FX_ATTACHLIGHT;

// precache it
declManager->FindMaterial(FXAction.data);
continue;
else if (token == "attachlight")
{
_attachLightName = tokeniser.nextToken();
_type = Type::AttachLight;
}

if (!token.Icmp("attachentity")) {
src.ReadToken(&token);
FXAction.data = token;
FXAction.type = FX_ATTACHENTITY;

// precache the model
renderModelManager->FindModel(FXAction.data);
continue;
else if (token == "attachentity")
{
_attachEntityName = tokeniser.nextToken();
_type = Type::AttachEntity;
}

#if 0
if (!token.Icmp("launch")) {
src.ReadToken(&token);
FXAction.data = token;
Expand Down
10 changes: 10 additions & 0 deletions radiantcore/fx/FxAction.h
Expand Up @@ -34,6 +34,11 @@ class FxAction :
float _fadeOutTimeInSeconds;
float _decalSize;
Vector3 _offset;
Vector3 _axis;
Vector3 _angle;
std::string _useLightAction;
std::string _attachLightName;
std::string _attachEntityName;

public:
using Ptr = std::shared_ptr<FxAction>;
Expand All @@ -60,6 +65,11 @@ class FxAction :
float getFadeOutTimeInSeconds() override;
float getDecalSize() override;
const Vector3& getOffset() override;
const Vector3& getAxis() override;
const Vector3& getAngle() override;
const std::string& getUseLight() override;
const std::string& getAttachLight() override;
const std::string& getAttachEntity() override;

// Parses the action from the given tokens.
// The opening brace { will already have been been consumed by the calling code
Expand Down
37 changes: 37 additions & 0 deletions test/Fx.cpp
Expand Up @@ -144,4 +144,41 @@ TEST_F(FxTest, ParseActionOffset)
EXPECT_EQ(getFxByName("fx/parserTest/fadeIn")->getAction(1)->getOffset(), Vector3(1.6f, 0.7f, -0.8f));
}

TEST_F(FxTest, ParseActionAxisAndAngle)
{
EXPECT_EQ(getFxByName("fx/sparks")->getAction(0)->getAxis(), Vector3(0,0,0));
EXPECT_EQ(getFxByName("fx/sparks")->getAction(0)->getAngle(), Vector3(0,0,0));

EXPECT_EQ(getFxByName("fx/parserTest/axisAndAngle")->getAction(0)->getAxis(), Vector3(0.8f, 0.6f, 0.5f));
EXPECT_EQ(getFxByName("fx/parserTest/axisAndAngle")->getAction(0)->getAngle(), Vector3(0, 0, 0));

EXPECT_EQ(getFxByName("fx/parserTest/axisAndAngle")->getAction(1)->getAxis(), Vector3(0, 0, 0));
EXPECT_EQ(getFxByName("fx/parserTest/axisAndAngle")->getAction(1)->getAngle(), Vector3(0.8f, -0.6f, 0.2f));
}

TEST_F(FxTest, ParseActionUseLight)
{
EXPECT_EQ(getFxByName("fx/sparks")->getAction(0)->getUseLight(), "");

EXPECT_EQ(getFxByName("fx/parserTest/useLight")->getAction(1)->getUseLight(), "LightOwner");
// Use light implies that the action is of type light
EXPECT_EQ(getFxByName("fx/parserTest/useLight")->getAction(1)->getType(), fx::IFxAction::Type::Light);
}

TEST_F(FxTest, ParseActionAttachLight)
{
EXPECT_EQ(getFxByName("fx/sparks")->getAction(0)->getAttachLight(), "");

EXPECT_EQ(getFxByName("fx/parserTest/attach")->getAction(0)->getAttachLight(), "light_1");
EXPECT_EQ(getFxByName("fx/parserTest/attach")->getAction(0)->getType(), fx::IFxAction::Type::AttachLight);
}

TEST_F(FxTest, ParseActionAttachEntity)
{
EXPECT_EQ(getFxByName("fx/sparks")->getAction(0)->getAttachEntity(), "");

EXPECT_EQ(getFxByName("fx/parserTest/attach")->getAction(1)->getAttachEntity(), "func_static_1");
EXPECT_EQ(getFxByName("fx/parserTest/attach")->getAction(1)->getType(), fx::IFxAction::Type::AttachEntity);
}

}
39 changes: 38 additions & 1 deletion test/resources/tdm/fx/parsertest.fx
Expand Up @@ -109,4 +109,41 @@ fx fx/parserTest/fadeIn
size 1.5
offset 1.6 , 0.7,-0.8
}
}
}

fx fx/parserTest/axisAndAngle
{
{
delay 1.5
axis 0.8,0.6, 0.5
}
{
delay 0.5
angle 0.8,-0.6, 0.2
}
}

fx fx/parserTest/useLight
{
{
delay 1.5
name "LightOwner"
light "lights/biground", 0.5, 1, 0.7, 550.3
}
{
useLight "LightOwner"
fadeOut 0.5
}
}

fx fx/parserTest/attach
{
{
delay 1.5
attachLight "light_1"
}
{
delay 2.5
attachEntity "func_static_1"
}
}

0 comments on commit dcac59a

Please sign in to comment.