Skip to content

Commit

Permalink
Warn when using v3.8 features without #version 3.8.
Browse files Browse the repository at this point in the history
- Addresses issue #420
- POV-Ray will now warn when using v3.7 or v3.8 features without matching `#version` directive.
- For consistency, POV-Ray will no longer throw an error whenever encountering anything macro-related in v3.0 scenes, and instead just warn when encountering `#macro` in such scenes.
- Modified internal tracking of scene language version to use a dedicated class instead of an `int`.
- Added a framework to print certain warnings only once.
  • Loading branch information
c-lipka committed Jul 11, 2021
1 parent a50e120 commit 946673f
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 144 deletions.
4 changes: 2 additions & 2 deletions source/backend/control/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -92,7 +92,7 @@ void Scene::StartParser(POVMS_Object& parseOptions)

if (parseOptions.Exist(kPOVAttrib_Version))
{
sceneData->languageVersion = clip(int(parseOptions.GetFloat(kPOVAttrib_Version) * 100.0f + .5f), 100, 10000);
sceneData->languageVersion = POVRayVersion(parseOptions.GetFloat(kPOVAttrib_Version));
sceneData->languageVersionSet = true;
}

Expand Down
92 changes: 91 additions & 1 deletion source/base/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -44,6 +44,7 @@
#include <vector>

#include "base/pov_mem.h"
#include "base/version.h"

namespace pov_base
{
Expand Down Expand Up @@ -336,6 +337,95 @@ class ThreadData
virtual ~ThreadData() { }
};

/// Class representing POV-Ray version numbers.
struct POVRayVersion
{
/// Set to actual software version.
inline POVRayVersion() :
POVRayVersion(POV_RAY_MAJOR_VERSION_INT, POV_RAY_MINOR_VERSION_INT, POV_RAY_REVISION_INT)
{}

inline POVRayVersion(const POVRayVersion& v) :
data(v.data)
{}

/// Set according to numeric fields.
inline POVRayVersion(int major, int minor, int revision) :
data(major * 100 + minor * 10 + revision)
{
POV_ASSERT((major > 0) && (major < 4));
POV_ASSERT((minor >= 0) && (minor < 10));
POV_ASSERT((revision >= 0) && (revision < 10));
}

/// Set as specified by parser-internal integer code.
inline explicit POVRayVersion(int intCode) :
data(intCode)
{
POV_ASSERT((intCode == 0) || ((intCode >= 100) && (intCode < 400)));
}

/// Set as specified by `#version`-style floating-point code.
inline explicit POVRayVersion(float floatCode) :
data(std::min(std::max((unsigned int)(floatCode * 100.0f + .5f), 100u), 10000u))
{
POV_ASSERT((floatCode >= 1.00) && (floatCode < 4.00));
}

/// Set as specified by `#version`-style floating-point code.
inline explicit POVRayVersion(double floatCode) :
data(std::min(std::max((unsigned int)(floatCode * 100.0 + .5), 100u), 10000u))
{
POV_ASSERT((floatCode >= 1.00) && (floatCode < 4.00));
}

inline POVRayVersion& operator=(const POVRayVersion& v)
{
data = v.data;
return *this;
}

/// Return first version field.
inline int major() const { return data / 100; }

/// Return second version field.
inline int minor() const { return (data / 10) % 10; }

/// Return third version field.
inline int revision() const { return data % 10; }

/// Return as `#version`-style floating-point code.
inline explicit operator double() const { return data * 0.01; }

/// Return as string.
inline std::string str() const
{
if (revision() == 0)
return std::string({ char('0'+major()), '.', char('0'+minor()) });
else
return std::string({ char('0'+major()), '.', char('0'+minor()), '.', char('0'+revision()) });
}

inline bool operator== (POVRayVersion v) const { return data == v.data; }
inline bool operator>= (POVRayVersion v) const { return data >= v.data; }
inline bool operator<= (POVRayVersion v) const { return data <= v.data; }
inline bool operator> (POVRayVersion v) const { return data > v.data; }
inline bool operator< (POVRayVersion v) const { return data < v.data; }

/// Compare to parser-internal integer code.
inline bool operator== (int parserCode) const { return data == parserCode; }

/// Compare to parser-internal integer code.
inline bool operator>= (int parserCode) const { return data >= parserCode; }

/// Compare to parser-internal integer code.
inline bool operator< (int parserCode) const { return data < parserCode; }

private:

int data;
};

/// @}
///
//##############################################################################
Expand Down
5 changes: 1 addition & 4 deletions source/base/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
/// @name Primary Version and Copyright Information
///
/// @note
/// The macro definition in this section may be probed by external tools, and must therefore
/// The macro definitions in this section may be probed by external tools, and must therefore
/// conform to the following rules:
/// - The definitions must reside on a single line each.
/// - The lines must not be disabled via conditional compilation or multi-line comments.
Expand Down Expand Up @@ -141,9 +141,6 @@
///
/// @{

/// Source code version as a 3-digit integer number.
#define POV_RAY_VERSION_INT (POV_RAY_MAJOR_VERSION_INT * 100 + POV_RAY_MINOR_VERSION_INT * 10 + POV_RAY_REVISION_INT)

/// Helper macro to convert a parameter into a string.
/// @note This macro can _not_ be used directly to stringify another macro's value, as it would
/// instead stringify the other macro's name.
Expand Down
4 changes: 2 additions & 2 deletions source/core/scene/scenedata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -65,7 +65,7 @@ SceneData::SceneData() :

iridWavelengths = MathColour::DefaultWavelengths();

languageVersion = POV_RAY_VERSION_INT;
languageVersion = POVRayVersion();
languageVersionSet = false;
languageVersionLate = false;
warningLevel = 10; // all warnings
Expand Down
13 changes: 7 additions & 6 deletions source/core/scene/scenedata.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -41,6 +41,7 @@

#include <map>

#include "base/types.h"
#include "base/image/colourspace.h"

#include "core/lighting/radiosity.h"
Expand Down Expand Up @@ -112,7 +113,7 @@ class SceneData
/// skysphere around scene
Skysphere_Struct *skysphere;
/// language version to assume
int languageVersion;
POVRayVersion languageVersion;
/// true if a #version statement has been encountered
bool languageVersionSet;
/// true if the first #version statement was found after other declarations
Expand Down Expand Up @@ -236,15 +237,15 @@ class SceneData
/// (which was the latest version before v3.7.0).
/// @note It is recommended to use this function only where behaviour differs
/// significantly from pre-v3.7 versions.
/// @return The current language version in integer format (e.g. 370 for v3.7.0)
/// if explicitly specified, or 362 otherwise.
/// @return The current language version as a POVRayVersion object
/// if explicitly specified, or v3.6.2 otherwise.
///
inline unsigned int EffectiveLanguageVersion() const
inline POVRayVersion EffectiveLanguageVersion() const
{
if (languageVersionSet)
return languageVersion;
else
return 362;
return POVRayVersion(362);
}

/// Create new scene specific data.
Expand Down
70 changes: 58 additions & 12 deletions source/parser/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray is free software: you can redistribute it and/or modify
/// it under the terms of the GNU Affero General Public License as
Expand Down Expand Up @@ -393,7 +393,7 @@ void Parser::Run()
"version v3.1 or earlier is not guaranteed. Please use POV-Ray v3.5 or earlier if\n"
"your scene depends on rendering defects caused by these bugs.");

sceneData->languageVersion = 350;
sceneData->languageVersion = POVRayVersion(350);
}

if(sceneData->languageVersionLate)
Expand Down Expand Up @@ -527,7 +527,7 @@ void Parser::Frame_Init()

/****************************************************************************/

void Parser::InitDefaults(int version)
void Parser::InitDefaults(POVRayVersion version)
{
// Initialize defaults depending on version:
// As of v3.8...
Expand Down Expand Up @@ -1591,6 +1591,7 @@ void Parser::Parse_Camera (Camera& Cam)
END_CASE

CASE (USER_DEFINED_TOKEN)
NewFeatureWarning(380, HERE, "'user_defined' in 'camera'");
mExperimentalFlags.userDefinedCamera = true;
Parse_User_Defined_Camera(New);
END_CASE
Expand Down Expand Up @@ -4997,12 +4998,15 @@ ObjectPtr Parser::Parse_Ovus()
Object->ConnectingRadius = 2.0 * std::max(Object->BottomRadius, Object->TopRadius);
EXPECT
CASE(RADIUS_TOKEN)
NewFeatureWarning(380, HERE, "'radius' in 'ovus'");
Object->ConnectingRadius = Parse_Float();
END_CASE
CASE(DISTANCE_TOKEN)
NewFeatureWarning(380, HERE, "'distance' in 'ovus'");
Object->VerticalSpherePosition = Parse_Float();
END_CASE
CASE(PRECISION_TOKEN)
NewFeatureWarning(380, HERE, "'precision' in 'ovus'");
Object->RootTolerance = Parse_Float();
END_CASE
OTHERWISE
Expand Down Expand Up @@ -6372,9 +6376,11 @@ ObjectPtr Parser::Parse_Torus()

EXPECT_ONE
CASE(DIFFERENCE_TOKEN)
NewFeatureWarning(380, HERE, "'difference' in 'torus'");
spindleMode = SpindleTorus::DifferenceSpindle;
END_CASE
CASE(INTERSECTION_TOKEN)
NewFeatureWarning(380, HERE, "'intersection' in 'torus'");
spindleMode = SpindleTorus::IntersectionSpindle;
if (!spindleTorus)
{
Expand All @@ -6383,9 +6389,11 @@ ObjectPtr Parser::Parse_Torus()
}
END_CASE
CASE(MERGE_TOKEN)
NewFeatureWarning(380, HERE, "'merge' in 'torus'");
spindleMode = SpindleTorus::MergeSpindle;
END_CASE
CASE(UNION_TOKEN)
NewFeatureWarning(380, HERE, "'union' in 'torus'");
spindleMode = SpindleTorus::UnionSpindle;
END_CASE
OTHERWISE
Expand Down Expand Up @@ -7561,12 +7569,14 @@ void Parser::Parse_Global_Settings()
{
Error("Radiosity nearest count must be a value from 1 to %d.", RadiosityFunction::MAX_NEAREST_COUNT);
}
Parse_Comma();
sceneData->radiositySettings.nearestCountAPT = (int)Allow_Float(0.0);
if (( sceneData->radiositySettings.nearestCountAPT < 0) ||
( sceneData->radiositySettings.nearestCountAPT >= sceneData->radiositySettings.nearestCount))
if (Allow_Int(sceneData->radiositySettings.nearestCountAPT, 0, true))
{
Error("Radiosity nearest count for adaptive pretrace must be non-negative and smaller than general nearest count.");
NewFeatureWarning(370, HERE, "two-parameter form of 'nearest_count' radiosity setting");
if ((sceneData->radiositySettings.nearestCountAPT < 0) ||
(sceneData->radiositySettings.nearestCountAPT >= sceneData->radiositySettings.nearestCount))
{
Error("Radiosity nearest count for adaptive pretrace must be non-negative and smaller than general nearest count.");
}
}
END_CASE

Expand Down Expand Up @@ -7602,6 +7612,7 @@ void Parser::Parse_Global_Settings()
END_CASE

CASE (BRILLIANCE_TOKEN)
NewFeatureWarning(380, HERE, "'brilliance' in 'radiosity'");
sceneData->radiositySettings.brilliance = ((int)Parse_Float() != 0);
END_CASE

Expand Down Expand Up @@ -8692,14 +8703,17 @@ void Parser::Parse_Declare(bool is_local, bool after_hash)

EXPECT_ONE
CASE (LEFT_PAREN_TOKEN)
NewFeatureWarning(380, HERE, "tuple-style bulk assignment");
UNGET
tupleDeclare = true;
END_CASE
CASE (LEFT_ANGLE_TOKEN)
NewFeatureWarning(380, HERE, "vector-style bulk assignment");
UNGET
lvectorDeclare = true;
END_CASE
CASE (LEFT_CURLY_TOKEN)
NewFeatureWarning(380, HERE, "array-style bulk assignment");
UNGET
larrayDeclare = true;
END_CASE
Expand Down Expand Up @@ -9725,13 +9739,13 @@ void Parser::Link_Textures (TEXTURE **Old_Textures, TEXTURE *New_Textures)
}
for (Layer = New_Textures; Layer->Next != nullptr; Layer = Layer->Next)
{
/* NK layers - 1999 June 10 - for backwards compatiblity with layered textures */
if(sceneData->EffectiveLanguageVersion() <= 310)
/* NK layers - 1999 June 10 - for backwards compatibility with layered textures */
if(sceneData->EffectiveLanguageVersion() < 350)
Convert_Filter_To_Transmit(Layer->Pigment);
}

/* NK layers - 1999 Nov 16 - for backwards compatiblity with layered textures */
if ((sceneData->EffectiveLanguageVersion() <= 310) && (*Old_Textures != nullptr))
/* NK layers - 1999 Nov 16 - for backwards compatibility with layered textures */
if ((sceneData->EffectiveLanguageVersion() < 350) && (*Old_Textures != nullptr))
Convert_Filter_To_Transmit(Layer->Pigment);

Layer->Next = *Old_Textures;
Expand Down Expand Up @@ -10855,6 +10869,38 @@ void Parser::Warning(WarningLevel level, const char *format,...)
messageFactory.Warning(level, "%s", localvsbuffer);
}

void Parser::WarningOnce(WarningLevel level, SourceLocation id, const char *format, ...)
{
POV_PARSER_ASSERT(level >= kWarningGeneral);

if (mWarningsIssued.insert(id).second)
{
va_list marker;
char localvsbuffer[1024];

va_start(marker, format);
std::vsnprintf(localvsbuffer, sizeof(localvsbuffer), format, marker);
va_end(marker);

if (Token.FileHandle != nullptr)
messageFactory.WarningAt(level, Token.FileHandle->name(), Token.Token_File_Pos.lineno, Token.Token_Col_No, Token.FileHandle->tellg().offset, "%s", localvsbuffer);
else
messageFactory.Warning(level, "%s", localvsbuffer);
}
}

void Parser::NewFeatureWarning(int sinceVersion, SourceLocation id, const char *feature)
{
if (sceneData->EffectiveLanguageVersion() < sinceVersion)
{
WarningOnce(kWarningLanguage, id,
"Use of POV-Ray v%s feature (%s) detected in alleged v%s scene.",
POVRayVersion(sinceVersion).str().c_str(),
feature,
sceneData->EffectiveLanguageVersion().str().c_str());
}
}

void Parser::VersionWarning(unsigned int sinceVersion, const char *format,...)
{
if(sceneData->EffectiveLanguageVersion() >= sinceVersion)
Expand Down
Loading

0 comments on commit 946673f

Please sign in to comment.