Skip to content

Commit 946673f

Browse files
committed
Warn when using v3.8 features without #version 3.8.
- 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.
1 parent a50e120 commit 946673f

File tree

12 files changed

+400
-144
lines changed

12 files changed

+400
-144
lines changed

source/backend/control/scene.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/// @parblock
99
///
1010
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11-
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
11+
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
1212
///
1313
/// POV-Ray is free software: you can redistribute it and/or modify
1414
/// it under the terms of the GNU Affero General Public License as
@@ -92,7 +92,7 @@ void Scene::StartParser(POVMS_Object& parseOptions)
9292

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

source/base/types.h

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/// @parblock
99
///
1010
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11-
/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
11+
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
1212
///
1313
/// POV-Ray is free software: you can redistribute it and/or modify
1414
/// it under the terms of the GNU Affero General Public License as
@@ -44,6 +44,7 @@
4444
#include <vector>
4545

4646
#include "base/pov_mem.h"
47+
#include "base/version.h"
4748

4849
namespace pov_base
4950
{
@@ -336,6 +337,95 @@ class ThreadData
336337
virtual ~ThreadData() { }
337338
};
338339

340+
/// Class representing POV-Ray version numbers.
341+
struct POVRayVersion
342+
{
343+
/// Set to actual software version.
344+
inline POVRayVersion() :
345+
POVRayVersion(POV_RAY_MAJOR_VERSION_INT, POV_RAY_MINOR_VERSION_INT, POV_RAY_REVISION_INT)
346+
{}
347+
348+
inline POVRayVersion(const POVRayVersion& v) :
349+
data(v.data)
350+
{}
351+
352+
/// Set according to numeric fields.
353+
inline POVRayVersion(int major, int minor, int revision) :
354+
data(major * 100 + minor * 10 + revision)
355+
{
356+
POV_ASSERT((major > 0) && (major < 4));
357+
POV_ASSERT((minor >= 0) && (minor < 10));
358+
POV_ASSERT((revision >= 0) && (revision < 10));
359+
}
360+
361+
/// Set as specified by parser-internal integer code.
362+
inline explicit POVRayVersion(int intCode) :
363+
data(intCode)
364+
{
365+
POV_ASSERT((intCode == 0) || ((intCode >= 100) && (intCode < 400)));
366+
}
367+
368+
/// Set as specified by `#version`-style floating-point code.
369+
inline explicit POVRayVersion(float floatCode) :
370+
data(std::min(std::max((unsigned int)(floatCode * 100.0f + .5f), 100u), 10000u))
371+
{
372+
POV_ASSERT((floatCode >= 1.00) && (floatCode < 4.00));
373+
}
374+
375+
/// Set as specified by `#version`-style floating-point code.
376+
inline explicit POVRayVersion(double floatCode) :
377+
data(std::min(std::max((unsigned int)(floatCode * 100.0 + .5), 100u), 10000u))
378+
{
379+
POV_ASSERT((floatCode >= 1.00) && (floatCode < 4.00));
380+
}
381+
382+
inline POVRayVersion& operator=(const POVRayVersion& v)
383+
{
384+
data = v.data;
385+
return *this;
386+
}
387+
388+
/// Return first version field.
389+
inline int major() const { return data / 100; }
390+
391+
/// Return second version field.
392+
inline int minor() const { return (data / 10) % 10; }
393+
394+
/// Return third version field.
395+
inline int revision() const { return data % 10; }
396+
397+
/// Return as `#version`-style floating-point code.
398+
inline explicit operator double() const { return data * 0.01; }
399+
400+
/// Return as string.
401+
inline std::string str() const
402+
{
403+
if (revision() == 0)
404+
return std::string({ char('0'+major()), '.', char('0'+minor()) });
405+
else
406+
return std::string({ char('0'+major()), '.', char('0'+minor()), '.', char('0'+revision()) });
407+
}
408+
409+
inline bool operator== (POVRayVersion v) const { return data == v.data; }
410+
inline bool operator>= (POVRayVersion v) const { return data >= v.data; }
411+
inline bool operator<= (POVRayVersion v) const { return data <= v.data; }
412+
inline bool operator> (POVRayVersion v) const { return data > v.data; }
413+
inline bool operator< (POVRayVersion v) const { return data < v.data; }
414+
415+
/// Compare to parser-internal integer code.
416+
inline bool operator== (int parserCode) const { return data == parserCode; }
417+
418+
/// Compare to parser-internal integer code.
419+
inline bool operator>= (int parserCode) const { return data >= parserCode; }
420+
421+
/// Compare to parser-internal integer code.
422+
inline bool operator< (int parserCode) const { return data < parserCode; }
423+
424+
private:
425+
426+
int data;
427+
};
428+
339429
/// @}
340430
///
341431
//##############################################################################

source/base/version.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
/// @name Primary Version and Copyright Information
5656
///
5757
/// @note
58-
/// The macro definition in this section may be probed by external tools, and must therefore
58+
/// The macro definitions in this section may be probed by external tools, and must therefore
5959
/// conform to the following rules:
6060
/// - The definitions must reside on a single line each.
6161
/// - The lines must not be disabled via conditional compilation or multi-line comments.
@@ -141,9 +141,6 @@
141141
///
142142
/// @{
143143

144-
/// Source code version as a 3-digit integer number.
145-
#define POV_RAY_VERSION_INT (POV_RAY_MAJOR_VERSION_INT * 100 + POV_RAY_MINOR_VERSION_INT * 10 + POV_RAY_REVISION_INT)
146-
147144
/// Helper macro to convert a parameter into a string.
148145
/// @note This macro can _not_ be used directly to stringify another macro's value, as it would
149146
/// instead stringify the other macro's name.

source/core/scene/scenedata.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/// @parblock
99
///
1010
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11-
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
11+
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
1212
///
1313
/// POV-Ray is free software: you can redistribute it and/or modify
1414
/// it under the terms of the GNU Affero General Public License as
@@ -65,7 +65,7 @@ SceneData::SceneData() :
6565

6666
iridWavelengths = MathColour::DefaultWavelengths();
6767

68-
languageVersion = POV_RAY_VERSION_INT;
68+
languageVersion = POVRayVersion();
6969
languageVersionSet = false;
7070
languageVersionLate = false;
7171
warningLevel = 10; // all warnings

source/core/scene/scenedata.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/// @parblock
99
///
1010
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11-
/// Copyright 1991-2017 Persistence of Vision Raytracer Pty. Ltd.
11+
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
1212
///
1313
/// POV-Ray is free software: you can redistribute it and/or modify
1414
/// it under the terms of the GNU Affero General Public License as
@@ -41,6 +41,7 @@
4141

4242
#include <map>
4343

44+
#include "base/types.h"
4445
#include "base/image/colourspace.h"
4546

4647
#include "core/lighting/radiosity.h"
@@ -112,7 +113,7 @@ class SceneData
112113
/// skysphere around scene
113114
Skysphere_Struct *skysphere;
114115
/// language version to assume
115-
int languageVersion;
116+
POVRayVersion languageVersion;
116117
/// true if a #version statement has been encountered
117118
bool languageVersionSet;
118119
/// true if the first #version statement was found after other declarations
@@ -236,15 +237,15 @@ class SceneData
236237
/// (which was the latest version before v3.7.0).
237238
/// @note It is recommended to use this function only where behaviour differs
238239
/// significantly from pre-v3.7 versions.
239-
/// @return The current language version in integer format (e.g. 370 for v3.7.0)
240-
/// if explicitly specified, or 362 otherwise.
240+
/// @return The current language version as a POVRayVersion object
241+
/// if explicitly specified, or v3.6.2 otherwise.
241242
///
242-
inline unsigned int EffectiveLanguageVersion() const
243+
inline POVRayVersion EffectiveLanguageVersion() const
243244
{
244245
if (languageVersionSet)
245246
return languageVersion;
246247
else
247-
return 362;
248+
return POVRayVersion(362);
248249
}
249250

250251
/// Create new scene specific data.

source/parser/parser.cpp

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
/// @parblock
99
///
1010
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11-
/// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
11+
/// Copyright 1991-2021 Persistence of Vision Raytracer Pty. Ltd.
1212
///
1313
/// POV-Ray is free software: you can redistribute it and/or modify
1414
/// it under the terms of the GNU Affero General Public License as
@@ -393,7 +393,7 @@ void Parser::Run()
393393
"version v3.1 or earlier is not guaranteed. Please use POV-Ray v3.5 or earlier if\n"
394394
"your scene depends on rendering defects caused by these bugs.");
395395

396-
sceneData->languageVersion = 350;
396+
sceneData->languageVersion = POVRayVersion(350);
397397
}
398398

399399
if(sceneData->languageVersionLate)
@@ -527,7 +527,7 @@ void Parser::Frame_Init()
527527

528528
/****************************************************************************/
529529

530-
void Parser::InitDefaults(int version)
530+
void Parser::InitDefaults(POVRayVersion version)
531531
{
532532
// Initialize defaults depending on version:
533533
// As of v3.8...
@@ -1591,6 +1591,7 @@ void Parser::Parse_Camera (Camera& Cam)
15911591
END_CASE
15921592

15931593
CASE (USER_DEFINED_TOKEN)
1594+
NewFeatureWarning(380, HERE, "'user_defined' in 'camera'");
15941595
mExperimentalFlags.userDefinedCamera = true;
15951596
Parse_User_Defined_Camera(New);
15961597
END_CASE
@@ -4997,12 +4998,15 @@ ObjectPtr Parser::Parse_Ovus()
49974998
Object->ConnectingRadius = 2.0 * std::max(Object->BottomRadius, Object->TopRadius);
49984999
EXPECT
49995000
CASE(RADIUS_TOKEN)
5001+
NewFeatureWarning(380, HERE, "'radius' in 'ovus'");
50005002
Object->ConnectingRadius = Parse_Float();
50015003
END_CASE
50025004
CASE(DISTANCE_TOKEN)
5005+
NewFeatureWarning(380, HERE, "'distance' in 'ovus'");
50035006
Object->VerticalSpherePosition = Parse_Float();
50045007
END_CASE
50055008
CASE(PRECISION_TOKEN)
5009+
NewFeatureWarning(380, HERE, "'precision' in 'ovus'");
50065010
Object->RootTolerance = Parse_Float();
50075011
END_CASE
50085012
OTHERWISE
@@ -6372,9 +6376,11 @@ ObjectPtr Parser::Parse_Torus()
63726376

63736377
EXPECT_ONE
63746378
CASE(DIFFERENCE_TOKEN)
6379+
NewFeatureWarning(380, HERE, "'difference' in 'torus'");
63756380
spindleMode = SpindleTorus::DifferenceSpindle;
63766381
END_CASE
63776382
CASE(INTERSECTION_TOKEN)
6383+
NewFeatureWarning(380, HERE, "'intersection' in 'torus'");
63786384
spindleMode = SpindleTorus::IntersectionSpindle;
63796385
if (!spindleTorus)
63806386
{
@@ -6383,9 +6389,11 @@ ObjectPtr Parser::Parse_Torus()
63836389
}
63846390
END_CASE
63856391
CASE(MERGE_TOKEN)
6392+
NewFeatureWarning(380, HERE, "'merge' in 'torus'");
63866393
spindleMode = SpindleTorus::MergeSpindle;
63876394
END_CASE
63886395
CASE(UNION_TOKEN)
6396+
NewFeatureWarning(380, HERE, "'union' in 'torus'");
63896397
spindleMode = SpindleTorus::UnionSpindle;
63906398
END_CASE
63916399
OTHERWISE
@@ -7561,12 +7569,14 @@ void Parser::Parse_Global_Settings()
75617569
{
75627570
Error("Radiosity nearest count must be a value from 1 to %d.", RadiosityFunction::MAX_NEAREST_COUNT);
75637571
}
7564-
Parse_Comma();
7565-
sceneData->radiositySettings.nearestCountAPT = (int)Allow_Float(0.0);
7566-
if (( sceneData->radiositySettings.nearestCountAPT < 0) ||
7567-
( sceneData->radiositySettings.nearestCountAPT >= sceneData->radiositySettings.nearestCount))
7572+
if (Allow_Int(sceneData->radiositySettings.nearestCountAPT, 0, true))
75687573
{
7569-
Error("Radiosity nearest count for adaptive pretrace must be non-negative and smaller than general nearest count.");
7574+
NewFeatureWarning(370, HERE, "two-parameter form of 'nearest_count' radiosity setting");
7575+
if ((sceneData->radiositySettings.nearestCountAPT < 0) ||
7576+
(sceneData->radiositySettings.nearestCountAPT >= sceneData->radiositySettings.nearestCount))
7577+
{
7578+
Error("Radiosity nearest count for adaptive pretrace must be non-negative and smaller than general nearest count.");
7579+
}
75707580
}
75717581
END_CASE
75727582

@@ -7602,6 +7612,7 @@ void Parser::Parse_Global_Settings()
76027612
END_CASE
76037613

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

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

86938704
EXPECT_ONE
86948705
CASE (LEFT_PAREN_TOKEN)
8706+
NewFeatureWarning(380, HERE, "tuple-style bulk assignment");
86958707
UNGET
86968708
tupleDeclare = true;
86978709
END_CASE
86988710
CASE (LEFT_ANGLE_TOKEN)
8711+
NewFeatureWarning(380, HERE, "vector-style bulk assignment");
86998712
UNGET
87008713
lvectorDeclare = true;
87018714
END_CASE
87028715
CASE (LEFT_CURLY_TOKEN)
8716+
NewFeatureWarning(380, HERE, "array-style bulk assignment");
87038717
UNGET
87048718
larrayDeclare = true;
87058719
END_CASE
@@ -9725,13 +9739,13 @@ void Parser::Link_Textures (TEXTURE **Old_Textures, TEXTURE *New_Textures)
97259739
}
97269740
for (Layer = New_Textures; Layer->Next != nullptr; Layer = Layer->Next)
97279741
{
9728-
/* NK layers - 1999 June 10 - for backwards compatiblity with layered textures */
9729-
if(sceneData->EffectiveLanguageVersion() <= 310)
9742+
/* NK layers - 1999 June 10 - for backwards compatibility with layered textures */
9743+
if(sceneData->EffectiveLanguageVersion() < 350)
97309744
Convert_Filter_To_Transmit(Layer->Pigment);
97319745
}
97329746

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

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

10872+
void Parser::WarningOnce(WarningLevel level, SourceLocation id, const char *format, ...)
10873+
{
10874+
POV_PARSER_ASSERT(level >= kWarningGeneral);
10875+
10876+
if (mWarningsIssued.insert(id).second)
10877+
{
10878+
va_list marker;
10879+
char localvsbuffer[1024];
10880+
10881+
va_start(marker, format);
10882+
std::vsnprintf(localvsbuffer, sizeof(localvsbuffer), format, marker);
10883+
va_end(marker);
10884+
10885+
if (Token.FileHandle != nullptr)
10886+
messageFactory.WarningAt(level, Token.FileHandle->name(), Token.Token_File_Pos.lineno, Token.Token_Col_No, Token.FileHandle->tellg().offset, "%s", localvsbuffer);
10887+
else
10888+
messageFactory.Warning(level, "%s", localvsbuffer);
10889+
}
10890+
}
10891+
10892+
void Parser::NewFeatureWarning(int sinceVersion, SourceLocation id, const char *feature)
10893+
{
10894+
if (sceneData->EffectiveLanguageVersion() < sinceVersion)
10895+
{
10896+
WarningOnce(kWarningLanguage, id,
10897+
"Use of POV-Ray v%s feature (%s) detected in alleged v%s scene.",
10898+
POVRayVersion(sinceVersion).str().c_str(),
10899+
feature,
10900+
sceneData->EffectiveLanguageVersion().str().c_str());
10901+
}
10902+
}
10903+
1085810904
void Parser::VersionWarning(unsigned int sinceVersion, const char *format,...)
1085910905
{
1086010906
if(sceneData->EffectiveLanguageVersion() >= sinceVersion)

0 commit comments

Comments
 (0)